CouponService::performBasicChecksOn()   A
last analyzed

Complexity

Conditions 5
Paths 5

Size

Total Lines 25
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 5

Importance

Changes 0
Metric Value
eloc 12
c 0
b 0
f 0
dl 0
loc 25
ccs 13
cts 13
cp 1
rs 9.5555
cc 5
nc 5
nop 2
crap 5
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\CouponException;
18
use MichaelRubel\Couponables\Exceptions\CouponExpiredException;
19
use MichaelRubel\Couponables\Exceptions\InvalidCouponException;
20
use MichaelRubel\Couponables\Exceptions\NotAllowedToRedeemException;
21
use MichaelRubel\Couponables\Exceptions\OverLimitException;
22
use MichaelRubel\Couponables\Exceptions\OverQuantityException;
23
use MichaelRubel\Couponables\Models\Contracts\CouponContract;
24
use MichaelRubel\Couponables\Models\Contracts\CouponPivotContract;
25
use MichaelRubel\Couponables\Services\Contracts\CouponServiceContract;
26
use MichaelRubel\Couponables\Traits\Concerns\GeneratesCoupons;
27
28
class CouponService implements CouponServiceContract
29
{
30
    use GeneratesCoupons, Macroable;
0 ignored issues
show
Bug introduced by
The trait Illuminate\Support\Traits\Macroable requires the property $name which is not provided by MichaelRubel\Couponables\Services\CouponService.
Loading history...
Bug introduced by
The trait MichaelRubel\Couponables...ncerns\GeneratesCoupons requires the property $id which is not provided by MichaelRubel\Couponables\Services\CouponService.
Loading history...
31
32
    /**
33
     * @param  CouponContract  $model
34
     * @param  CouponPivotContract  $pivot
35
     */
36 62
    public function __construct(
37
        public CouponContract $model,
38
        public CouponPivotContract $pivot,
39
    ) {
40 62
    }
41
42
    /**
43
     * Get the coupon model by the code.
44
     *
45
     * @param  string|null  $code
46
     *
47
     * @return CouponContract|null
48
     */
49 41
    public function getCoupon(?string $code): ?CouponContract
50
    {
51 41
        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

51
        return $this->model->/** @scrutinizer ignore-call */ firstWhere($this->model->getCodeColumn(), $code);
Loading history...
52
    }
53
54
    /**
55
     * Verify if coupon is valid otherwise throw an exception.
56
     *
57
     * @param  string|null  $code
58
     * @param  Model|null  $redeemer
59
     *
60
     * @return CouponContract
61
     *
62
     * @throws CouponException
63
     * @throws OverLimitException
64
     * @throws OverQuantityException
65
     * @throws InvalidCouponException
66
     * @throws CouponExpiredException
67
     * @throws CouponDisabledException
68
     * @throws NotAllowedToRedeemException
69
     */
70 38
    public function verifyCoupon(?string $code, ?Model $redeemer = null): CouponContract
71
    {
72 38
        $coupon = $this->getCoupon($code) ?? throw new InvalidCouponException;
73
74 30
        $this->performBasicChecksOn($coupon);
75
76 26
        if ($redeemer) {
77 26
            $this->performRedeemerChecksOn($coupon, $redeemer);
78
        }
79
80 21
        event(new CouponVerified($coupon, $redeemer));
81
82 21
        return $coupon;
83
    }
84
85
    /**
86
     * Perform the stateless checks on the coupon
87
     * model. Redeemer is optional in this case.
88
     *
89
     * @param  CouponContract|null  $coupon
90
     * @param  Model|null  $redeemer
91
     *
92
     * @return CouponContract
93
     *
94
     * @throws CouponException
95
     * @throws OverQuantityException
96
     * @throws CouponExpiredException
97
     * @throws CouponDisabledException
98
     */
99 32
    public function performBasicChecksOn(?CouponContract $coupon, ?Model $redeemer = null): CouponContract
100
    {
101 32
        if (! $coupon) {
102 1
            throw new InvalidCouponException;
103
        }
104
105 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

105
        if ($coupon->/** @scrutinizer ignore-call */ isDisabled()) {
Loading history...
106 2
            event(new CouponDisabled($coupon, $redeemer));
107
108 2
            throw new CouponDisabledException;
109
        }
110
111 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

111
        if ($coupon->/** @scrutinizer ignore-call */ isExpired()) {
Loading history...
112 2
            event(new CouponExpired($coupon, $redeemer));
113
114 2
            throw new CouponExpiredException;
115
        }
116
117 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

117
        if ($coupon->/** @scrutinizer ignore-call */ isOverQuantity()) {
Loading history...
118 2
            event(new CouponIsOverQuantity($coupon, $redeemer));
119
120 2
            throw new OverQuantityException;
121
        }
122
123 27
        return $coupon;
124
    }
125
126
    /**
127
     * Perform the "Redeemer" checks on the coupon model.
128
     *
129
     * @param  CouponContract|null  $coupon
130
     * @param  Model  $redeemer
131
     *
132
     * @return CouponContract
133
     *
134
     * @throws CouponException
135
     * @throws OverLimitException
136
     * @throws NotAllowedToRedeemException
137
     */
138 27
    public function performRedeemerChecksOn(?CouponContract $coupon, Model $redeemer): CouponContract
139
    {
140 27
        if (! $coupon) {
141 1
            throw new InvalidCouponException;
142
        }
143
144 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

144
        if (! $coupon->/** @scrutinizer ignore-call */ isAllowedToRedeemBy($redeemer)) {
Loading history...
145 5
            event(new NotAllowedToRedeem($coupon, $redeemer));
146
147 5
            throw new NotAllowedToRedeemException;
148
        }
149
150 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

150
        if ($coupon->/** @scrutinizer ignore-call */ isOverLimit($redeemer)) {
Loading history...
151 3
            event(new CouponIsOverLimit($coupon, $redeemer));
152
153 3
            throw new OverLimitException;
154
        }
155
156 21
        return $coupon;
157
    }
158
159
    /**
160
     * Apply the coupon.
161
     *
162
     * @param  CouponContract  $coupon
163
     * @param  Model  $redeemer
164
     * @param  Model|null  $for
165
     *
166
     * @return CouponContract
167
     */
168 19
    public function applyCoupon(CouponContract $coupon, Model $redeemer, ?Model $for): CouponContract
169
    {
170 19
        $redeemer->coupons()->attach($coupon, [
171 19
            $this->pivot->getRedeemedTypeColumn() => $for?->getMorphClass(),
172 19
            $this->pivot->getRedeemedIdColumn()   => $for?->id,
173 19
            $this->pivot->getRedeemedAtColumn()   => now(),
174 19
            $this->pivot->getCreatedAtColumn()    => now(),
175 19
        ]);
176
177 19
        if (! is_null($coupon->{$this->model->getQuantityColumn()})) {
178 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

178
            $coupon->/** @scrutinizer ignore-call */ 
179
                     decrement($this->model->getQuantityColumn());
Loading history...
179
        }
180
181 19
        event(new CouponRedeemed($coupon, $redeemer));
182
183 19
        return $coupon;
184
    }
185
}
186