Files
edr-platform/apps/edr-freight-web/backoffice/src/components/trainScheduling/emptyContainerLoad.util.spec.ts
Hagernesh b4f2ec1c75 feat(train-scheduling): load returned empties onto an export train
Empties had no way onto a departure: the return record could name a train
but nothing seated it on a wagon. Export schedules now expose a loading
action that packs selected returns onto free wagons at one 40ft or two 20ft
each, enforced both in the picker and in the API (existing empties on the
schedule count against their wagon).

Adds container_size, train_schedule_id and wagon_sequence_no to
freight.empty_container_returns.
2026-08-14 09:57:50 +00:00

61 lines
2.0 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import { packEmptiesOntoWagons, wagonsNeeded, type EmptyLoadPick } from './emptyContainerLoad.util';
const pick = (id: string, containerSize: '20' | '40'): EmptyLoadPick => ({ id, containerSize });
describe('emptyContainerLoad.util', () => {
it('gives each 40ft its own wagon', () => {
const { assignments, unplaced } = packEmptiesOntoWagons(
[pick('a', '40'), pick('b', '40')],
[1, 2, 3],
);
expect(unplaced).toEqual([]);
expect(assignments.map((a) => a.wagonSequenceNo)).toEqual([1, 2]);
});
it('pairs 20ft two to a wagon, last odd one alone', () => {
const { assignments } = packEmptiesOntoWagons(
[pick('a', '20'), pick('b', '20'), pick('c', '20')],
[4, 5],
);
expect(assignments.map((a) => [a.id, a.wagonSequenceNo])).toEqual([
['a', 4],
['b', 4],
['c', 5],
]);
});
it('never mixes a 40ft and a 20ft on one wagon', () => {
const { assignments } = packEmptiesOntoWagons(
[pick('a', '20'), pick('b', '40'), pick('c', '20')],
[1, 2],
);
const bySizeOnWagon = new Map<number, string[]>();
for (const a of assignments) {
bySizeOnWagon.set(a.wagonSequenceNo, [
...(bySizeOnWagon.get(a.wagonSequenceNo) ?? []),
a.containerSize,
]);
}
for (const sizes of bySizeOnWagon.values()) {
expect(sizes.includes('40') ? sizes.length : 0).toBeLessThan(2);
expect(sizes.length).toBeLessThanOrEqual(2);
}
});
it('reports picks that ran out of wagons instead of dropping them', () => {
const { assignments, unplaced } = packEmptiesOntoWagons(
[pick('a', '40'), pick('b', '40'), pick('c', '20'), pick('d', '20')],
[7],
);
expect(assignments).toHaveLength(1);
expect(unplaced.map((p) => p.id)).toEqual(['b', 'c', 'd']);
});
it('counts wagons needed', () => {
expect(wagonsNeeded([])).toBe(0);
expect(wagonsNeeded([pick('a', '40'), pick('b', '20'), pick('c', '20')])).toBe(2);
expect(wagonsNeeded([pick('a', '20')])).toBe(1);
});
});