Passed
Push — main ( 805f12...d8598c )
by Michael
03:39
created

CouponService   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 81
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 23
c 2
b 0
f 0
dl 0
loc 81
ccs 24
cts 24
cp 1
rs 10
wmc 9

3 Methods

Rating   Name   Duplication   Size   Complexity  
A verifyCoupon() 0 25 6
A applyCoupon() 0 11 2
A __construct() 0 4 1
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 13
    public function __construct(CouponContract $model, CouponPivotContract $pivot)
37
    {
38 13
        $this->model = call($model);
39 13
        $this->pivot = call($pivot);
40 13
    }
41
42
    /**
43
     * Verify if coupon is valid otherwise throw an exception.
44
     *
45
     * @param string $code
46
     * @param Model  $redeemer
47
     *
48
     * @return CouponContract
49
     * @throws OverQuantityException
50
     * @throws OverLimitException
51
     * @throws NotAllowedToRedeemException
52
     * @throws CouponExpiredException
53
     * @throws InvalidCouponException
54
     */
55 13
    public function verifyCoupon(string $code, Model $redeemer): CouponContract
56
    {
57 13
        $coupon = $this->model
58 13
            ->where($this->model->getCodeColumn(), $code)
59 13
            ->firstOr(fn () => throw new InvalidCouponException);
60
61 12
        $coupon = call($coupon);
62
63 12
        if ($coupon->isExpired()) {
64 1
            throw new CouponExpiredException;
65
        }
66
67 11
        if ($coupon->isOverQuantity()) {
68 1
            throw new OverQuantityException;
69
        }
70
71 11
        if ($coupon->isOverLimitFor($redeemer)) {
72 2
            throw new OverLimitException;
73
        }
74
75 11
        if ($coupon->isMorphColumnsFilled() && ! $coupon->redeemer()?->is($redeemer)) {
76 1
            throw new NotAllowedToRedeemException;
77
        }
78
79 10
        return $coupon->getInternal(Call::INSTANCE);
80
    }
81
82
    /**
83
     * Apply the coupon.
84
     *
85
     * @param Model $coupon
86
     * @param Model $redeemer
87
     *
88
     * @return void
89
     */
90 10
    public function applyCoupon(Model $coupon, Model $redeemer): void
91
    {
92 10
        $redeemer->coupons()->attach($coupon->id, [
93 10
            $this->pivot->getRedeemedAtColumn() => now(),
94
        ]);
95
96 10
        if (! is_null($coupon->{$this->model->getQuantityColumn()})) {
97 3
            $coupon->decrement($this->model->getQuantityColumn());
98
        }
99
100 10
        event(new CouponRedeemed($this, $coupon));
101 10
    }
102
}
103