Functional Weave
Code in TypeScript

logistics.freight-rate@1.0.1

README.md

2,545 bytes · view raw

# logistics.freight-rate

Prices a consignment on a carrier's tariff: find the zone's weight break that
covers the chargeable weight on the ship date, price it, check whether a
heavier break would be cheaper, and add the fuel surcharge in force that day.

## The tariff is an argument

Freight rates are private contracts between a shipper and a carrier, so the
tariff is passed in (`rates`), not shipped as registry data. Each row still
carries `validFrom` and `validTo`, so one table can hold last year's rates and
this year's and the ship date picks between them. Carriers publish their fuel
surcharge as a percentage that changes weekly or monthly; that is the second
table. The figures in the vectors are illustrative, not any carrier's.

## Pricing one break

```
ratedGrams = chargeableGrams rounded up to stepGrams
freight    = base + ratedGrams x perKgMinor / 1000   (rounded half up to the minor unit)
freight    = max(freight, minimum)
```

That one shape covers the common tariffs: a flat price per weight band
(`perKgMinor` 0), a per-kilogram rate by weight break with a minimum charge
(air freight's M / N / +45 / +100 ...), and a base plus a per-kilogram
element. The break is chosen on the chargeable weight as given, before the
break's own rounding; bands must not overlap.

## A heavier break can be cheaper

Per-kilogram rates fall as the weight rises, so 40 kg at 4.50/kg (180.00)
costs more than 45 kg at 3.80/kg (171.00). Carriers charge the lower figure
by pricing the consignment at the first weight of the heavier break, and so
does this: every heavier break of the zone in force on the date is tried at
its `fromGrams`, and the cheapest wins (on a tie, the lighter rated weight).
`ratedGrams` and `breakFromGrams` say what happened. Pricing only the break
the weight falls in is the mistake this vector catches.

## Fuel surcharge

`fuelSurcharge = freight x basisPoints / 10000`, rounded half up, applied to
the freight charge only. Of the rows in force on the ship date, the one with
the latest `validFrom` wins, so a new week's figure can be appended without
closing the previous row. An empty table means no surcharge; a non-empty
table with no row for the date is an error, because it almost always means
the table has not been updated.

## Errors

No break for the zone and date covering the weight, two breaks covering it,
a weight below 1 g, a step below 1, a negative rate, and mixed currencies are
all errors, each naming what it found.

1.0.1 fixes Python accepting non-ASCII digits in shipDate; adds tests.