mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
81 lines
2.8 KiB
TypeScript
81 lines
2.8 KiB
TypeScript
import type { RateAppliesTo, RateTrigger, RateUnit } from './rate.entity';
|
|
|
|
/**
|
|
* Which rate units make sense for a given rate shape. The weighting basis is
|
|
* driven by the *type* of thing being billed — a container leg bills per
|
|
* container, bulk freight per ton, an intercity move can be per-km, a
|
|
* cancellation is a flat/per-invoice fee, and overweight is always per excess
|
|
* ton. This keeps the rate table dynamic yet non-conflicting: the admin can
|
|
* only pick a unit the pricing engine knows how to apply.
|
|
*
|
|
* Returned lists are ordered with the most natural/default unit first.
|
|
*/
|
|
export function allowedRateUnits(input: {
|
|
appliesTo: RateAppliesTo;
|
|
trigger: RateTrigger;
|
|
}): RateUnit[] {
|
|
const { appliesTo, trigger } = input;
|
|
|
|
// Surcharges (Applies to = Other) are governed by their trigger.
|
|
if (appliesTo === 'OTHER') {
|
|
switch (trigger) {
|
|
case 'OVERWEIGHT':
|
|
// Overweight always bills the excess tonnage — per ton, nothing else.
|
|
return ['PER_TON'];
|
|
case 'REEFER':
|
|
case 'HAZARDOUS':
|
|
// Scale with the freight shape: per container for boxes, per ton for bulk.
|
|
return ['PER_CONTAINER', 'PER_TON'];
|
|
case 'DEMURRAGE':
|
|
return ['PER_CONTAINER', 'PER_TON'];
|
|
case 'WITH_RETURN':
|
|
// Container-only empty-return service — bills per returned container.
|
|
return ['PER_CONTAINER', 'FLAT'];
|
|
case 'CANCELLATION':
|
|
return ['FLAT', 'PER_INVOICE'];
|
|
case 'CUSTOMS_CLEARANCE':
|
|
// Flat per clearance (ONE_TIME contract) / per shipment request (GENERAL).
|
|
return ['FLAT'];
|
|
case 'LASHING':
|
|
// Flat cargo-securing fee, billed once per booking.
|
|
return ['FLAT'];
|
|
case 'CONSOLIDATION':
|
|
return ['PER_CONTAINER', 'FLAT'];
|
|
case 'SHIPPING_LINE':
|
|
case 'PIL_EXTRA_FEE':
|
|
return ['PER_CONTAINER', 'FLAT'];
|
|
default:
|
|
return ['FLAT', 'PER_TON', 'PER_CONTAINER'];
|
|
}
|
|
}
|
|
|
|
// Base freight + first/last mile scale with the cargo type.
|
|
switch (appliesTo) {
|
|
case 'CONTAINER':
|
|
return ['PER_CONTAINER', 'PER_WAGON'];
|
|
case 'BULK':
|
|
return ['PER_TON', 'PER_WAGON'];
|
|
case 'INTERCITY':
|
|
return ['PER_CONTAINER', 'PER_TON', 'PER_WAGON', 'PER_KM'];
|
|
case 'FIRST_MILE':
|
|
case 'LAST_MILE':
|
|
return ['PER_CONTAINER', 'PER_TON', 'PER_KM', 'FLAT'];
|
|
default:
|
|
return ['FLAT'];
|
|
}
|
|
}
|
|
|
|
/** The default (first / most natural) unit for a rate shape. */
|
|
export function defaultRateUnit(input: { appliesTo: RateAppliesTo; trigger: RateTrigger }): RateUnit {
|
|
return allowedRateUnits(input)[0];
|
|
}
|
|
|
|
/** True when `unit` is a valid weighting basis for the given rate shape. */
|
|
export function isRateUnitAllowed(input: {
|
|
appliesTo: RateAppliesTo;
|
|
trigger: RateTrigger;
|
|
unit: RateUnit;
|
|
}): boolean {
|
|
return allowedRateUnits(input).includes(input.unit);
|
|
}
|