• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

conedevelopment / bazar / 20260538364

16 Dec 2025 07:53AM UTC coverage: 62.192% (-1.3%) from 63.48%
20260538364

Pull #235

github

web-flow
Merge e68c692b4 into 090ff8496
Pull Request #235: Coupons & Discounts

99 of 171 new or added lines in 19 files covered. (57.89%)

3 existing lines in 2 files now uncovered.

1010 of 1624 relevant lines covered (62.19%)

15.01 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

39.13
/src/Models/Coupon.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Cone\Bazar\Models;
6

7
use Cone\Bazar\Enums\CouponType;
8
use Cone\Bazar\Interfaces\Checkoutable;
9
use Cone\Bazar\Interfaces\Models\Coupon as Contract;
10
use Cone\Root\Traits\InteractsWithProxy;
11
use DateTimeInterface;
12
use Exception;
13
use Illuminate\Database\Eloquent\Attributes\Scope;
14
use Illuminate\Database\Eloquent\Builder;
15
use Illuminate\Database\Eloquent\Casts\AsArrayObject;
16
use Illuminate\Database\Eloquent\Model;
17
use Illuminate\Support\Facades\Date;
18

19
class Coupon extends Model implements Contract
20
{
21
    use InteractsWithProxy;
22

23
    /**
24
     * The model's default values for attributes.
25
     */
26
    protected $attributes = [
27
        'active' => true,
28
        'code' => null,
29
        'expires_at' => null,
30
        'rules' => '[]',
31
        'stackable' => false,
32
        'type' => CouponType::FIX,
33
        'value' => 0,
34
    ];
35

36
    /**
37
     * The attributes that are mass assignable.
38
     */
39
    protected $fillable = [
40
        'active',
41
        'code',
42
        'expires_at',
43
        'rules',
44
        'stackable',
45
        'type',
46
        'value',
47
    ];
48

49
    /**
50
     * The table associated with the model.
51
     */
52
    protected $table = 'bazar_coupons';
53

54
    /**
55
     * Get the proxied interface.
56
     */
57
    public static function getProxiedInterface(): string
58
    {
59
        return Contract::class;
1✔
60
    }
61

62
    /**
63
     * {@inheritdoc}
64
     */
65
    public function getMorphClass(): string
66
    {
NEW
67
        return static::getProxiedClass();
×
68
    }
69

70
    /**
71
     * Validate the coupon for the checkoutable model.
72
     */
73
    public function validate(Checkoutable $model): bool
74
    {
NEW
75
        return true;
×
76
    }
77

78
    /**
79
     * Calculate the discount amount for the checkoutable model.
80
     */
81
    public function calculate(Checkoutable $model): float
82
    {
NEW
83
        return 0;
×
84
    }
85

86
    /**
87
     * Apply the coupon to the checkoutable model.
88
     */
89
    public function apply(Checkoutable $model): void
90
    {
NEW
91
        if (! $this->validate($model)) {
×
NEW
92
            throw new Exception('The coupon is not valid for this checkoutable model.');
×
93
        }
94

NEW
95
        $value = $this->calculate($model);
×
96

NEW
97
        $model->coupons()->syncWithoutDetaching([
×
NEW
98
            $this->getKey() => ['value' => $value],
×
NEW
99
        ]);
×
100
    }
101

102
    /**
103
     * Scope a query to only include active coupons.
104
     */
105
    #[Scope]
106
    protected function active(Builder $query, bool $active = true): Builder
107
    {
NEW
108
        return $query->where($query->qualifyColumn('active'), $active);
×
109
    }
110

111
    /**
112
     * Scope a query to only include available coupons.
113
     */
114
    #[Scope]
115
    protected function available(Builder $query, ?DateTimeInterface $date = null): Builder
116
    {
NEW
117
        $date ??= Date::now();
×
118

NEW
119
        return $query->active()
×
NEW
120
            ->whereNull($query->qualifyColumn('expires_at'))
×
NEW
121
            ->orWhere($query->qualifyColumn('expires_at'), '>', $date);
×
122
    }
123

124
    /**
125
     * {@inheritdoc}
126
     */
127
    public function casts(): array
128
    {
129
        return [
21✔
130
            'active' => 'boolean',
21✔
131
            'expires_at' => 'datetime',
21✔
132
            'rules' => AsArrayObject::class,
21✔
133
            'stackable' => 'boolean',
21✔
134
            'type' => CouponType::class,
21✔
135
            'value' => 'float',
21✔
136
        ];
21✔
137
    }
138
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc