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

conedevelopment / bazar / 20213722262

14 Dec 2025 08:30PM UTC coverage: 63.031% (-0.4%) from 63.48%
20213722262

Pull #235

github

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

0 of 3 new or added lines in 2 files covered. (0.0%)

53 existing lines in 11 files now uncovered.

965 of 1531 relevant lines covered (63.03%)

15.16 hits per line

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

97.3
/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\Exceptions\CartException;
10
use Cone\Bazar\Interfaces\Models\Cart as Contract;
11
use Cone\Bazar\Traits\Addressable;
12
use Cone\Bazar\Traits\InteractsWithItems;
13
use Cone\Root\Traits\InteractsWithProxy;
14
use Illuminate\Database\Eloquent\Builder;
15
use Illuminate\Database\Eloquent\Factories\HasFactory;
16
use Illuminate\Database\Eloquent\Model;
17
use Illuminate\Database\Eloquent\Relations\BelongsTo;
18
use Illuminate\Database\Eloquent\Relations\MorphOne;
19
use Illuminate\Support\Facades\Date;
20

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

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

38
    /**
39
     * The attributes that should be cast to native types.
40
     *
41
     * @var array<string, string>
42
     */
43
    protected $casts = [
44
        'locked' => 'bool',
45
    ];
46

47
    /**
48
     * The attributes that are mass assignable.
49
     *
50
     * @var list<string>
51
     */
52
    protected $fillable = [
53
        'currency',
54
        'locked',
55
    ];
56

57
    /**
58
     * The table associated with the model.
59
     *
60
     * @var string
61
     */
62
    protected $table = 'bazar_carts';
63

64
    /**
65
     * The "booted" method of the model.
66
     */
67
    protected static function booted(): void
68
    {
69
        static::creating(static function (self $cart): void {
42✔
70
            $cart->setAttribute('currency', $cart->currency ?: Bazar::getCurrency());
42✔
71
        });
42✔
72
    }
73

74
    /**
75
     * Get the proxied interface.
76
     */
77
    public static function getProxiedInterface(): string
78
    {
79
        return Contract::class;
1✔
80
    }
81

82
    /**
83
     * Create a new factory instance for the model.
84
     */
85
    protected static function newFactory(): CartFactory
86
    {
87
        return CartFactory::new();
28✔
88
    }
89

90
    /**
91
     * {@inheritdoc}
92
     */
93
    public function getMorphClass(): string
94
    {
95
        return static::getProxiedClass();
41✔
96
    }
97

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

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

122
    /**
123
     * Lock the cart.
124
     */
125
    public function lock(): void
126
    {
127
        if (! $this->locked) {
1✔
128
            $this->setAttribute('locked', true)->save();
1✔
129
        }
130
    }
131

132
    /**
133
     * Unlock the cart.
134
     */
135
    public function unlock(): void
136
    {
137
        if ($this->locked) {
1✔
138
            $this->setAttribute('locked', false)->save();
1✔
139
        }
140
    }
141

142
    /**
143
     * Scope a query to only include the locked carts.
144
     */
145
    public function scopeLocked(Builder $query): Builder
146
    {
147
        return $query->where($query->qualifyColumn('locked'), true);
1✔
148
    }
149

150
    /**
151
     * Scope a query to only include the unlocked carts.
152
     */
153
    public function scopeUnlocked(Builder $query): Builder
154
    {
155
        return $query->where($query->qualifyColumn('locked'), false);
1✔
156
    }
157

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

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

178
        $this->order->user()->associate($this->user)->save();
1✔
179

180
        if ($this->order_id !== $this->order->getKey()) {
1✔
181
            $this->order()->associate($this->order)->save();
1✔
182
        }
183

184
        $this->order->items()->delete();
1✔
185
        $this->order->items()->createMany($this->items->toArray());
1✔
186

187
        $this->order->address->fill($this->address->toArray())->save();
1✔
188

189
        if ($this->order->needsShipping()) {
1✔
190
            $this->order->shipping->fill($this->shipping->toArray())->save();
1✔
191
            $this->order->shipping->address->fill($this->shipping->address->toArray())->save();
1✔
192
        }
193

194
        $this->order->calculateTax();
1✔
195

196
        return $this->order;
1✔
197
    }
198
}
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