Completed
Pull Request — master (#45)
by Бабичев
05:45
created

CommonService::forceWithdraw()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 10
nc 1
nop 4
dl 0
loc 19
ccs 11
cts 11
cp 1
crap 1
rs 9.9332
c 0
b 0
f 0
1
<?php
2
3
namespace Bavix\Wallet\Services;
4
5
use Bavix\Wallet\Exceptions\BalanceIsEmpty;
6
use Bavix\Wallet\Exceptions\InsufficientFunds;
7
use Bavix\Wallet\Interfaces\Wallet;
8
use Bavix\Wallet\Models\Transaction;
9
use Bavix\Wallet\Models\Transfer;
10
use Bavix\Wallet\Models\Wallet as WalletModel;
11
use Bavix\Wallet\Objects\Bring;
12
use Bavix\Wallet\Objects\Operation;
13
use Bavix\Wallet\Traits\HasWallet;
14
use Illuminate\Support\Facades\DB;
15
use function app;
16
use function compact;
17
18
class CommonService
19
{
20
21
    /**
22
     * @param Wallet $from
23
     * @param Wallet $to
24
     * @param int $amount
25
     * @param array|null $meta
26
     * @param string $status
27
     * @return Transfer
28
     */
29 9
    public function transfer(Wallet $from, Wallet $to, int $amount, ?array $meta = null, string $status = Transfer::STATUS_TRANSFER): Transfer
30
    {
31 9
        $this->verifyWithdraw($from, $amount);
32 9
        return $this->forceTransfer($from, $to, $amount, $meta, $status);
0 ignored issues
show
Bug introduced by
$from of type Bavix\Wallet\Traits\HasWallet is incompatible with the type Bavix\Wallet\Interfaces\Wallet expected by parameter $from of Bavix\Wallet\Services\Co...ervice::forceTransfer(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

32
        return $this->forceTransfer(/** @scrutinizer ignore-type */ $from, $to, $amount, $meta, $status);
Loading history...
33
    }
34
35
    /**
36
     * @param Wallet $from
37
     * @param Wallet $to
38
     * @param int $amount
39
     * @param array|null $meta
40
     * @param string $status
41
     * @return Transfer
42
     */
43 19
    public function forceTransfer(Wallet $from, Wallet $to, int $amount, ?array $meta = null, string $status = Transfer::STATUS_TRANSFER): Transfer
44
    {
45 19
        $fee = app(WalletService::class)->fee($to, $amount);
46 19
        $withdraw = $this->forceWithdraw($from, $amount + $fee, $meta);
47 19
        $deposit = $this->deposit($to, $amount, $meta);
48
49 19
        $from = app(WalletService::class)
50 19
            ->getWallet($from);
51
52 19
        $transfers = $this->multiBrings([
53 19
            (new Bring())
54 19
                ->setStatus($status)
55 19
                ->setDeposit($deposit)
56 19
                ->setWithdraw($withdraw)
57 19
                ->setFrom($from)
58 19
                ->setTo($to)
59
        ]);
60
61 19
        return current($transfers);
62
    }
63
64
    /**
65
     * @param Wallet $wallet
66
     * @param int $amount
67
     * @param array|null $meta
68
     * @param bool|null $confirmed
69
     * @return Transaction
70
     */
71 30
    public function forceWithdraw(Wallet $wallet, int $amount, ?array $meta, bool $confirmed = true): Transaction
72
    {
73 30
        $walletService = app(WalletService::class);
74 30
        $walletService->checkAmount($amount);
75
76
        /**
77
         * @var WalletModel $wallet
78
         */
79 30
        $wallet = $walletService->getWallet($wallet);
80
81 30
        $transactions = $this->multiOperation($wallet, [
82 30
            (new Operation())
83 30
                ->setType(Transaction::TYPE_WITHDRAW)
84 30
                ->setConfirmed($confirmed)
85 30
                ->setAmount(-$amount)
86 30
                ->setMeta($meta)
87
        ]);
88
89 30
        return current($transactions);
90
    }
91
92
    /**
93
     * @param Wallet $wallet
94
     * @param int $amount
95
     * @param array|null $meta
96
     * @param bool $confirmed
97
     * @return Transaction
98
     */
99 35
    public function deposit(Wallet $wallet, int $amount, ?array $meta, bool $confirmed = true): Transaction
100
    {
101 35
        $walletService = app(WalletService::class);
102 35
        $walletService->checkAmount($amount);
103
104
        /**
105
         * @var WalletModel $wallet
106
         */
107 32
        $wallet = $walletService->getWallet($wallet);
108
109 32
        $transactions = $this->multiOperation($wallet, [
110 32
            (new Operation())
111 32
                ->setType(Transaction::TYPE_DEPOSIT)
112 32
                ->setConfirmed($confirmed)
113 32
                ->setAmount($amount)
114 32
                ->setMeta($meta)
115
        ]);
116
117 32
        return current($transactions);
118
    }
119
120
    /**
121
     * @param Wallet $wallet
122
     * @param int $amount
123
     * @return void
124
     * @throws BalanceIsEmpty
125
     * @throws InsufficientFunds
126
     */
127 36
    public function verifyWithdraw(Wallet $wallet, int $amount): void
128
    {
129
        /**
130
         * @var HasWallet $wallet
131
         */
132 36
        if ($amount && !$wallet->balance) {
133 14
            throw new BalanceIsEmpty(trans('wallet::errors.wallet_empty'));
0 ignored issues
show
Bug introduced by
It seems like trans('wallet::errors.wallet_empty') can also be of type array; however, parameter $message of Bavix\Wallet\Exceptions\...eIsEmpty::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

133
            throw new BalanceIsEmpty(/** @scrutinizer ignore-type */ trans('wallet::errors.wallet_empty'));
Loading history...
134
        }
135
136 30
        if (!$wallet->canWithdraw($amount)) {
137 1
            throw new InsufficientFunds(trans('wallet::errors.insufficient_funds'));
0 ignored issues
show
Bug introduced by
It seems like trans('wallet::errors.insufficient_funds') can also be of type array; however, parameter $message of Bavix\Wallet\Exceptions\...entFunds::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

137
            throw new InsufficientFunds(/** @scrutinizer ignore-type */ trans('wallet::errors.insufficient_funds'));
Loading history...
138
        }
139 29
    }
140
141
    /**
142
     * Create Operation without DB::transaction
143
     *
144
     * @param Wallet $self
145
     * @param array $operations
146
     * @return array
147
     */
148 32
    public function multiOperation(Wallet $self, array $operations): array
149
    {
150 32
        $amount = 0;
151 32
        $objects = [];
152 32
        foreach ($operations as $operation) {
153 32
            if ($operation->isConfirmed()) {
154 32
                $amount += $operation->getAmount();
155
            }
156
157 32
            $objects[] = $operation
158 32
                ->setWallet($self)
159 32
                ->create();
160
        }
161
162 32
        $this->addBalance($self, $amount);
163 32
        return $objects;
164
    }
165
166
    /**
167
     * Create Bring with DB::transaction
168
     *
169
     * @param Bring[] $brings
170
     * @return array
171
     * @throws
172
     */
173 2
    public function assemble(array $brings): array
174
    {
175
        return DB::transaction(function () use ($brings) {
176 2
            return $this->multiBrings($brings);
177 2
        });
178
    }
179
180
    /**
181
     * Create Bring without DB::transaction
182
     *
183
     * @param array $brings
184
     * @return array
185
     */
186 20
    public function multiBrings(array $brings): array
187
    {
188 20
        $objects = [];
189 20
        foreach ($brings as $bring) {
190 20
            $objects[] = $bring->create();
191
        }
192
193 20
        return $objects;
194
    }
195
196
    /**
197
     * @param Wallet $wallet
198
     * @param int $amount
199
     * @return bool
200
     * @throws
201
     */
202 32
    public function addBalance(Wallet $wallet, int $amount): bool
203
    {
204
        /**
205
         * @var ProxyService $proxy
206
         * @var WalletModel $wallet
207
         */
208 32
        $proxy = app(ProxyService::class);
209 32
        $balance = $wallet->balance + $amount;
210 32
        if ($proxy->has($wallet->getKey())) {
0 ignored issues
show
Bug introduced by
It seems like $wallet->getKey() can also be of type boolean and null; however, parameter $key of Bavix\Wallet\Services\ProxyService::has() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

210
        if ($proxy->has(/** @scrutinizer ignore-type */ $wallet->getKey())) {
Loading history...
211 32
            $balance = $proxy->get($wallet->getKey()) + $amount;
0 ignored issues
show
Bug introduced by
It seems like $wallet->getKey() can also be of type boolean and null; however, parameter $key of Bavix\Wallet\Services\ProxyService::get() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

211
            $balance = $proxy->get(/** @scrutinizer ignore-type */ $wallet->getKey()) + $amount;
Loading history...
212
        }
213
214 32
        $result = $wallet->update(compact('balance'));
215 32
        $proxy->set($wallet->getKey(), $balance);
0 ignored issues
show
Bug introduced by
It seems like $wallet->getKey() can also be of type boolean and null; however, parameter $key of Bavix\Wallet\Services\ProxyService::set() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

215
        $proxy->set(/** @scrutinizer ignore-type */ $wallet->getKey(), $balance);
Loading history...
216
217 32
        return $result;
218
    }
219
220
}
221