Passed
Push — main ( 96c851...f3bc21 )
by Michael
03:43
created

CouponService::performBasicChecksOn()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 21
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 10
nc 4
nop 2
dl 0
loc 21
ccs 11
cts 11
cp 1
crap 4
rs 9.9332
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace MichaelRubel\Couponables\Services;
6
7
use Illuminate\Database\Eloquent\Model;
8
use Illuminate\Support\Traits\Macroable;
9
use MichaelRubel\Couponables\Events\CouponDisabled;
10
use MichaelRubel\Couponables\Events\CouponExpired;
11
use MichaelRubel\Couponables\Events\CouponIsOverLimit;
12
use MichaelRubel\Couponables\Events\CouponIsOverQuantity;
13
use MichaelRubel\Couponables\Events\CouponRedeemed;
14
use MichaelRubel\Couponables\Events\CouponVerified;
15
use MichaelRubel\Couponables\Events\NotAllowedToRedeem;
16
use MichaelRubel\Couponables\Exceptions\CouponDisabledException;
17
use MichaelRubel\Couponables\Exceptions\CouponExpiredException;
18
use MichaelRubel\Couponables\Exceptions\InvalidCouponException;
19
use MichaelRubel\Couponables\Exceptions\NotAllowedToRedeemException;
20
use MichaelRubel\Couponables\Exceptions\OverLimitException;
21
use MichaelRubel\Couponables\Exceptions\OverQuantityException;
22
use MichaelRubel\Couponables\Models\Contracts\CouponContract;
23
use MichaelRubel\Couponables\Models\Contracts\CouponPivotContract;
24
use MichaelRubel\Couponables\Services\Contracts\CouponServiceContract;
25
use MichaelRubel\Couponables\Traits\Concerns\GeneratesCoupons;
26
27
class CouponService implements CouponServiceContract
28
{
29
    use Macroable, GeneratesCoupons;
0 ignored issues
show
Bug introduced by
The trait MichaelRubel\Couponables...ncerns\GeneratesCoupons requires the property $id which is not provided by MichaelRubel\Couponables\Services\CouponService.
Loading history...
Bug introduced by
The trait Illuminate\Support\Traits\Macroable requires the property $name which is not provided by MichaelRubel\Couponables\Services\CouponService.
Loading history...
30
31
    /**
32
     * @param  CouponContract  $model
33
     * @param  CouponPivotContract  $pivot
34
     */
35 61
    public function __construct(
36
        public CouponContract $model,
37
        public CouponPivotContract $pivot,
38
    ) {
39 61
    }
40
41
    /**
42
     * Get the coupon model by the code.
43
     *
44
     * @param  string|null  $code
45
     *
46
     * @return CouponContract|null
47
     */
48 40
    public function getCoupon(?string $code): ?CouponContract
49
    {
50 40
        return $this->model->firstWhere($this->model->getCodeColumn(), $code);
0 ignored issues
show
Bug introduced by
The method firstWhere() does not exist on MichaelRubel\Couponables...ontracts\CouponContract. Since it exists in all sub-types, consider adding an abstract or default implementation to MichaelRubel\Couponables...ontracts\CouponContract. ( Ignorable by Annotation )

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

50
        return $this->model->/** @scrutinizer ignore-call */ firstWhere($this->model->getCodeColumn(), $code);
Loading history...
51
    }
52
53
    /**
54
     * Perform the stateless checks on the coupon
55
     * model. Redeemer is optional in this case.
56
     *
57
     * @param  CouponContract  $coupon
58
     * @param  Model|null  $redeemer
59
     *
60
     * @return CouponContract
61
     *
62
     * @throws CouponExpiredException
63
     * @throws OverQuantityException
64
     * @throws CouponDisabledException
65
     */
66 31
    public function performBasicChecksOn(CouponContract $coupon, ?Model $redeemer = null): CouponContract
67
    {
68 31
        if ($coupon->isDisabled()) {
0 ignored issues
show
Bug introduced by
The method isDisabled() does not exist on MichaelRubel\Couponables...ontracts\CouponContract. Since it exists in all sub-types, consider adding an abstract or default implementation to MichaelRubel\Couponables...ontracts\CouponContract. ( Ignorable by Annotation )

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

68
        if ($coupon->/** @scrutinizer ignore-call */ isDisabled()) {
Loading history...
69 2
            event(new CouponDisabled($coupon, $redeemer));
70
71 2
            throw new CouponDisabledException;
72
        }
73
74 29
        if ($coupon->isExpired()) {
0 ignored issues
show
Bug introduced by
The method isExpired() does not exist on MichaelRubel\Couponables...ontracts\CouponContract. Since it exists in all sub-types, consider adding an abstract or default implementation to MichaelRubel\Couponables...ontracts\CouponContract. ( Ignorable by Annotation )

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

74
        if ($coupon->/** @scrutinizer ignore-call */ isExpired()) {
Loading history...
75 2
            event(new CouponExpired($coupon, $redeemer));
76
77 2
            throw new CouponExpiredException;
78
        }
79
80 27
        if ($coupon->isOverQuantity()) {
0 ignored issues
show
Bug introduced by
The method isOverQuantity() does not exist on MichaelRubel\Couponables...ontracts\CouponContract. Since it exists in all sub-types, consider adding an abstract or default implementation to MichaelRubel\Couponables...ontracts\CouponContract. ( Ignorable by Annotation )

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

80
        if ($coupon->/** @scrutinizer ignore-call */ isOverQuantity()) {
Loading history...
81 2
            event(new CouponIsOverQuantity($coupon, $redeemer));
82
83 2
            throw new OverQuantityException;
84
        }
85
86 27
        return $coupon;
87
    }
88
89
    /**
90
     * Perform the "Redeemer" checks on the coupon model.
91
     *
92
     * @param  CouponContract  $coupon
93
     * @param  Model  $redeemer
94
     *
95
     * @return CouponContract
96
     *
97
     * @throws OverLimitException
98
     * @throws NotAllowedToRedeemException
99
     */
100 26
    public function performRedeemerChecksOn(CouponContract $coupon, Model $redeemer): CouponContract
101
    {
102 26
        if (! $coupon->isAllowedToRedeemBy($redeemer)) {
0 ignored issues
show
Bug introduced by
The method isAllowedToRedeemBy() does not exist on MichaelRubel\Couponables...ontracts\CouponContract. Since it exists in all sub-types, consider adding an abstract or default implementation to MichaelRubel\Couponables...ontracts\CouponContract. ( Ignorable by Annotation )

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

102
        if (! $coupon->/** @scrutinizer ignore-call */ isAllowedToRedeemBy($redeemer)) {
Loading history...
103 5
            event(new NotAllowedToRedeem($coupon, $redeemer));
104
105 5
            throw new NotAllowedToRedeemException;
106
        }
107
108 21
        if ($coupon->isOverLimit($redeemer)) {
0 ignored issues
show
Bug introduced by
The method isOverLimit() does not exist on MichaelRubel\Couponables...ontracts\CouponContract. Since it exists in all sub-types, consider adding an abstract or default implementation to MichaelRubel\Couponables...ontracts\CouponContract. ( Ignorable by Annotation )

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

108
        if ($coupon->/** @scrutinizer ignore-call */ isOverLimit($redeemer)) {
Loading history...
109 3
            event(new CouponIsOverLimit($coupon, $redeemer));
110
111 3
            throw new OverLimitException;
112
        }
113
114 21
        return $coupon;
115
    }
116
117
    /**
118
     * Verify if coupon is valid otherwise throw an exception.
119
     *
120
     * @param  string|null  $code
121
     * @param  Model|null  $redeemer
122
     *
123
     * @return CouponContract
124
     * @throws CouponExpiredException
125
     * @throws InvalidCouponException
126
     * @throws NotAllowedToRedeemException
127
     * @throws OverLimitException
128
     * @throws OverQuantityException
129
     * @throws CouponDisabledException
130
     */
131 38
    public function verifyCoupon(?string $code, ?Model $redeemer = null): CouponContract
132
    {
133 38
        $coupon = $this->getCoupon($code) ?? throw new InvalidCouponException;
134
135 30
        $this->performBasicChecksOn($coupon);
136
137 26
        if ($redeemer) {
138 26
            $this->performRedeemerChecksOn($coupon, $redeemer);
139
        }
140
141 21
        event(new CouponVerified($coupon, $redeemer));
142
143 21
        return $coupon;
144
    }
145
146
    /**
147
     * Apply the coupon.
148
     *
149
     * @param  CouponContract  $coupon
150
     * @param  Model  $redeemer
151
     * @param  Model|null  $for
152
     *
153
     * @return CouponContract
154
     */
155 19
    public function applyCoupon(CouponContract $coupon, Model $redeemer, ?Model $for): CouponContract
156
    {
157 19
        $redeemer->coupons()->attach($coupon, [
158 19
            $this->pivot->getRedeemedTypeColumn() => $for?->getMorphClass(),
159 19
            $this->pivot->getRedeemedIdColumn()   => $for?->id,
160 19
            $this->pivot->getRedeemedAtColumn()   => now(),
161 19
            $this->pivot->getCreatedAtColumn()    => now(),
162 19
        ]);
163
164 19
        if (! is_null($coupon->{$this->model->getQuantityColumn()})) {
165 2
            $coupon->decrement($this->model->getQuantityColumn());
0 ignored issues
show
Bug introduced by
The method decrement() does not exist on MichaelRubel\Couponables...ontracts\CouponContract. Since it exists in all sub-types, consider adding an abstract or default implementation to MichaelRubel\Couponables...ontracts\CouponContract. ( Ignorable by Annotation )

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

165
            $coupon->/** @scrutinizer ignore-call */ 
166
                     decrement($this->model->getQuantityColumn());
Loading history...
166
        }
167
168 19
        event(new CouponRedeemed($coupon, $redeemer));
169
170 19
        return $coupon;
171
    }
172
}
173