mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-27 00:52:50 +00:00
feat: fuel surcharge per lane and cargo type
This commit is contained in:
@@ -475,13 +475,16 @@ describe('RuleEngineService — fuel surcharge (per lane + cargo type)', () => {
|
||||
const fuelMods = (result: Awaited<ReturnType<RuleEngineService['evaluate']>>) =>
|
||||
result.appliedModifiers.filter((m) => m.surchargeCode === 'FUEL_SURCHARGE');
|
||||
|
||||
it('PER_LITER bills base liters × rate value once, regardless of wagons', async () => {
|
||||
it('PER_LITER collapses to one flat total (base liters × rate value), regardless of wagons', async () => {
|
||||
const result = await buildService([fuelPerLiter]).evaluate(fuelInput());
|
||||
const mods = fuelMods(result);
|
||||
expect(mods).toHaveLength(1);
|
||||
expect(mods[0].triggerValue).toBe(100);
|
||||
// Flat: the customer sees only the total, and a frozen contract snapshot
|
||||
// (also stored flat) multiplies it by quantity 1 — never by the liters.
|
||||
expect(mods[0].triggerValue).toBe(1);
|
||||
expect(mods[0].unitPriceUsd).toBe(200);
|
||||
expect(mods[0].calculatedAmount).toBe(200);
|
||||
expect(mods[0].billingUnit).toBe('PER_LITER');
|
||||
expect(mods[0].billingUnit).toBe('FLAT');
|
||||
});
|
||||
|
||||
it('PER_WAGON bills the wagons the cargo occupies', async () => {
|
||||
|
||||
@@ -648,9 +648,12 @@ export class RuleEngineService {
|
||||
/**
|
||||
* Fuel surcharge — fires when the booking's cargo type has hasFuel = true,
|
||||
* billed off the FUEL rate matching the booking's lane (trade direction +
|
||||
* origin + destination) and cargo type. PER_LITER bills baseLiters ×
|
||||
* rateValue once per booking; PER_WAGON bills the wagons the cargo occupies.
|
||||
* No matching lane rate simply bills nothing — same leniency as lashing.
|
||||
* origin + destination) and cargo type. PER_LITER collapses to one FLAT
|
||||
* amount (baseLiters × rateValue, once per booking) — the customer only ever
|
||||
* sees the total, and the frozen contract snapshot stores that same flat
|
||||
* figure so the snapshot-override math bills it exactly once. PER_WAGON
|
||||
* bills the wagons the cargo occupies. No matching lane rate simply bills
|
||||
* nothing — same leniency as lashing.
|
||||
*/
|
||||
private fuelCharges(
|
||||
input: BookingEvaluationInput,
|
||||
@@ -673,9 +676,12 @@ export class RuleEngineService {
|
||||
0,
|
||||
Number(input.bulkWagons ?? 0) || Number(input.totalWagons ?? 0),
|
||||
);
|
||||
const billedQty =
|
||||
rate.rateUnit === 'PER_LITER' ? Number(rate.baseLiters ?? 0) : wagons;
|
||||
const amount = billedQty * rateValue;
|
||||
const perLiter = rate.rateUnit === 'PER_LITER';
|
||||
const billedQty = perLiter ? 1 : wagons;
|
||||
const unitPrice = perLiter
|
||||
? Number(rate.baseLiters ?? 0) * rateValue
|
||||
: rateValue;
|
||||
const amount = billedQty * unitPrice;
|
||||
if (!(amount > 0)) return modifiers;
|
||||
modifiers.push({
|
||||
rateId: rate.id,
|
||||
@@ -683,8 +689,8 @@ export class RuleEngineService {
|
||||
triggerValue: billedQty,
|
||||
calculatedAmount: amount,
|
||||
currency: rate.currency,
|
||||
unitPriceUsd: rateValue,
|
||||
billingUnit: rate.rateUnit,
|
||||
unitPriceUsd: unitPrice,
|
||||
billingUnit: perLiter ? 'FLAT' : rate.rateUnit,
|
||||
});
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user