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

CouponService::applyCoupon()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 5
c 1
b 0
f 0
nc 2
nop 2
dl 0
loc 11
ccs 6
cts 6
cp 1
crap 2
rs 10
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