1 | <?php |
||||
2 | |||||
3 | namespace Bavix\Wallet\Traits; |
||||
4 | |||||
5 | use function app; |
||||
6 | use Bavix\Wallet\Interfaces\Mathable; |
||||
7 | use Bavix\Wallet\Interfaces\Storable; |
||||
8 | use Bavix\Wallet\Interfaces\Wallet; |
||||
9 | use Bavix\Wallet\Models\Transaction; |
||||
10 | use Bavix\Wallet\Models\Transfer; |
||||
11 | use Bavix\Wallet\Models\Wallet as WalletModel; |
||||
12 | use Bavix\Wallet\Services\CommonService; |
||||
13 | use Bavix\Wallet\Services\DbService; |
||||
14 | use Bavix\Wallet\Services\WalletService; |
||||
15 | use function config; |
||||
16 | use Illuminate\Database\Eloquent\Relations\MorphMany; |
||||
17 | use Illuminate\Support\Collection; |
||||
18 | use Throwable; |
||||
19 | |||||
20 | /** |
||||
21 | * Trait HasWallet. |
||||
22 | * |
||||
23 | * |
||||
24 | * @property-read Collection|WalletModel[] $wallets |
||||
25 | * @property-read int $balance |
||||
26 | */ |
||||
27 | trait HasWallet |
||||
28 | { |
||||
29 | use MorphOneWallet; |
||||
30 | |||||
31 | /** |
||||
32 | * The input means in the system. |
||||
33 | * |
||||
34 | * @param int $amount |
||||
35 | * @param array|null $meta |
||||
36 | * @param bool $confirmed |
||||
37 | * |
||||
38 | * @return Transaction |
||||
39 | * @throws |
||||
40 | */ |
||||
41 | 92 | public function deposit($amount, ?array $meta = null, bool $confirmed = true): Transaction |
|||
42 | { |
||||
43 | 92 | $self = $this; |
|||
44 | |||||
45 | return app(DbService::class)->transaction(static function () use ($self, $amount, $meta, $confirmed) { |
||||
46 | 92 | return app(CommonService::class) |
|||
47 | 92 | ->deposit($self, $amount, $meta, $confirmed); |
|||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||
48 | 92 | }); |
|||
49 | } |
||||
50 | |||||
51 | /** |
||||
52 | * Magic laravel framework method, makes it |
||||
53 | * possible to call property balance. |
||||
54 | * |
||||
55 | * Example: |
||||
56 | * $user1 = User::first()->load('wallet'); |
||||
57 | * $user2 = User::first()->load('wallet'); |
||||
58 | * |
||||
59 | * Without static: |
||||
60 | * var_dump($user1->balance, $user2->balance); // 100 100 |
||||
61 | * $user1->deposit(100); |
||||
62 | * $user2->deposit(100); |
||||
63 | * var_dump($user1->balance, $user2->balance); // 200 200 |
||||
64 | * |
||||
65 | * With static: |
||||
66 | * var_dump($user1->balance, $user2->balance); // 100 100 |
||||
67 | * $user1->deposit(100); |
||||
68 | * var_dump($user1->balance); // 200 |
||||
69 | * $user2->deposit(100); |
||||
70 | * var_dump($user2->balance); // 300 |
||||
71 | * |
||||
72 | * @return int|float |
||||
73 | * @throws |
||||
74 | */ |
||||
75 | 118 | public function getBalanceAttribute() |
|||
76 | { |
||||
77 | 118 | return app(Storable::class)->getBalance($this); |
|||
78 | } |
||||
79 | |||||
80 | /** |
||||
81 | * all user actions on wallets will be in this method. |
||||
82 | * |
||||
83 | * @return MorphMany |
||||
84 | */ |
||||
85 | 110 | public function transactions(): MorphMany |
|||
86 | { |
||||
87 | 110 | return ($this instanceof WalletModel ? $this->holder : $this) |
|||
88 | 110 | ->morphMany(config('wallet.transaction.model', Transaction::class), 'payable'); |
|||
0 ignored issues
–
show
It seems like
morphMany() must be provided by classes using this trait. How about adding it as abstract method to this trait?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
89 | } |
||||
90 | |||||
91 | /** |
||||
92 | * This method ignores errors that occur when transferring funds. |
||||
93 | * |
||||
94 | * @param Wallet $wallet |
||||
95 | * @param int $amount |
||||
96 | * @param array|null $meta |
||||
97 | * @return null|Transfer |
||||
98 | */ |
||||
99 | 3 | public function safeTransfer(Wallet $wallet, $amount, ?array $meta = null): ?Transfer |
|||
100 | { |
||||
101 | try { |
||||
102 | 3 | return $this->transfer($wallet, $amount, $meta); |
|||
103 | 3 | } catch (Throwable $throwable) { |
|||
104 | 3 | return null; |
|||
105 | } |
||||
106 | } |
||||
107 | |||||
108 | /** |
||||
109 | * A method that transfers funds from host to host. |
||||
110 | * |
||||
111 | * @param Wallet $wallet |
||||
112 | * @param int $amount |
||||
113 | * @param array|null $meta |
||||
114 | * @return Transfer |
||||
115 | * @throws |
||||
116 | */ |
||||
117 | 8 | public function transfer(Wallet $wallet, $amount, ?array $meta = null): Transfer |
|||
118 | { |
||||
119 | 8 | app(CommonService::class)->verifyWithdraw($this, $amount); |
|||
0 ignored issues
–
show
$this of type Bavix\Wallet\Traits\HasWallet is incompatible with the type Bavix\Wallet\Interfaces\Wallet expected by parameter $wallet of Bavix\Wallet\Services\Co...rvice::verifyWithdraw() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
120 | |||||
121 | 8 | return $this->forceTransfer($wallet, $amount, $meta); |
|||
122 | } |
||||
123 | |||||
124 | /** |
||||
125 | * Withdrawals from the system. |
||||
126 | * |
||||
127 | * @param int $amount |
||||
128 | * @param array|null $meta |
||||
129 | * @param bool $confirmed |
||||
130 | * |
||||
131 | * @return Transaction |
||||
132 | */ |
||||
133 | 39 | public function withdraw($amount, ?array $meta = null, bool $confirmed = true): Transaction |
|||
134 | { |
||||
135 | 39 | app(CommonService::class)->verifyWithdraw($this, $amount); |
|||
0 ignored issues
–
show
$this of type Bavix\Wallet\Traits\HasWallet is incompatible with the type Bavix\Wallet\Interfaces\Wallet expected by parameter $wallet of Bavix\Wallet\Services\Co...rvice::verifyWithdraw() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
136 | |||||
137 | 32 | return $this->forceWithdraw($amount, $meta, $confirmed); |
|||
138 | } |
||||
139 | |||||
140 | /** |
||||
141 | * Checks if you can withdraw funds. |
||||
142 | * |
||||
143 | * @param int $amount |
||||
144 | * @param bool $allowZero |
||||
145 | * @return bool |
||||
146 | */ |
||||
147 | 69 | public function canWithdraw($amount, bool $allowZero = null): bool |
|||
148 | { |
||||
149 | 69 | $math = app(Mathable::class); |
|||
150 | |||||
151 | /** |
||||
152 | * Allow to buy for free with a negative balance. |
||||
153 | */ |
||||
154 | 69 | if ($allowZero && ! $math->compare($amount, 0)) { |
|||
155 | 11 | return true; |
|||
156 | } |
||||
157 | |||||
158 | 66 | return $math->compare($this->balance, $amount) >= 0; |
|||
159 | } |
||||
160 | |||||
161 | /** |
||||
162 | * Forced to withdraw funds from system. |
||||
163 | * |
||||
164 | * @param int $amount |
||||
165 | * @param array|null $meta |
||||
166 | * @param bool $confirmed |
||||
167 | * |
||||
168 | * @return Transaction |
||||
169 | * @throws |
||||
170 | */ |
||||
171 | 47 | public function forceWithdraw($amount, ?array $meta = null, bool $confirmed = true): Transaction |
|||
172 | { |
||||
173 | 47 | $self = $this; |
|||
174 | |||||
175 | return app(DbService::class)->transaction(static function () use ($self, $amount, $meta, $confirmed) { |
||||
176 | 47 | return app(CommonService::class) |
|||
177 | 47 | ->forceWithdraw($self, $amount, $meta, $confirmed); |
|||
0 ignored issues
–
show
$self of type Bavix\Wallet\Traits\HasWallet is incompatible with the type Bavix\Wallet\Interfaces\Wallet expected by parameter $wallet 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
![]() |
|||||
178 | 47 | }); |
|||
179 | } |
||||
180 | |||||
181 | /** |
||||
182 | * the forced transfer is needed when the user does not have the money and we drive it. |
||||
183 | * Sometimes you do. Depends on business logic. |
||||
184 | * |
||||
185 | * @param Wallet $wallet |
||||
186 | * @param int $amount |
||||
187 | * @param array|null $meta |
||||
188 | * @return Transfer |
||||
189 | * @throws |
||||
190 | */ |
||||
191 | 8 | public function forceTransfer(Wallet $wallet, $amount, ?array $meta = null): Transfer |
|||
192 | { |
||||
193 | 8 | $self = $this; |
|||
194 | |||||
195 | return app(DbService::class)->transaction(static function () use ($self, $amount, $wallet, $meta) { |
||||
196 | 8 | return app(CommonService::class) |
|||
197 | 8 | ->forceTransfer($self, $wallet, $amount, $meta); |
|||
0 ignored issues
–
show
$self 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
![]() |
|||||
198 | 8 | }); |
|||
199 | } |
||||
200 | |||||
201 | /** |
||||
202 | * the transfer table is used to confirm the payment |
||||
203 | * this method receives all transfers. |
||||
204 | * |
||||
205 | * @return MorphMany |
||||
206 | */ |
||||
207 | 39 | public function transfers(): MorphMany |
|||
208 | { |
||||
209 | 39 | return app(WalletService::class) |
|||
210 | 39 | ->getWallet($this, false) |
|||
0 ignored issues
–
show
$this of type Bavix\Wallet\Traits\HasWallet is incompatible with the type Bavix\Wallet\Interfaces\Wallet expected by parameter $object of Bavix\Wallet\Services\WalletService::getWallet() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
211 | 39 | ->morphMany(config('wallet.transfer.model', Transfer::class), 'from'); |
|||
212 | } |
||||
213 | } |
||||
214 |