feat(contracts): lazily expire lapsed contracts and price fuel surcharge

This commit is contained in:
Marshal
2026-08-12 11:23:04 +00:00
parent a02d24806b
commit 3dbda745dd
5 changed files with 112 additions and 17 deletions

View File

@@ -11,7 +11,14 @@ import { Contract } from './entities/contract.entity';
export interface ContractUnitRateLineItem {
code: string;
label: string;
unit: 'per_container' | 'per_wagon' | 'per_ton' | 'per_item' | 'per_km' | 'flat';
unit:
| 'per_container'
| 'per_wagon'
| 'per_ton'
| 'per_item'
| 'per_km'
| 'per_liter'
| 'flat';
unitPrice: number;
containerSize?: string | null;
conditionalOn?: string | null;
@@ -44,6 +51,8 @@ function toContractUnit(rateUnit: string): ContractUnitRateLineItem['unit'] {
return 'per_wagon';
case 'PER_CONTAINER':
return 'per_container';
case 'PER_LITER':
return 'per_liter';
default:
return 'flat';
}
@@ -276,6 +285,39 @@ export class ContractPricingService {
}
}
// Fuel surcharge — shown when the contract's commodity incurs fuel
// (cargoType.hasFuel), sold per lane + commodity. Billed at booking on the
// frozen/live rate (per wagon × wagons, or per liter × base liters, once);
// this line freezes the agreed unit price.
{
const scope = (contract.cargoScope ?? []).find((c) => c.cargoTypeId);
if (scope?.cargoType?.hasFuel && route) {
const fuel = liveRates.find(
(r) =>
r.trigger === 'FUEL' &&
r.currency === 'USD' &&
r.tradeDirection === contract.tradeDirection &&
r.originYardId === route.originYardId &&
r.destinationYardId === route.destinationYardId &&
r.cargoTypeId === scope.cargoTypeId,
);
if (fuel && Number(fuel.rateValue) > 0) {
const base = Number(fuel.baseLiters ?? 0);
lineItems.push({
code: 'FUEL_SURCHARGE',
label:
fuel.rateUnit === 'PER_LITER'
? `Fuel surcharge (${scope.cargoType.cargoTypeName}, ${base} liters)`
: `Fuel surcharge (${scope.cargoType.cargoTypeName})`,
unit: toContractUnit(fuel.rateUnit),
unitPrice: convert(Number(fuel.rateValue)),
cargoTypeCode: scope.cargoType.code ?? null,
conditionalOn: 'has_fuel',
});
}
}
}
// Empty-container return service — container contracts only, toggled on the
// contract like hazard/reefer. Billed at booking per WITH_RETURN container.
if (