Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

CookieMonster's avatar

how to compute the shipping rates given weight and postcode?

I have a form that looks like below:

https://ibb.co/BwTLF6R

I select weight(in kg) and also the postcode pickup and postcode delivery. When I proceed, I should be able to generate a quotation of shipping fees based on all available couriers. It should give the expected outcome something like below(the prices are hardcoded for now):

https://ibb.co/J3Mshg1

My issue is coming up with a formula to calculate the actual rates based on the locations(by postcode). I have the fixed rates for each courier. Each courier have two rates, one rate for the west side of the country and another rate for east side(more pricey than west side) of the country. To show a sample like below:

Courier A:

weight(kg).        west region.       east region
   1                   3.50             5.60
   2                   4.20             7.40 
   3                   7.10             12.30
......

This applies for the other couriers rate that I have as well. So far I came up with three tables, Rates, Couriers and Locations.

I populate these tables with the data like below:

Rates Table: https://ibb.co/RCV2qKP

Couriers Table:

https://ibb.co/BtfdZLT

Locations Table:

https://ibb.co/M2M4CpC

The relationship I have between these three is as follows:

Rate.php:


class Rate extends Model
{
    protected $guarded =[];

    // belong to a courier
    public function courier(){
       return $this->belongsTo(Courier::class);
    }

    // belongs to a location(penisular or sabah/sarawak)
    public function locations(){
       return $this->belongsTo(Location::class);
    }


}

Courier.php:

class Courier extends Model
{
    protected $fillable = ['name'];

    // One courier has many rates
    public function rates(){
        return $this->hasMany(Rate::class);
    }

    // One courier has locations and rates
    public function locations(){
        return $this->hasManyThrough(Location::class,Rate::class);
    }
}

Location.php:

class Location extends Model
{
    protected $fillable = [
        'name'
    ];
}

So in my controller when the form is submitted, it is currently looking like this:

    //Show quotation order
        public function quotation(Request $request){
            
            $validated = $request->validate([
                'parcel_weight' => 'required',
                'parcel_size' => 'required',
                'postcode_pickup' => 'required|postal_code:MY|exists:postcodes,postcode',
                'postcode_delivery' => 'required|postal_code:MY|exists:postcodes,postcode'
            ]);
    
            // compute the quotation rate for each courier based on the inputs
            $shippingCosts = Courier::with('rates.location')->get()
    ->mapWithKeys(function($courier) use ($destination, $weight) {
        return [ 
            $courier->name => $courier->rates
                                        ->filter(fn($rate) => $rate->location->name == $destination)
                                        ->sort('weight')
                                        ->first(fn($rate) => $rate->weigth >= $weight)->cost
        ];
    });

$shippingCosts == [
    'Courier A' => 3.00,
    'Courier B' => 3.00,
    'Courier C' => 3.00,
];

    
            return view('orders.quotation');
        }
    }

I am kinda stuck on this part as how to work out a way to compute the shipping rates since each postcode correspond to either west region or east region with their own respectively rates.

One way I thought of that might work is that I already have a postcodes table with approx 50 thousands record for each postcode tied to each state. So I can cross check the postcode given with the table to get the state abbreviation. Since there is 13 states with 11(west region) and 2(east region), I could perhaps assign the location ID to it and then query the rates table given the location_id as well as the weight and that will return all 10 couriers(rate) which can then be shown in the quotation. Although, I don't know if it is optimal way of doing so.

0 likes
0 replies

Please or to participate in this conversation.