add lashing surcharge for cargo types with hasLashing flag

add lashing surcharge for cargo types with hasLashing flag
This commit is contained in:
Marshal
2026-07-17 23:25:53 +00:00
parent 6467173c76
commit 3a1a08b1e1
59 changed files with 1919 additions and 140 deletions

View File

@@ -2,6 +2,7 @@ import { BadRequestException, Injectable, NotFoundException } from "@nestjs/comm
import { randomUUID } from "node:crypto";
import { ContractRendererService } from "../../contracts/contract-renderer.service";
import { RateSchedule } from "../../contracts/contract-rate-schedule.builder";
import { getTemplateMeta } from "../../contracts/contract-template.registry";
import {
ContractDynamicTemplateView,
@@ -177,17 +178,9 @@ export class ContractTemplatesService {
const isBulk = code.endsWith("_BULK");
const now = new Date();
const unitRates = isBulk
? [
{ label: "Rail transport — per metric ton", unitPrice: 59.4, unit: "ton", currency: "USD" },
{ label: "Origin handling and documentation", unitPrice: 18, unit: "ton", currency: "USD" },
{ label: "Lashing material (when provided by EDR)", unitPrice: 150, unit: "unit", currency: "USD" },
]
: [
{ label: "Rail transport — 40ft container", unitPrice: 1916, unit: "container", currency: "USD" },
{ label: "Rail transport — 2 × 20ft containers", unitPrice: 1944, unit: "container", currency: "USD" },
{ label: "Excess tonnage surcharge", unitPrice: 10, unit: "ton", currency: "USD" },
];
// Representative rate schedule so the admin preview shows the live-rate
// table shape. Real contracts populate this from freight.rates (LIVE).
const rateSchedule = this.mockRateSchedule(code, isBulk);
return {
bookingId: "00000000-0000-0000-0000-000000000000",
@@ -239,13 +232,16 @@ export class ContractTemplatesService {
lastMileDeliveryAddress: "—",
},
pricing: {
displayMode: "UNIT_RATES",
unitRates,
lineItems: [],
surcharges: [],
totalAmount: 0,
currency: "USD",
equipmentReturn: isBulk ? "—" : "With empty return",
originLabel: isBulk ? "Nagad Railway Station" : "SGTD Freight Station",
destinationLabel: "Galaan Multipurpose Port (GMP)",
containerLines: [],
} as unknown as ContractViewModel["pricing"],
rateSchedule,
signatures: [],
canSignCustomer: false,
canSignStaff: false,
@@ -256,6 +252,43 @@ export class ContractTemplatesService {
};
}
/** Static, representative rate schedule for the admin preview only. */
private mockRateSchedule(code: ContractTemplateCode, isBulk: boolean): RateSchedule {
const dir = code.startsWith("IMPORT")
? "import"
: code.startsWith("EXPORT")
? "export"
: "domestic";
const lane =
dir === "export"
? "Galaan Multipurpose Port → SGTD"
: dir === "domestic"
? "Mojo Dry Port → Dire Dawa"
: "Negad → Mojo Dry Port";
const freightLanes = isBulk
? [
{ route: lane, cargo: "Wheat", currency: "USD", amount: "100", unit: "per wagon" },
]
: [
{ route: lane, cargo: "40ft GP", currency: "USD", amount: "200", unit: "per container" },
{ route: lane, cargo: "20ft GP", currency: "USD", amount: "180", unit: "per container" },
];
return {
freightLanes,
additionalServices: [
{ route: "First-mile pickup by truck", cargo: "—", currency: "USD", amount: "50", unit: "per container" },
{ route: "Last-mile delivery by truck", cargo: "—", currency: "USD", amount: "50", unit: "per container" },
],
surcharges: [
{ route: "Customs clearance service", cargo: "—", currency: "USD", amount: "120", unit: "flat" },
],
isEmpty: false,
currencyLabel: "USD",
};
}
private assertCode(code: string): ContractTemplateCode {
const upper = code?.toUpperCase() as ContractTemplateCode;
if (!CONTRACT_TEMPLATE_CODES.includes(upper)) {