WalletService::discount()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 3
c 0
b 0
f 0
nc 2
nop 2
dl 0
loc 8
ccs 4
cts 4
cp 1
crap 3
rs 10
1
<?php
2
3
namespace Bavix\Wallet\Services;
4
5
use function app;
6
use Bavix\Wallet\Exceptions\AmountInvalid;
7
use Bavix\Wallet\Interfaces\Customer;
8
use Bavix\Wallet\Interfaces\Discount;
9
use Bavix\Wallet\Interfaces\Mathable;
10
use Bavix\Wallet\Interfaces\MinimalTaxable;
11
use Bavix\Wallet\Interfaces\Storable;
12
use Bavix\Wallet\Interfaces\Taxable;
13
use Bavix\Wallet\Interfaces\Wallet;
14
use Bavix\Wallet\Models\Wallet as WalletModel;
15
use Bavix\Wallet\Traits\HasWallet;
16
17
class WalletService
18
{
19
    /**
20
     * @param Wallet $customer
21
     * @param Wallet $product
22
     * @return int
23
     */
24 51
    public function discount(Wallet $customer, Wallet $product): int
25
    {
26 51
        if ($customer instanceof Customer && $product instanceof Discount) {
27 21
            return $product->getPersonalDiscount($customer);
28
        }
29
30
        // without discount
31 40
        return 0;
32
    }
33
34
    /**
35
     * @param Wallet $object
36
     * @return int
37
     */
38 63
    public function decimalPlacesValue(Wallet $object): int
39
    {
40 63
        return $this->getWallet($object)->decimal_places ?: 2;
41
    }
42
43
    /**
44
     * @param Wallet $object
45
     * @return string
46
     */
47 17
    public function decimalPlaces(Wallet $object): string
48
    {
49 17
        return app(Mathable::class)
50 17
            ->pow(10, $this->decimalPlacesValue($object));
51
    }
52
53
    /**
54
     * Consider the fee that the system will receive.
55
     *
56
     * @param Wallet $wallet
57
     * @param int $amount
58
     * @return float|int
59
     */
60 52
    public function fee(Wallet $wallet, $amount)
61
    {
62 52
        $fee = 0;
63 52
        $math = app(Mathable::class);
64 52
        if ($wallet instanceof Taxable) {
65 14
            $placesValue = $this->decimalPlacesValue($wallet);
66 14
            $fee = $math->floor(
67 14
                $math->div(
68 14
                    $math->mul($amount, $wallet->getFeePercent(), 0),
69 14
                    100,
70
                    $placesValue
71
                )
72
            );
73
        }
74
75
        /**
76
         * Added minimum commission condition.
77
         *
78
         * @see https://github.com/bavix/laravel-wallet/issues/64#issuecomment-514483143
79
         */
80 52
        if ($wallet instanceof MinimalTaxable) {
81 1
            $minimal = $wallet->getMinimalFee();
82 1
            if (app(Mathable::class)->compare($fee, $minimal) === -1) {
83 1
                $fee = $minimal;
84
            }
85
        }
86
87 52
        return $fee;
88
    }
89
90
    /**
91
     * The amount of checks for errors.
92
     *
93
     * @param int $amount
94
     * @throws
95
     */
96 113
    public function checkAmount($amount): void
97
    {
98 113
        if (app(Mathable::class)->compare($amount, 0) === -1) {
99 3
            throw new AmountInvalid(trans('wallet::errors.price_positive'));
0 ignored issues
show
Bug introduced by
It seems like trans('wallet::errors.price_positive') can also be of type array and array; however, parameter $message of Bavix\Wallet\Exceptions\...tInvalid::__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

99
            throw new AmountInvalid(/** @scrutinizer ignore-type */ trans('wallet::errors.price_positive'));
Loading history...
100
        }
101 110
    }
102
103
    /**
104
     * @param Wallet $object
105
     * @param bool $autoSave
106
     * @return WalletModel
107
     */
108 128
    public function getWallet(Wallet $object, bool $autoSave = true): WalletModel
109
    {
110
        /**
111
         * @var WalletModel $wallet
112
         */
113 128
        $wallet = $object;
114
115 128
        if (! ($object instanceof WalletModel)) {
116
            /**
117
             * @var HasWallet $object
118
             */
119 85
            $wallet = $object->wallet;
120
        }
121
122 128
        if ($autoSave) {
123 128
            $wallet->exists or $wallet->save();
124
        }
125
126 128
        return $wallet;
127
    }
128
129
    /**
130
     * @param WalletModel $wallet
131
     * @return bool
132
     */
133 27
    public function refresh(WalletModel $wallet): bool
134
    {
135
        return app(LockService::class)->lock($this, __FUNCTION__, static function () use ($wallet) {
136 27
            $math = app(Mathable::class);
137 27
            app(Storable::class)->getBalance($wallet);
138 27
            $whatIs = $wallet->balance;
139 27
            $balance = $wallet->getAvailableBalance();
140 27
            $wallet->balance = $balance;
141
142 27
            return app(Storable::class)->setBalance($wallet, $balance) &&
0 ignored issues
show
Bug introduced by
It seems like $balance 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 ignore-type  annotation

142
            return app(Storable::class)->setBalance($wallet, /** @scrutinizer ignore-type */ $balance) &&
Loading history...
143 27
                (! $math->compare($whatIs, $balance) || $wallet->save());
144 27
        });
145
    }
146
}
147