1 | <?php |
||||
2 | |||||
3 | namespace Bavix\Wallet\Services; |
||||
4 | |||||
5 | use function app; |
||||
6 | use Bavix\Wallet\Exceptions\BalanceIsEmpty; |
||||
7 | use Bavix\Wallet\Exceptions\InsufficientFunds; |
||||
8 | use Bavix\Wallet\Interfaces\Mathable; |
||||
9 | use Bavix\Wallet\Interfaces\Storable; |
||||
10 | use Bavix\Wallet\Interfaces\Wallet; |
||||
11 | use Bavix\Wallet\Models\Transaction; |
||||
12 | use Bavix\Wallet\Models\Transfer; |
||||
13 | use Bavix\Wallet\Models\Wallet as WalletModel; |
||||
14 | use Bavix\Wallet\Objects\Bring; |
||||
15 | use Bavix\Wallet\Objects\Operation; |
||||
16 | use Bavix\Wallet\Traits\HasWallet; |
||||
17 | use function compact; |
||||
18 | use function max; |
||||
19 | |||||
20 | class CommonService |
||||
21 | { |
||||
22 | /** |
||||
23 | * @param Wallet $from |
||||
24 | * @param Wallet $to |
||||
25 | * @param int $amount |
||||
26 | * @param array|null $meta |
||||
27 | * @param string $status |
||||
28 | * @return Transfer |
||||
29 | */ |
||||
30 | 22 | public function transfer(Wallet $from, Wallet $to, $amount, ?array $meta = null, string $status = Transfer::STATUS_TRANSFER): Transfer |
|||
31 | { |
||||
32 | return app(LockService::class)->lock($this, __FUNCTION__, function () use ($from, $to, $amount, $meta, $status) { |
||||
33 | 22 | $math = app(Mathable::class); |
|||
34 | 22 | $discount = app(WalletService::class)->discount($from, $to); |
|||
35 | 22 | $newAmount = max(0, $math->sub($amount, $discount)); |
|||
36 | 22 | $fee = app(WalletService::class)->fee($to, $newAmount); |
|||
37 | 22 | $this->verifyWithdraw($from, $math->add($newAmount, $fee)); |
|||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||
38 | |||||
39 | 22 | return $this->forceTransfer($from, $to, $amount, $meta, $status); |
|||
0 ignored issues
–
show
$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
![]() |
|||||
40 | 22 | }); |
|||
41 | } |
||||
42 | |||||
43 | /** |
||||
44 | * @param Wallet $from |
||||
45 | * @param Wallet $to |
||||
46 | * @param int $amount |
||||
47 | * @param array|null $meta |
||||
48 | * @param string $status |
||||
49 | * @return Transfer |
||||
50 | */ |
||||
51 | 46 | public function forceTransfer(Wallet $from, Wallet $to, $amount, ?array $meta = null, string $status = Transfer::STATUS_TRANSFER): Transfer |
|||
52 | { |
||||
53 | return app(LockService::class)->lock($this, __FUNCTION__, function () use ($from, $to, $amount, $meta, $status) { |
||||
54 | 46 | $math = app(Mathable::class); |
|||
55 | 46 | $from = app(WalletService::class)->getWallet($from); |
|||
56 | 46 | $discount = app(WalletService::class)->discount($from, $to); |
|||
57 | 46 | $amount = max(0, $math->sub($amount, $discount)); |
|||
58 | |||||
59 | 46 | $fee = app(WalletService::class)->fee($to, $amount); |
|||
60 | 46 | $placesValue = app(WalletService::class)->decimalPlacesValue($from); |
|||
61 | 46 | $withdraw = $this->forceWithdraw($from, $math->add($amount, $fee, $placesValue), $meta); |
|||
0 ignored issues
–
show
$math->add($amount, $fee, $placesValue) of type string is incompatible with the type integer expected by parameter $amount of Bavix\Wallet\Services\Co...ervice::forceWithdraw() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
62 | 46 | $deposit = $this->deposit($to, $amount, $meta); |
|||
63 | |||||
64 | 46 | $transfers = $this->multiBrings([ |
|||
65 | 46 | app(Bring::class) |
|||
66 | 46 | ->setStatus($status) |
|||
67 | 46 | ->setDeposit($deposit) |
|||
68 | 46 | ->setWithdraw($withdraw) |
|||
69 | 46 | ->setDiscount($discount) |
|||
70 | 46 | ->setFrom($from) |
|||
71 | 46 | ->setTo($to), |
|||
72 | ]); |
||||
73 | |||||
74 | 46 | return current($transfers); |
|||
75 | 46 | }); |
|||
76 | } |
||||
77 | |||||
78 | /** |
||||
79 | * @param Wallet $wallet |
||||
80 | * @param int $amount |
||||
81 | * @param array|null $meta |
||||
82 | * @param bool|null $confirmed |
||||
83 | * @return Transaction |
||||
84 | */ |
||||
85 | 80 | public function forceWithdraw(Wallet $wallet, $amount, ?array $meta, bool $confirmed = true): Transaction |
|||
86 | { |
||||
87 | return app(LockService::class)->lock($this, __FUNCTION__, function () use ($wallet, $amount, $meta, $confirmed) { |
||||
88 | 80 | $walletService = app(WalletService::class); |
|||
89 | 80 | $walletService->checkAmount($amount); |
|||
90 | |||||
91 | /** |
||||
92 | * @var WalletModel $wallet |
||||
93 | */ |
||||
94 | 80 | $wallet = $walletService->getWallet($wallet); |
|||
95 | |||||
96 | 80 | $transactions = $this->multiOperation($wallet, [ |
|||
97 | 80 | app(Operation::class) |
|||
98 | 80 | ->setType(Transaction::TYPE_WITHDRAW) |
|||
99 | 80 | ->setConfirmed($confirmed) |
|||
100 | 80 | ->setAmount(-$amount) |
|||
101 | 80 | ->setMeta($meta), |
|||
102 | ]); |
||||
103 | |||||
104 | 80 | return current($transactions); |
|||
105 | 80 | }); |
|||
106 | } |
||||
107 | |||||
108 | /** |
||||
109 | * @param Wallet $wallet |
||||
110 | * @param int $amount |
||||
111 | * @param array|null $meta |
||||
112 | * @param bool $confirmed |
||||
113 | * @return Transaction |
||||
114 | */ |
||||
115 | 101 | public function deposit(Wallet $wallet, $amount, ?array $meta, bool $confirmed = true): Transaction |
|||
116 | { |
||||
117 | return app(LockService::class)->lock($this, __FUNCTION__, function () use ($wallet, $amount, $meta, $confirmed) { |
||||
118 | 101 | $walletService = app(WalletService::class); |
|||
119 | 101 | $walletService->checkAmount($amount); |
|||
120 | |||||
121 | /** |
||||
122 | * @var WalletModel $wallet |
||||
123 | */ |
||||
124 | 98 | $wallet = $walletService->getWallet($wallet); |
|||
125 | |||||
126 | 98 | $transactions = $this->multiOperation($wallet, [ |
|||
127 | 98 | app(Operation::class) |
|||
128 | 98 | ->setType(Transaction::TYPE_DEPOSIT) |
|||
129 | 98 | ->setConfirmed($confirmed) |
|||
130 | 98 | ->setAmount($amount) |
|||
131 | 98 | ->setMeta($meta), |
|||
132 | ]); |
||||
133 | |||||
134 | 98 | return current($transactions); |
|||
135 | 101 | }); |
|||
136 | } |
||||
137 | |||||
138 | /** |
||||
139 | * @param Wallet $wallet |
||||
140 | * @param int $amount |
||||
141 | * @param bool $allowZero |
||||
142 | * @return void |
||||
143 | * @throws BalanceIsEmpty |
||||
144 | * @throws InsufficientFunds |
||||
145 | */ |
||||
146 | 76 | public function verifyWithdraw(Wallet $wallet, $amount, bool $allowZero = null): void |
|||
147 | { |
||||
148 | /** |
||||
149 | * @var HasWallet $wallet |
||||
150 | */ |
||||
151 | 76 | if ($amount && ! $wallet->balance) { |
|||
152 | 21 | throw new BalanceIsEmpty(trans('wallet::errors.wallet_empty')); |
|||
0 ignored issues
–
show
It seems like
trans('wallet::errors.wallet_empty') can also be of type array and 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
![]() |
|||||
153 | } |
||||
154 | |||||
155 | 67 | if (! $wallet->canWithdraw($amount, $allowZero)) { |
|||
156 | 3 | throw new InsufficientFunds(trans('wallet::errors.insufficient_funds')); |
|||
0 ignored issues
–
show
It seems like
trans('wallet::errors.insufficient_funds') can also be of type array and 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
![]() |
|||||
157 | } |
||||
158 | 65 | } |
|||
159 | |||||
160 | /** |
||||
161 | * Create Operation without DB::transaction. |
||||
162 | * |
||||
163 | * @param Wallet $self |
||||
164 | * @param Operation[] $operations |
||||
165 | * @return array |
||||
166 | */ |
||||
167 | 110 | public function multiOperation(Wallet $self, array $operations): array |
|||
168 | { |
||||
169 | return app(LockService::class)->lock($this, __FUNCTION__, function () use ($self, $operations) { |
||||
170 | 110 | $amount = 0; |
|||
171 | 110 | $objects = []; |
|||
172 | 110 | $math = app(Mathable::class); |
|||
173 | 110 | foreach ($operations as $operation) { |
|||
174 | 110 | if ($operation->isConfirmed()) { |
|||
175 | 95 | $amount = $math->add($amount, $operation->getAmount()); |
|||
176 | } |
||||
177 | |||||
178 | 110 | $objects[] = $operation |
|||
179 | 110 | ->setWallet($self) |
|||
180 | 110 | ->create(); |
|||
181 | } |
||||
182 | |||||
183 | 110 | $this->addBalance($self, $amount); |
|||
0 ignored issues
–
show
It seems like
$amount can also be of type string ; however, parameter $amount of Bavix\Wallet\Services\CommonService::addBalance() does only seem to accept integer , 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
![]() |
|||||
184 | |||||
185 | 110 | return $objects; |
|||
186 | 110 | }); |
|||
187 | } |
||||
188 | |||||
189 | /** |
||||
190 | * Create Bring with DB::transaction. |
||||
191 | * |
||||
192 | * @param Bring[] $brings |
||||
193 | * @return array |
||||
194 | * @throws |
||||
195 | */ |
||||
196 | 8 | public function assemble(array $brings): array |
|||
197 | { |
||||
198 | return app(LockService::class)->lock($this, __FUNCTION__, function () use ($brings) { |
||||
199 | 8 | $self = $this; |
|||
200 | |||||
201 | return app(DbService::class)->transaction(static function () use ($self, $brings) { |
||||
202 | 8 | return $self->multiBrings($brings); |
|||
203 | 8 | }); |
|||
204 | 8 | }); |
|||
205 | } |
||||
206 | |||||
207 | /** |
||||
208 | * Create Bring without DB::transaction. |
||||
209 | * |
||||
210 | * @param array $brings |
||||
211 | * @return array |
||||
212 | */ |
||||
213 | 51 | public function multiBrings(array $brings): array |
|||
214 | { |
||||
215 | return app(LockService::class)->lock($this, __FUNCTION__, function () use ($brings) { |
||||
216 | 51 | $objects = []; |
|||
217 | 51 | foreach ($brings as $bring) { |
|||
218 | 51 | $objects[] = $bring->create(); |
|||
219 | } |
||||
220 | |||||
221 | 51 | return $objects; |
|||
222 | 51 | }); |
|||
223 | } |
||||
224 | |||||
225 | /** |
||||
226 | * @param Wallet $wallet |
||||
227 | * @param int $amount |
||||
228 | * @return bool |
||||
229 | * @throws |
||||
230 | */ |
||||
231 | 114 | public function addBalance(Wallet $wallet, $amount): bool |
|||
232 | { |
||||
233 | return app(LockService::class)->lock($this, __FUNCTION__, static function () use ($wallet, $amount) { |
||||
234 | /** |
||||
235 | * @var WalletModel $wallet |
||||
236 | */ |
||||
237 | 114 | $balance = app(Storable::class) |
|||
238 | 114 | ->incBalance($wallet, $amount); |
|||
239 | |||||
240 | try { |
||||
241 | 114 | $result = $wallet->update(compact('balance')); |
|||
242 | 2 | } catch (\Throwable $throwable) { |
|||
243 | 2 | app(Storable::class) |
|||
244 | 2 | ->setBalance($wallet, $wallet->getAvailableBalance()); |
|||
0 ignored issues
–
show
It seems like
$wallet->getAvailableBalance() can also be of type double ; however, parameter $amount of Bavix\Wallet\Interfaces\Storable::setBalance() does only seem to accept integer , 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
![]() |
|||||
245 | |||||
246 | 2 | throw $throwable; |
|||
247 | } |
||||
248 | |||||
249 | 112 | if (! $result) { |
|||
250 | 2 | app(Storable::class) |
|||
251 | 2 | ->setBalance($wallet, $wallet->getAvailableBalance()); |
|||
252 | } |
||||
253 | |||||
254 | 112 | return $result; |
|||
255 | 114 | }); |
|||
256 | } |
||||
257 | } |
||||
258 |