mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 14:38:12 +00:00
Refactor wagon type handling and container wagon calculations
- Removed maxWagonsPerTrain from WagonType entity and related DTOs. - Updated containerWagonsForLines function to calculate required wagons based on container lines more accurately. - Added unit tests for containerWagonsForLines to ensure correct calculations. - Adjusted related services and scripts to reflect the removal of maxWagonsPerTrain. - Enhanced booking and contract components to use new status labels for better user experience. - Implemented validation for unique container numbers in shipment forms.
This commit is contained in:
@@ -89,18 +89,38 @@ export function containersPerWagonFromType(wagonsPerUnit: number): number {
|
||||
return Math.max(1, Math.round(1 / wpu));
|
||||
}
|
||||
|
||||
function lineWagonsRequired(line: {
|
||||
type ContainerLine = {
|
||||
quantity?: number | null;
|
||||
wagonsRequired?: number | null;
|
||||
containerType?: { wagonsPerUnit?: number | null; sizeFt?: number | null } | null;
|
||||
}): number {
|
||||
};
|
||||
|
||||
/**
|
||||
* RAW (un-ceiled) wagon fraction one container line occupies: qty × wagonsPerUnit
|
||||
* (40ft = 1, 20ft = 0.5). Two 20ft = 1.0, three 20ft = 1.5. Kept fractional so
|
||||
* the BOOKING total is ceiled once — ceiling per line over-counts a booking that
|
||||
* splits its 20ft units across several lines (3×20 + 3×20 = 3 wagons, not 4).
|
||||
*/
|
||||
function lineWagonsRaw(line: ContainerLine): number {
|
||||
const qty = Number(line.quantity ?? 0);
|
||||
if (qty <= 0) return 0;
|
||||
const wpu = Number(line.containerType?.wagonsPerUnit);
|
||||
if (Number.isFinite(wpu) && wpu > 0) {
|
||||
return Math.ceil(qty * wpu);
|
||||
return qty * wpu;
|
||||
}
|
||||
return Math.max(1, Math.ceil(Number(line.wagonsRequired ?? 1)));
|
||||
// No wagonsPerUnit on the type: fall back to the line's stored fraction, else
|
||||
// treat the whole line as one wagon.
|
||||
const stored = Number(line.wagonsRequired);
|
||||
return Number.isFinite(stored) && stored > 0 ? stored : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whole wagons a set of container lines needs: ceil the summed RAW fraction so a
|
||||
* half-full 20ft wagon rounds up ONCE at the booking level. Empty set → 0.
|
||||
*/
|
||||
export function containerWagonsForLines(lines: ContainerLine[]): number {
|
||||
const raw = lines.reduce((sum, line) => sum + lineWagonsRaw(line), 0);
|
||||
return raw > 0 ? Math.ceil(raw) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,15 +130,16 @@ export function buildContainerWagonPlan(
|
||||
bookings: Booking[],
|
||||
wagonType: WagonType,
|
||||
): WagonPlanSlot[] {
|
||||
// Whole wagons PER BOOKING (ceil each booking's total TEU once — a 20ft unit
|
||||
// can share a wagon with another 20ft of the SAME booking, never across
|
||||
// bookings), then sum. Ceiling per line instead would over-count a booking
|
||||
// that splits its 20ft units across several lines.
|
||||
const totalSlots = bookings.reduce((sum, booking) => {
|
||||
const lineSlots = (booking.bookingContainers ?? []).reduce(
|
||||
(lineSum, line) => lineSum + lineWagonsRequired(line),
|
||||
0,
|
||||
);
|
||||
return sum + Math.max(lineSlots, 1);
|
||||
const bookingSlots = containerWagonsForLines(booking.bookingContainers ?? []);
|
||||
return sum + Math.max(bookingSlots, 1);
|
||||
}, 0);
|
||||
|
||||
const slots = Math.max(1, Math.ceil(totalSlots));
|
||||
const slots = Math.max(1, totalSlots);
|
||||
const basePlan: WagonPlanSlot[] = Array.from({ length: slots }, (_, index) => ({
|
||||
sequenceNo: index + 1,
|
||||
wagonTypeId: wagonType.id,
|
||||
@@ -424,7 +445,7 @@ export function validateBulkWagonSlotWeights(wagonPlan: WagonPlanSlot[]): string
|
||||
|
||||
export function validateTrainLimits(
|
||||
wagonPlan: WagonPlanSlot[],
|
||||
wagonType: WagonType,
|
||||
wagonType: Pick<WagonType, 'lengthMeters'>,
|
||||
limits?: TrainLimitConfig,
|
||||
): string[] {
|
||||
const violations: string[] = [];
|
||||
@@ -478,7 +499,7 @@ export function validateMixedTrainLimits(
|
||||
|
||||
return validateTrainLimits(
|
||||
wagonPlan,
|
||||
{ maxWagonsPerTrain } as WagonType,
|
||||
{ lengthMeters: minWagonLength },
|
||||
{ ...limits, maxWagonsPerTrain },
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user