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

conedevelopment / bazar / 20312410163

17 Dec 2025 05:58PM UTC coverage: 64.395% (+0.9%) from 63.48%
20312410163

push

github

web-flow
Merge pull request #235 from conedevelopment/coupons

Coupons & Discounts

204 of 260 new or added lines in 23 files covered. (78.46%)

8 existing lines in 1 file now uncovered.

1096 of 1702 relevant lines covered (64.39%)

18.27 hits per line

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

91.67
/src/Models/Item.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Cone\Bazar\Models;
6

7
use Cone\Bazar\Database\Factories\ItemFactory;
8
use Cone\Bazar\Interfaces\Buyable;
9
use Cone\Bazar\Interfaces\Models\Item as Contract;
10
use Cone\Bazar\Traits\InteractsWithTaxes;
11
use Cone\Root\Traits\InteractsWithProxy;
12
use Illuminate\Database\Eloquent\Casts\Attribute;
13
use Illuminate\Database\Eloquent\Concerns\HasUuids;
14
use Illuminate\Database\Eloquent\Factories\HasFactory;
15
use Illuminate\Database\Eloquent\Model;
16
use Illuminate\Database\Eloquent\Relations\MorphTo;
17

18
class Item extends Model implements Contract
19
{
20
    use HasFactory;
21
    use HasUuids;
22
    use InteractsWithProxy;
23
    use InteractsWithTaxes;
24

25
    /**
26
     * The accessors to append to the model's array form.
27
     *
28
     * @var list<string>
29
     */
30
    protected $appends = [
31
        'subtotal',
32
        'total',
33
    ];
34

35
    /**
36
     * The attributes that should have default values.
37
     *
38
     * @var array<string, mixed>
39
     */
40
    protected $attributes = [
41
        'price' => 0,
42
        'properties' => '[]',
43
        'quantity' => 1,
44
    ];
45

46
    /**
47
     * The attributes that are mass assignable.
48
     *
49
     * @var list<string>
50
     */
51
    protected $fillable = [
52
        'buyable_id',
53
        'buyable_type',
54
        'name',
55
        'price',
56
        'properties',
57
        'quantity',
58
    ];
59

60
    /**
61
     * The attributes that should be hidden for arrays.
62
     *
63
     * @var list<string>
64
     */
65
    protected $hidden = [
66
        'checkoutable',
67
    ];
68

69
    /**
70
     * The table associated with the model.
71
     *
72
     * @var string
73
     */
74
    protected $table = 'bazar_items';
75

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

84
    /**
85
     * Create a new factory instance for the model.
86
     */
87
    protected static function newFactory(): ItemFactory
88
    {
89
        return ItemFactory::new();
5✔
90
    }
91

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

100
    /**
101
     * {@inheritdoc}
102
     */
103
    public function casts(): array
104
    {
105
        return [
46✔
106
            'price' => 'float',
46✔
107
            'properties' => 'array',
46✔
108
            'quantity' => 'float',
46✔
109
        ];
46✔
110
    }
111

112
    /**
113
     * Get the buyable model for the item.
114
     */
115
    public function buyable(): MorphTo
116
    {
117
        return $this->morphTo();
35✔
118
    }
119

120
    /**
121
     * Get the checkoutable model for the item.
122
     */
123
    public function checkoutable(): MorphTo
124
    {
125
        return $this->morphTo()->withDefault();
19✔
126
    }
127

128
    /**
129
     * Get the formatted price attribute.
130
     *
131
     * @return \Illuminate\Database\Eloquent\Casts\Attribute<string, never>
132
     */
133
    protected function formattedPrice(): Attribute
134
    {
135
        return new Attribute(
2✔
136
            get: fn (): string => $this->getFormattedPrice(),
2✔
137
        );
2✔
138
    }
139

140
    /**
141
     * Get the formatted gross price attribute.
142
     *
143
     * @return \Illuminate\Database\Eloquent\Casts\Attribute<string, never>
144
     */
145
    protected function formattedGrossPrice(): Attribute
146
    {
147
        return new Attribute(
1✔
148
            get: fn (): string => $this->getFormattedGrossPrice(),
1✔
149
        );
1✔
150
    }
151

152
    /**
153
     * Get the total attribute.
154
     *
155
     * @return \Illuminate\Database\Eloquent\Casts\Attribute<float, never>
156
     */
157
    protected function total(): Attribute
158
    {
159
        return new Attribute(
18✔
160
            get: fn (): float => $this->getTotal()
18✔
161
        );
18✔
162
    }
163

164
    /**
165
     * Get the formatted total attribute.
166
     *
167
     * @return \Illuminate\Database\Eloquent\Casts\Attribute<string, never>
168
     */
169
    protected function formattedTotal(): Attribute
170
    {
171
        return new Attribute(
2✔
172
            get: fn (): string => $this->getFormattedTotal()
2✔
173
        );
2✔
174
    }
175

176
    /**
177
     * Get the subtotal attribute.
178
     *
179
     * @return \Illuminate\Database\Eloquent\Casts\Attribute<float, never>
180
     */
181
    protected function subtotal(): Attribute
182
    {
183
        return new Attribute(
18✔
184
            get: fn (): float => $this->getSubtotal()
18✔
185
        );
18✔
186
    }
187

188
    /**
189
     * Get the formatted subtotal attribute.
190
     *
191
     * @return \Illuminate\Database\Eloquent\Casts\Attribute<string, never>
192
     */
193
    protected function formattedSubtotal(): Attribute
194
    {
195
        return new Attribute(
2✔
196
            get: fn (): string => $this->getFormattedSubtotal()
2✔
197
        );
2✔
198
    }
199

200
    /**
201
     * Get the name.
202
     */
203
    public function getName(): string
204
    {
205
        return $this->name;
×
206
    }
207

208
    /**
209
     * Get the price.
210
     */
211
    public function getPrice(): float
212
    {
213
        return $this->price;
40✔
214
    }
215

216
    /**
217
     * Get the formatted price.
218
     */
219
    public function getFormattedPrice(): string
220
    {
221
        return $this->checkoutable->getCurrency()->format($this->getPrice());
1✔
222
    }
223

224
    /**
225
     * Get the gross price.
226
     */
227
    public function getGrossPrice(): float
228
    {
229
        return $this->getPrice() + $this->getTax();
23✔
230
    }
231

232
    /**
233
     * Get the formatted price.
234
     */
235
    public function getFormattedGrossPrice(): string
236
    {
NEW
237
        return $this->checkoutable->getCurrency()->format($this->getGrossPrice());
×
238
    }
239

240
    /**
241
     * Get the total.
242
     */
243
    public function getTotal(): float
244
    {
245
        return $this->getGrossPrice() * $this->getQuantity();
23✔
246
    }
247

248
    /**
249
     * Get the formatted total.
250
     */
251
    public function getFormattedTotal(): string
252
    {
253
        return $this->checkoutable->getCurrency()->format($this->getTotal());
1✔
254
    }
255

256
    /**
257
     * Get the subtotal.
258
     */
259
    public function getSubtotal(): float
260
    {
261
        return $this->getPrice() * $this->getQuantity();
39✔
262
    }
263

264
    /**
265
     * Get the formatted subtotal.
266
     */
267
    public function getFormattedSubtotal(): string
268
    {
269
        return $this->checkoutable->getCurrency()->format($this->getSubtotal());
1✔
270
    }
271

272
    /**
273
     * Get the tax base.
274
     */
275
    public function getTaxBase(): float
276
    {
277
        return $this->price;
8✔
278
    }
279

280
    /**
281
     * Get the formatted tax.
282
     */
283
    public function getFormattedTax(): string
284
    {
NEW
285
        return $this->checkoutable->getCurrency()->format($this->getTax());
×
286
    }
287

288
    /**
289
     * Get the formatted tax.
290
     */
291
    public function getFormattedTaxTotal(): string
292
    {
NEW
293
        return $this->checkoutable->getCurrency()->format($this->getTaxTotal());
×
294
    }
295

296
    /**
297
     * Get the quantity.
298
     */
299
    public function getQuantity(): float
300
    {
301
        return $this->quantity;
40✔
302
    }
303

304
    /**
305
     * Determine if the item is a line item.
306
     */
307
    public function isLineItem(): bool
308
    {
309
        return $this->buyable instanceof Buyable;
38✔
310
    }
311

312
    /**
313
     * Determine if the item is a fee.
314
     */
315
    public function isFee(): bool
316
    {
317
        return ! $this->isLineItem();
21✔
318
    }
319

320
    /**
321
     * Calculate the taxes.
322
     */
323
    public function calculateTaxes(): float
324
    {
325
        $taxes = $this->buyable->getApplicableTaxRates()->mapWithKeys(function (TaxRate $taxRate): array {
15✔
326
            return [$taxRate->getKey() => ['value' => $taxRate->calculate($this)]];
8✔
327
        });
15✔
328

329
        $this->taxes()->sync($taxes);
15✔
330

331
        return $this->getTaxTotal();
15✔
332
    }
333
}
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