Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
5 / 5
CRAP
100.00% covered (success)
100.00%
1 / 1
ShippingService
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
5 / 5
9
100.00% covered (success)
100.00%
1 / 1
 zones
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 hasZones
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 findRate
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 resolveCharge
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
3
 codAllowed
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3namespace App\Services\Shipping;
4
5use App\Models\ShippingRate;
6use App\Models\ShippingZone;
7use Illuminate\Support\Collection;
8
9/**
10 * Real zone × rate shipping. A store that never sets up a zone keeps using
11 * the flat "Inside Dhaka / Outside Dhaka" list from Settings → Checkout
12 * (see OrderService::resolveShippingCharge()) — zones are entirely opt-in.
13 */
14class ShippingService
15{
16    /** Active zones with their rates, in display order. */
17    public function zones(): Collection
18    {
19        return ShippingZone::query()
20            ->where('is_active', true)
21            ->with('rates')
22            ->orderBy('sort_order')
23            ->orderBy('name')
24            ->get()
25            ->filter(fn (ShippingZone $z) => $z->rates->isNotEmpty())
26            ->values();
27    }
28
29    public function hasZones(): bool
30    {
31        return $this->zones()->isNotEmpty();
32    }
33
34    public function findRate(int $rateId): ?ShippingRate
35    {
36        return ShippingRate::query()->with('zone')->find($rateId);
37    }
38
39    /** The delivery charge for a chosen rate at this order subtotal. */
40    public function resolveCharge(?int $rateId, float $subtotal): float
41    {
42        $rate = $rateId ? $this->findRate($rateId) : null;
43
44        return $rate ? $rate->chargeFor($subtotal) : 0.0;
45    }
46
47    /** Is COD allowed for the zone this rate belongs to? */
48    public function codAllowed(?int $rateId): bool
49    {
50        $rate = $rateId ? $this->findRate($rateId) : null;
51
52        return $rate ? (bool) $rate->zone?->cod_allowed : true;
53    }
54}