| 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
Loading history...
|
|||||
| 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
Loading history...
|
|||||
| 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
Loading history...
|
|||||
| 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
Loading history...
|
|||||
| 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
Loading history...
|
|||||
| 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
Loading history...
|
|||||
| 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
Loading history...
|
|||||
| 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 |