Passed
Push — master ( e72d83...d1ec6f )
by Бабичев
15:06 queued 05:14
created

HasWallet::wallet()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 2

Importance

Changes 2
Bugs 1 Features 0
Metric Value
cc 2
eloc 7
c 2
b 1
f 0
nc 2
nop 0
dl 0
loc 9
ccs 8
cts 8
cp 1
crap 2
rs 10
1
<?php
2
3
namespace Bavix\Wallet\Traits;
4
5
use Bavix\Wallet\Interfaces\Wallet;
6
use Bavix\Wallet\Models\Transaction;
7
use Bavix\Wallet\Models\Transfer;
8
use Bavix\Wallet\Models\Wallet as WalletModel;
9
use Bavix\Wallet\Services\CommonService;
10
use Bavix\Wallet\Services\WalletService;
11
use Illuminate\Database\Eloquent\Relations\MorphMany;
12
use Illuminate\Database\Eloquent\Relations\MorphOne;
13
use Illuminate\Support\Collection;
14
use Illuminate\Support\Facades\DB;
15
use Throwable;
16
use function app;
17
use function config;
18
19
/**
20
 * Trait HasWallet
21
 *
22
 * @package Bavix\Wallet\Traits
23
 *
24
 * @property-read Collection|WalletModel[] $wallets
25
 * @property-read int $balance
26
 */
27
trait HasWallet
28
{
29
30
    use MorphOneWallet;
31
32
    /**
33
     * The input means in the system
34
     *
35
     * @param int $amount
36
     * @param array|null $meta
37
     * @param bool $confirmed
38
     *
39
     * @return Transaction
40
     */
41 46
    public function deposit(int $amount, ?array $meta = null, bool $confirmed = true): Transaction
42
    {
43 46
        $self = $this;
44
        return DB::transaction(static function() use ($self, $amount, $meta, $confirmed) {
45 46
            return app(CommonService::class)
46 46
                ->deposit($self, $amount, $meta, $confirmed);
0 ignored issues
show
Bug introduced by
$self of type Bavix\Wallet\Traits\HasWallet is incompatible with the type Bavix\Wallet\Interfaces\Wallet expected by parameter $wallet of Bavix\Wallet\Services\CommonService::deposit(). ( Ignorable by Annotation )

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

46
                ->deposit(/** @scrutinizer ignore-type */ $self, $amount, $meta, $confirmed);
Loading history...
47 46
        });
48
    }
49
50
    /**
51
     * Magic laravel framework method, makes it
52
     *  possible to call property balance
53
     *
54
     * Example:
55
     *  $user1 = User::first()->load('wallet');
56
     *  $user2 = User::first()->load('wallet');
57
     *
58
     * Without static:
59
     *  var_dump($user1->balance, $user2->balance); // 100 100
60
     *  $user1->deposit(100);
61
     *  $user2->deposit(100);
62
     *  var_dump($user1->balance, $user2->balance); // 200 200
63
     *
64
     * With static:
65
     *  var_dump($user1->balance, $user2->balance); // 100 100
66
     *  $user1->deposit(100);
67
     *  var_dump($user1->balance); // 200
68
     *  $user2->deposit(100);
69
     *  var_dump($user2->balance); // 300
70
     *
71
     * @return int
72
     * @throws
73
     */
74 64
    public function getBalanceAttribute(): int
75
    {
76 64
        return app(WalletService::class)->getBalance($this);
0 ignored issues
show
Bug introduced by
$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::getBalance(). ( Ignorable by Annotation )

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

76
        return app(WalletService::class)->getBalance(/** @scrutinizer ignore-type */ $this);
Loading history...
77
    }
78
79
    /**
80
     * all user actions on wallets will be in this method
81
     *
82
     * @return MorphMany
83
     */
84 50
    public function transactions(): MorphMany
85
    {
86 50
        return ($this instanceof WalletModel ? $this->holder : $this)
87 50
            ->morphMany(config('wallet.transaction.model'), 'payable');
0 ignored issues
show
Bug introduced by
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 ignore-call  annotation

87
            ->/** @scrutinizer ignore-call */ morphMany(config('wallet.transaction.model'), 'payable');
Loading history...
88
    }
89
90
    /**
91
     * This method ignores errors that occur when transferring funds
92
     *
93
     * @param Wallet $wallet
94
     * @param int $amount
95
     * @param array|null $meta
96
     * @return null|Transfer
97
     */
98 3
    public function safeTransfer(Wallet $wallet, int $amount, ?array $meta = null): ?Transfer
99
    {
100
        try {
101 3
            return $this->transfer($wallet, $amount, $meta);
102 3
        } catch (Throwable $throwable) {
103 3
            return null;
104
        }
105
    }
106
107
    /**
108
     * A method that transfers funds from host to host
109
     *
110
     * @param Wallet $wallet
111
     * @param int $amount
112
     * @param array|null $meta
113
     * @return Transfer
114
     * @throws
115
     */
116 7
    public function transfer(Wallet $wallet, int $amount, ?array $meta = null): Transfer
117
    {
118 7
        app(CommonService::class)->verifyWithdraw($this, $amount);
0 ignored issues
show
Bug introduced by
$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 ignore-type  annotation

118
        app(CommonService::class)->verifyWithdraw(/** @scrutinizer ignore-type */ $this, $amount);
Loading history...
119 7
        return $this->forceTransfer($wallet, $amount, $meta);
120
    }
121
122
    /**
123
     * Withdrawals from the system
124
     *
125
     * @param int $amount
126
     * @param array|null $meta
127
     * @param bool $confirmed
128
     *
129
     * @return Transaction
130
     */
131 29
    public function withdraw(int $amount, ?array $meta = null, bool $confirmed = true): Transaction
132
    {
133 29
        app(CommonService::class)->verifyWithdraw($this, $amount);
0 ignored issues
show
Bug introduced by
$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 ignore-type  annotation

133
        app(CommonService::class)->verifyWithdraw(/** @scrutinizer ignore-type */ $this, $amount);
Loading history...
134 22
        return $this->forceWithdraw($amount, $meta, $confirmed);
135
    }
136
137
    /**
138
     * Checks if you can withdraw funds
139
     *
140
     * @param int $amount
141
     * @param bool $allowZero
142
     * @return bool
143
     */
144 38
    public function canWithdraw(int $amount, bool $allowZero = null): bool
145
    {
146
        /**
147
         * Allow to buy for free with a negative balance
148
         */
149 38
        if ($allowZero && $amount === 0) {
150 4
            return true;
151
        }
152
153 37
        return $this->balance >= $amount;
154
    }
155
156
    /**
157
     * Forced to withdraw funds from system
158
     *
159
     * @param int $amount
160
     * @param array|null $meta
161
     * @param bool $confirmed
162
     *
163
     * @return Transaction
164
     */
165 27
    public function forceWithdraw(int $amount, ?array $meta = null, bool $confirmed = true): Transaction
166
    {
167 27
        $self = $this;
168
        return DB::transaction(static function() use ($self, $amount, $meta, $confirmed) {
169 27
            return app(CommonService::class)
170 27
                ->forceWithdraw($self, $amount, $meta, $confirmed);
0 ignored issues
show
Bug introduced by
$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 ignore-type  annotation

170
                ->forceWithdraw(/** @scrutinizer ignore-type */ $self, $amount, $meta, $confirmed);
Loading history...
171 27
        });
172
    }
173
174
    /**
175
     * the forced transfer is needed when the user does not have the money and we drive it.
176
     * Sometimes you do. Depends on business logic.
177
     *
178
     * @param Wallet $wallet
179
     * @param int $amount
180
     * @param array|null $meta
181
     * @return Transfer
182
     */
183 7
    public function forceTransfer(Wallet $wallet, int $amount, ?array $meta = null): Transfer
184
    {
185 7
        $self = $this;
186
        return DB::transaction(static function() use ($self, $amount, $wallet, $meta) {
187 7
            return app(CommonService::class)
188 7
                ->forceTransfer($self, $wallet, $amount, $meta);
0 ignored issues
show
Bug introduced by
$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 ignore-type  annotation

188
                ->forceTransfer(/** @scrutinizer ignore-type */ $self, $wallet, $amount, $meta);
Loading history...
189 7
        });
190
    }
191
192
    /**
193
     * the transfer table is used to confirm the payment
194
     * this method receives all transfers
195
     *
196
     * @return MorphMany
197
     */
198 16
    public function transfers(): MorphMany
199
    {
200 16
        return app(WalletService::class)
201 16
            ->getWallet($this, false)
0 ignored issues
show
Bug introduced by
$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 ignore-type  annotation

201
            ->getWallet(/** @scrutinizer ignore-type */ $this, false)
Loading history...
202 16
            ->morphMany(config('wallet.transfer.model'), 'from');
203
    }
204
205
}
206