A lot of shipping code hardcodes the volumetric divisor. Someone writes / 5000 next to the dimension calculation, it matches the spreadsheet, tests pass, and the number quietly becomes part of the application.
That is a commercial parameter pretending to be a constant. It varies by carrier, by lane, by service level, and by product category, and it decides what your customer is billed. Treating it as physics is how you end up quoting one price and invoicing another.
The actual calculation
Chargeable weight is the greater of two numbers:
actual = scale weight of the packed parcel
volumetric = (L x W x H in cm) / divisor
chargeable = max(actual, volumetric)
The divisor is the interesting term. A 50x40x30 cm box is 60,000 cm³. At divisor 5000 that bills as 12 kg. At 6000 it bills as 10 kg. Same parcel, same fuel, roughly a 17 percent difference, decided entirely by a number the carrier chose.
Add the usual modifiers and it stops being one formula. Some carriers round up to the next half kilo. Some impose a minimum chargeable weight. Some apply a different divisor above a threshold. Some bill irregular parcels on a girth rule instead.
Model it as data
Lane = Struct.new(
:code, :divisor, :min_chargeable_kg,
:rounding_step_kg, :girth_rule, keyword_init: true
)
LANES = [
Lane.new(code: "express_us", divisor: 5000, min_chargeable_kg: 0.5, rounding_step_kg: 0.5),
Lane.new(code: "eco_packet_us", divisor: 8000, min_chargeable_kg: 0.05, rounding_step_kg: 0.05),
Lane.new(code: "air_uk", divisor: 6000, min_chargeable_kg: 0.5, rounding_step_kg: 0.5),
].index_by(&:code)
Then the function is one place, and it is testable against the table rather than against a magic number:
def chargeable_weight(parcel, lane)
volumetric = parcel.l_cm * parcel.w_cm * parcel.h_cm / BigDecimal(lane.divisor)
raw = [parcel.actual_kg, volumetric].max
raw = lane.min_chargeable_kg if raw < lane.min_chargeable_kg
round_up_to(raw, lane.rounding_step_kg)
end
Three things that will bite you
Use decimal arithmetic. Binary floating point turns 0.1 + 0.2 into a billing discrepancy, and a discrepancy across thousands of parcels becomes a reconciliation you have to explain to a customer.
Store the divisor with the quote, not just the result. When a buyer asks why they were charged for 12 kg on a 600 g item, "because the lane used a 5000 divisor and here is the box" is an answer. "I do not know" is a refund.
Record which box you measured. Dimensions should be the packed, carton-side dimensions captured at pick time, not the catalogue dimensions entered by whoever listed the SKU. This is the single largest source of surprise billing in cross-border parcels, and it is a data capture problem, not a math problem.
Where it belongs in the system
We run this for the small-parcel and one-piece fulfillment lanes FulfillNexa by SBT (fulfillnexa.com) operates out of its three Chinese warehouses, 3,000 m² in Shenzhen, 13,000 m² in Suzhou and 8,000 m² in Dongguan, and the shape that survived contact with real rate sheets is: carrier tables loaded as versioned data, one pure calculation function, and every quote persisted with the divisor and the measured dimensions that produced it.
The versioning matters more than it sounds. Rate cards move, and a quote from last week has to reproduce exactly, which means the calculation needs to know which version of the table it was made against.
If your shipping code has a bare 5000 in it, it is not a formula. It is a business decision you inherited from a file, and it is being applied to every parcel you touch.
Top comments (0)