Completed
Pull Request — master (#40)
by Бабичев
08:57
created

CommonService::deposit()   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 11
    public function transfer(Wallet $from, Wallet $to, int $amount, ?array $meta = null, string $status = Transfer::STATUS_TRANSFER): Transfer
30
    {
31 11
        $this->verifyWithdraw($from, $amount);
32 11
        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 18
    public function forceTransfer(Wallet $from, Wallet $to, int $amount, ?array $meta = null, string $status = Transfer::STATUS_TRANSFER): Transfer
44
    {
45 18
        $fee = app(WalletService::class)->fee($to, $amount);
46 18
        $withdraw = $this->forceWithdraw($from, $amount + $fee, $meta);
47 18
        $deposit = $this->deposit($to, $amount, $meta);
48
49 18
        $from = app(WalletService::class)
50 18
            ->getWallet($from);
51
52 18
        $transfers = $this->multiBrings([
53 18
            (new Bring())
54 18
                ->setStatus($status)
55 18
                ->setDeposit($deposit)
56 18
                ->setWithdraw($withdraw)
57 18
                ->setFrom($from)
58 18
                ->setTo($to)
59
        ]);
60
61 18
        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 29
    public function forceWithdraw(Wallet $wallet, int $amount, ?array $meta, bool $confirmed = true): Transaction
72
    {
73 29
        $walletService = app(WalletService::class);
74 29
        $walletService->checkAmount($amount);
75
76
        /**
77
         * @var WalletModel $wallet
78
         */
79 29
        $wallet = $walletService->getWallet($wallet);
80
81 29
        $transactions = $this->multiOperation($wallet, [
82 29
            (new Operation())
83 29
                ->setType(Transaction::TYPE_WITHDRAW)
84 29
                ->setConfirmed($confirmed)
85 29
                ->setAmount(-$amount)
86 29
                ->setMeta($meta)
87
        ]);
88
89 29
        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 34
    public function deposit(Wallet $wallet, int $amount, ?array $meta, bool $confirmed = true): Transaction
100
    {
101 34
        $walletService = app(WalletService::class);
102 34
        $walletService->checkAmount($amount);
103
104
        /**
105
         * @var WalletModel $wallet
106
         */
107 31
        $wallet = $walletService->getWallet($wallet);
108
109 31
        $transactions = $this->multiOperation($wallet, [
110 31
            (new Operation())
111 31
                ->setType(Transaction::TYPE_DEPOSIT)
112 31
                ->setConfirmed($confirmed)
113 31
                ->setAmount($amount)
114 31
                ->setMeta($meta)
115
        ]);
116
117 31
        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 35
    public function verifyWithdraw(Wallet $wallet, int $amount): void
128
    {
129
        /**
130
         * @var HasWallet $wallet
131
         */
132 35
        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 29
        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 28
    }
140
141
    /**
142
     * Create Operation with DB::transaction
143
     *
144
     * @param Wallet $self
145
     * @param Operation[] $transactions
146
     * @return Transaction[]
147
     */
148
    public function enforce(Wallet $self, array $transactions): array
149
    {
150
        return DB::transaction(function () use ($self, $transactions) {
151
            return $this->multiOperation($self, $transactions);
152
        });
153
    }
154
155
    /**
156
     * Create Operation without DB::transaction
157
     *
158
     * @param Wallet $self
159
     * @param array $operations
160
     * @return array
161
     */
162 31
    public function multiOperation(Wallet $self, array $operations): array
163
    {
164 31
        $amount = 0;
165 31
        $objects = [];
166 31
        foreach ($operations as $operation) {
167 31
            if ($operation->isConfirmed()) {
168 31
                $amount += $operation->getAmount();
169
            }
170
171 31
            $objects[] = $operation
172 31
                ->setWallet($self)
173 31
                ->create();
174
        }
175
176 31
        $this->addBalance($self, $amount);
177 31
        return $objects;
178
    }
179
180
    /**
181
     * Create Bring with DB::transaction
182
     *
183
     * @param Bring[] $brings
184
     * @return array
185
     * @throws
186
     */
187 2
    public function assemble(array $brings): array
188
    {
189
        return DB::transaction(function () use ($brings) {
190 2
            return $this->multiBrings($brings);
191 2
        });
192
    }
193
194
    /**
195
     * Create Bring without DB::transaction
196
     *
197
     * @param array $brings
198
     * @return array
199
     */
200 19
    public function multiBrings(array $brings): array
201
    {
202 19
        $objects = [];
203 19
        foreach ($brings as $bring) {
204 19
            $objects[] = $bring->create();
205
        }
206
207 19
        return $objects;
208
    }
209
210
    /**
211
     * @param Wallet $wallet
212
     * @param int $amount
213
     * @return bool
214
     * @throws
215
     */
216 31
    public function addBalance(Wallet $wallet, int $amount): bool
217
    {
218
        /**
219
         * @var ProxyService $proxy
220
         * @var WalletModel $wallet
221
         */
222 31
        $proxy = app(ProxyService::class);
223 31
        $balance = $wallet->balance + $amount;
224 31
        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

224
        if ($proxy->has(/** @scrutinizer ignore-type */ $wallet->getKey())) {
Loading history...
225 31
            $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

225
            $balance = $proxy->get(/** @scrutinizer ignore-type */ $wallet->getKey()) + $amount;
Loading history...
226
        }
227
228 31
        $result = $wallet->update(compact('balance'));
229 31
        $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

229
        $proxy->set(/** @scrutinizer ignore-type */ $wallet->getKey(), $balance);
Loading history...
230
231 31
        return $result;
232
    }
233
234
}
235