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

conedevelopment / bazar / 20248285521

15 Dec 2025 09:37PM UTC coverage: 61.163% (-2.3%) from 63.48%
20248285521

Pull #235

github

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

58 of 144 new or added lines in 18 files covered. (40.28%)

14 existing lines in 3 files now uncovered.

989 of 1617 relevant lines covered (61.16%)

14.83 hits per line

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

97.56
/src/Models/Cart.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Cone\Bazar\Models;
6

7
use Cone\Bazar\Bazar;
8
use Cone\Bazar\Database\Factories\CartFactory;
9
use Cone\Bazar\Enums\Currency;
10
use Cone\Bazar\Exceptions\CartException;
11
use Cone\Bazar\Interfaces\Models\Cart as Contract;
12
use Cone\Bazar\Traits\Addressable;
13
use Cone\Bazar\Traits\AsOrder;
14
use Cone\Root\Traits\InteractsWithProxy;
15
use Illuminate\Database\Eloquent\Builder;
16
use Illuminate\Database\Eloquent\Factories\HasFactory;
17
use Illuminate\Database\Eloquent\Model;
18
use Illuminate\Database\Eloquent\Relations\BelongsTo;
19
use Illuminate\Database\Eloquent\Relations\MorphOne;
20
use Illuminate\Support\Facades\Date;
21

22
class Cart extends Model implements Contract
23
{
24
    use Addressable;
25
    use AsOrder;
26
    use HasFactory;
27
    use InteractsWithProxy;
28

29
    /**
30
     * The attributes that should have default values.
31
     *
32
     * @var array<string, mixed>
33
     */
34
    protected $attributes = [
35
        'currency' => null,
36
        'locked' => false,
37
    ];
38

39
    /**
40
     * The attributes that are mass assignable.
41
     *
42
     * @var list<string>
43
     */
44
    protected $fillable = [
45
        'currency',
46
        'locked',
47
    ];
48

49
    /**
50
     * The table associated with the model.
51
     *
52
     * @var string
53
     */
54
    protected $table = 'bazar_carts';
55

56
    /**
57
     * The "booted" method of the model.
58
     */
59
    protected static function booted(): void
60
    {
61
        static::creating(static function (self $cart): void {
42✔
62
            $cart->setAttribute('currency', $cart->currency ?: Bazar::getCurrency());
42✔
63
        });
42✔
64
    }
65

66
    /**
67
     * Get the proxied interface.
68
     */
69
    public static function getProxiedInterface(): string
70
    {
71
        return Contract::class;
1✔
72
    }
73

74
    /**
75
     * Create a new factory instance for the model.
76
     */
77
    protected static function newFactory(): CartFactory
78
    {
79
        return CartFactory::new();
28✔
80
    }
81

82
    /**
83
     * {@inheritdoc}
84
     */
85
    public function getMorphClass(): string
86
    {
87
        return static::getProxiedClass();
41✔
88
    }
89

90
    /**
91
     * Get the attributes that should be cast.
92
     *
93
     * @return array<string, string>
94
     */
95
    public function casts(): array
96
    {
97
        return [
42✔
98
            'currency' => Currency::class,
42✔
99
            'locked' => 'bool',
42✔
100
        ];
42✔
101
    }
102

103
    /**
104
     * Get the order for the cart.
105
     *
106
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo<\Cone\Bazar\Models\Order, \Cone\Bazar\Models\Cart>
107
     */
108
    public function order(): BelongsTo
109
    {
110
        return $this->belongsTo(Order::getProxiedClass())
2✔
111
            ->withDefault(function (Order $order): Order {
2✔
112
                return $order->fill($this->toArray());
2✔
113
            });
2✔
114
    }
115

116
    /**
117
     * Get the address for the model.
118
     */
119
    public function address(): MorphOne
120
    {
121
        return $this->morphOne(Address::getProxiedClass(), 'addressable')
10✔
122
            ->withDefault(function (Address $address): Address {
10✔
123
                return $address->fill($this->user?->address?->toArray() ?: []);
3✔
124
            });
10✔
125
    }
126

127
    /**
128
     * Lock the cart.
129
     */
130
    public function lock(): void
131
    {
132
        if (! $this->locked) {
1✔
133
            $this->setAttribute('locked', true)->save();
1✔
134
        }
135
    }
136

137
    /**
138
     * Unlock the cart.
139
     */
140
    public function unlock(): void
141
    {
142
        if ($this->locked) {
1✔
143
            $this->setAttribute('locked', false)->save();
1✔
144
        }
145
    }
146

147
    /**
148
     * Scope a query to only include the locked carts.
149
     */
150
    public function scopeLocked(Builder $query): Builder
151
    {
152
        return $query->where($query->qualifyColumn('locked'), true);
1✔
153
    }
154

155
    /**
156
     * Scope a query to only include the unlocked carts.
157
     */
158
    public function scopeUnlocked(Builder $query): Builder
159
    {
160
        return $query->where($query->qualifyColumn('locked'), false);
1✔
161
    }
162

163
    /**
164
     * Scope a query to only include the expired carts.
165
     */
166
    public function scopeExpired(Builder $query): Builder
167
    {
168
        return $query->whereNull($query->qualifyColumn('user_id'))
2✔
169
            ->where($query->qualifyColumn('updated_at'), '<', Date::now()->subDays(3));
2✔
170
    }
171

172
    /**
173
     * Convert the cart to a new order.
174
     */
175
    public function toOrder(): Order
176
    {
177
        $this->getLineItems()->each(function (Item $item): void {
1✔
178
            if (! $item->buyable->buyable($this->order)) {
1✔
UNCOV
179
                throw new CartException(sprintf('Unable to add [%s] item to the order.', get_class($item->buyable)));
×
180
            }
181
        });
1✔
182

183
        $this->order->user()->associate($this->user)->save();
1✔
184

185
        if ($this->order_id !== $this->order->getKey()) {
1✔
186
            $this->order()->associate($this->order)->save();
1✔
187
        }
188

189
        $this->order->items()->delete();
1✔
190
        $this->order->items()->createMany($this->items->toArray());
1✔
191

192
        $this->order->address->fill($this->address->toArray())->save();
1✔
193

194
        if ($this->order->needsShipping()) {
1✔
195
            $this->order->shipping->fill($this->shipping->toArray())->save();
1✔
196
            $this->order->shipping->address->fill($this->shipping->address->toArray())->save();
1✔
197
        }
198

199
        $this->order->calculateTax();
1✔
200

201
        return $this->order;
1✔
202
    }
203
}
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