Passed
Push — main ( e612c6...b8afa1 )
by Michael
03:41
created

CouponService::getCoupon()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 1
rs 10
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 MichaelRubel\Couponables\Events\CouponRedeemed;
9
use MichaelRubel\Couponables\Exceptions\OverLimitException;
10
use MichaelRubel\Couponables\Exceptions\InvalidCouponException;
11
use MichaelRubel\Couponables\Exceptions\NotAllowedToRedeemException;
12
use MichaelRubel\Couponables\Exceptions\OverQuantityException;
13
use MichaelRubel\Couponables\Exceptions\CouponExpiredException;
14
use MichaelRubel\Couponables\Models\Contracts\CouponContract;
15
use MichaelRubel\Couponables\Models\Contracts\CouponPivotContract;
16
use MichaelRubel\Couponables\Services\Contracts\CouponServiceContract;
17
use MichaelRubel\EnhancedContainer\Call;
18
use MichaelRubel\EnhancedContainer\Core\CallProxy;
19
20
class CouponService implements CouponServiceContract
21
{
22
    /**
23
     * @var CallProxy
24
     */
25
    protected CallProxy $model;
26
27
    /**
28
     * @var CallProxy
29
     */
30
    protected CallProxy $pivot;
31
32
    /**
33
     * @param CouponContract      $model
34
     * @param CouponPivotContract $pivot
35
     */
36 17
    public function __construct(CouponContract $model, CouponPivotContract $pivot)
37
    {
38 17
        $this->model = call($model);
39 17
        $this->pivot = call($pivot);
40
    }
41
42
    /**
43
     * Get the coupon model by the code.
44
     *
45
     * @param string $code
46
     *
47
     * @return CouponContract
48
     * @throws InvalidCouponException
49
     */
50 17
    public function getCoupon(string $code): CouponContract
51
    {
52 17
        return $this->model
53 17
            ->where($this->model->getCodeColumn(), $code)
54 17
            ->firstOr(fn () => throw new InvalidCouponException);
55
    }
56
57
    /**
58
     * Verify if coupon is valid otherwise throw an exception.
59
     *
60
     * @param string $code
61
     * @param Model  $redeemer
62
     *
63
     * @return CouponContract
64
     * @throws OverQuantityException
65
     * @throws OverLimitException
66
     * @throws NotAllowedToRedeemException
67
     * @throws CouponExpiredException
68
     * @throws InvalidCouponException
69
     */
70 17
    public function verifyCoupon(string $code, Model $redeemer): CouponContract
71
    {
72 17
        $coupon = call($this->getCoupon($code));
73
74 15
        if ($coupon->isExpired()) {
75 1
            throw new CouponExpiredException;
76
        }
77
78 14
        if ($coupon->isOverQuantity()) {
79 1
            throw new OverQuantityException;
80
        }
81
82 14
        if ($coupon->isOverLimitFor($redeemer)) {
83 2
            throw new OverLimitException;
84
        }
85
86 14
        if ($coupon->isMorphColumnsFilled() && ! $coupon->redeemer()?->is($redeemer)) {
87 1
            throw new NotAllowedToRedeemException;
88
        }
89
90 13
        return $coupon->getInternal(Call::INSTANCE);
91
    }
92
93
    /**
94
     * Apply the coupon.
95
     *
96
     * @param CouponContract $coupon
97
     * @param Model          $redeemer
98
     *
99
     * @return CouponContract
100
     */
101 13
    public function applyCoupon(CouponContract $coupon, Model $redeemer): CouponContract
102
    {
103 13
        $redeemer->coupons()->attach($coupon->id, [
0 ignored issues
show
Bug introduced by
Accessing id on the interface MichaelRubel\Couponables...ontracts\CouponContract suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
104 13
            $this->pivot->getRedeemedAtColumn() => now(),
105
        ]);
106
107 13
        if (! is_null($coupon->{$this->model->getQuantityColumn()})) {
108 3
            $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

108
            $coupon->/** @scrutinizer ignore-call */ 
109
                     decrement($this->model->getQuantityColumn());
Loading history...
109
        }
110
111 13
        event(new CouponRedeemed($this, $coupon));
112
113 13
        return $coupon;
114
    }
115
}
116