fix issue

This commit is contained in:
Marshal
2026-08-22 01:23:50 +00:00
parent b6c1efa043
commit 1ab2cfdb3b
13 changed files with 874 additions and 109 deletions

View File

@@ -1,6 +1,7 @@
import {
autoFillPlacements,
findMissingContainerNumberIssues,
occupiedTeuPerEdgeBySlot,
type ContainerUnitForPlacement,
} from './container-placement.util';
@@ -27,14 +28,15 @@ describe('container-placement.util', () => {
];
it('auto-fills placements across slots', () => {
const placements = autoFillPlacements(units, [1, 2]);
const { placements, overflow } = autoFillPlacements(units, [1, 2]);
expect(placements).toHaveLength(2);
expect(overflow).toHaveLength(0);
expect(placements[0].sequenceNo).toBe(1);
expect(placements[1].sequenceNo).toBe(2);
});
it('reports missing container numbers only when placement is empty', () => {
const placements = autoFillPlacements(units, [1, 2]);
const { placements } = autoFillPlacements(units, [1, 2]);
const issues = findMissingContainerNumberIssues(units, placements);
expect(issues).toHaveLength(0);
expect(placements[1].containerNumber).toMatch(/^TBD-/);
@@ -53,7 +55,84 @@ describe('container-placement.util', () => {
containerNumber: null,
},
];
const placements = autoFillPlacements(single, [1]);
const { placements } = autoFillPlacements(single, [1]);
expect(placements[0].containerNumber).toBe('TBD-BK-2026-000033-1');
});
const ft40 = (
bookingId: string,
i: number,
leg?: { from: number; to: number },
): ContainerUnitForPlacement => ({
bookingId,
bookingReference: bookingId,
bookingContainerId: `${bookingId}-line`,
unitIndex: i,
label: `${bookingId} · ${i + 1} · 40GP`,
teuSlots: 2,
sizeFt: 40,
containerNumber: `CNT${bookingId}${i}`,
leg,
});
it('never clamps overflow onto the last slot — returns it instead', () => {
// 3 × 40ft, 2 slots. The old walk piled unit 3 onto slot #2 and let the
// validator reject it once per container ("Wagon #42…", the reported bug).
const three = [ft40('A', 0), ft40('A', 1), ft40('A', 2)];
const { placements, overflow } = autoFillPlacements(three, [1, 2]);
expect(placements).toHaveLength(2);
expect(overflow).toHaveLength(1);
expect(placements.every((p) => p.sequenceNo === 1 || p.sequenceNo === 2)).toBe(true);
});
it('leg-aware: disjoint-leg 40fts share one wagon (the staging case)', () => {
// 2 slots riding the whole 2-edge route. Leg-blind fill fits only two of
// these four 40fts; per-edge TEU fits all four — two per wagon, one per leg.
const slots = [
{ sequenceNo: 1, from: 0, to: 2 },
{ sequenceNo: 2, from: 0, to: 2 },
];
const four = [
ft40('LEG1', 0, { from: 0, to: 1 }),
ft40('LEG1', 1, { from: 0, to: 1 }),
ft40('LEG2', 0, { from: 1, to: 2 }),
ft40('LEG2', 1, { from: 1, to: 2 }),
];
const { placements, overflow } = autoFillPlacements(four, slots, new Map(), 2);
expect(overflow).toHaveLength(0);
expect(placements).toHaveLength(4);
});
it('same-leg 40fts still never share a wagon', () => {
const slots = [{ sequenceNo: 1, from: 0, to: 2 }];
const two = [ft40('X', 0, { from: 0, to: 1 }), ft40('X', 1, { from: 0, to: 1 })];
const { placements, overflow } = autoFillPlacements(two, slots, new Map(), 2);
expect(placements).toHaveLength(1);
expect(overflow).toHaveLength(1);
});
it('respects per-edge occupied TEU from caller-provided placements', () => {
const slots = [{ sequenceNo: 1, from: 0, to: 2 }];
const provided = [{ bookingContainerId: 'P-line', unitIndex: 0, sequenceNo: 1 }];
const providedUnit = ft40('P', 0, { from: 0, to: 1 });
const occupied = occupiedTeuPerEdgeBySlot(provided, [providedUnit], 2);
// Edge 0 is full on slot 1; an edge-0 unit overflows, an edge-1 unit fits.
const edge0 = autoFillPlacements([ft40('Q', 0, { from: 0, to: 1 })], slots, occupied, 2);
expect(edge0.overflow).toHaveLength(1);
const edge1 = autoFillPlacements([ft40('Q', 0, { from: 1, to: 2 })], slots, occupied, 2);
expect(edge1.overflow).toHaveLength(0);
expect(edge1.placements[0].sequenceNo).toBe(1);
});
it('a unit never lands on a slot that does not ride its leg', () => {
const slots = [{ sequenceNo: 1, from: 0, to: 1 }]; // alights at stop 1
const { placements, overflow } = autoFillPlacements(
[ft40('Y', 0, { from: 1, to: 2 })],
slots,
new Map(),
2,
);
expect(placements).toHaveLength(0);
expect(overflow).toHaveLength(1);
});
});