mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-08 13:38:20 +00:00
fix issue and add consolidation
This commit is contained in:
@@ -200,16 +200,14 @@ export function buildBulkWagonPlan(
|
||||
);
|
||||
const cappedTonSlots = cappedTonSlotsByBooking.reduce((sum, n) => sum + n, 0);
|
||||
|
||||
const totalWeight = roundTons(
|
||||
bookings.reduce(
|
||||
(sum, b, i) =>
|
||||
itemSlotsByBooking[i] > 0 || cappedTonSlotsByBooking[i] > 0
|
||||
? sum
|
||||
: sum + Number(b.cargoTotalWeightVgm ?? 0),
|
||||
0,
|
||||
),
|
||||
);
|
||||
const tonSlots = totalWeight > 0 ? Math.ceil(totalWeight / capacity) : 0;
|
||||
// One bulk booking per wagon — bookings never pool tonnage on a shared
|
||||
// wagon, so each uncapped booking sizes its own wagons (ceil per booking,
|
||||
// not over the pooled total).
|
||||
const tonSlots = bookings.reduce((sum, b, i) => {
|
||||
if (itemSlotsByBooking[i] > 0 || cappedTonSlotsByBooking[i] > 0) return sum;
|
||||
const weight = roundTons(Number(b.cargoTotalWeightVgm ?? 0));
|
||||
return weight > 0 ? sum + Math.ceil(weight / capacity) : sum;
|
||||
}, 0);
|
||||
const slots = Math.max(1, tonSlots + itemSlots + cappedTonSlots);
|
||||
|
||||
const basePlan: WagonPlanSlot[] = Array.from({ length: slots }, (_, index) => ({
|
||||
@@ -374,13 +372,12 @@ function allocateBookingsToSlots(
|
||||
|
||||
if (booking.remainingWeightTons <= 0) {
|
||||
bookingIndex += 1;
|
||||
} else if (allocatedWeightTons >= takeCap) {
|
||||
// The cap stopped this wagon short of its rating and the booking has
|
||||
// more to load. The leftover room is NOT free: `buildBulkWagonPlan`
|
||||
// already reserved a wagon for the rest, so backfilling another booking
|
||||
// here would double-book the consist. Close the wagon.
|
||||
break;
|
||||
}
|
||||
// One bulk booking per wagon: a wagon carrying bulk takes nothing else —
|
||||
// never a second booking's cargo. `buildBulkWagonPlan` sized the slots
|
||||
// per booking, so leftover room on this wagon is not free capacity.
|
||||
// Close the wagon after its single allocation.
|
||||
break;
|
||||
}
|
||||
|
||||
return { ...slot, assignedWeightTons, allocations };
|
||||
@@ -504,6 +501,26 @@ export function sumWagonsRequired(booking: Booking, wagonPlan?: WagonPlanSlot[])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* One wagon carries one kind of cargo: a slot with a BULK allocation holds
|
||||
* nothing else — no container beside it and no second bulk booking. Container
|
||||
* allocations may still share a wagon with each other (TEU rules apply).
|
||||
*/
|
||||
export function validateWagonCargoExclusivity(wagonPlan: WagonPlanSlot[]): string[] {
|
||||
const violations: string[] = [];
|
||||
for (const slot of wagonPlan) {
|
||||
const hasBulk = slot.allocations.some(
|
||||
(a) => a.loadType === AllocationLoadType.Bulk,
|
||||
);
|
||||
if (hasBulk && slot.allocations.length > 1) {
|
||||
violations.push(
|
||||
`Wagon #${slot.sequenceNo} mixes bulk with other cargo — a wagon carrying bulk takes that one load only`,
|
||||
);
|
||||
}
|
||||
}
|
||||
return violations;
|
||||
}
|
||||
|
||||
export function validateBulkWagonSlotWeights(wagonPlan: WagonPlanSlot[]): string[] {
|
||||
const violations: string[] = [];
|
||||
for (const slot of wagonPlan.filter((s) => s.slotLoadType === 'BULK')) {
|
||||
@@ -547,6 +564,7 @@ export function validateTrainLimits(
|
||||
);
|
||||
|
||||
violations.push(...validateBulkWagonSlotWeights(wagonPlan));
|
||||
violations.push(...validateWagonCargoExclusivity(wagonPlan));
|
||||
|
||||
return violations;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user