mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 16:28:12 +00:00
- Added functionality to cancel contracts, allowing users to provide a reason for cancellation. - Updated contract statuses to include SUSPENDED and changed CLOSED to COMPLETED. - Enhanced the UI to reflect the new cancellation option and updated messaging for contract statuses. - Refactored contract booking actions to accommodate changes in booking logic for ONE_TIME and GENERAL contracts. - Removed clearance document management from the contract detail page, as it is now handled per booking. - Introduced a SQL script to reset bookings and train schedules for development purposes.
71 lines
2.9 KiB
TypeScript
71 lines
2.9 KiB
TypeScript
import { WagonStockLedger } from './wagon-stock-ledger.util';
|
|
|
|
const WHOLE = { fromEdge: 0, toEdge: 1 };
|
|
|
|
describe('WagonStockLedger', () => {
|
|
it('reports the wagons of a booking\'s OWN types, not the train total', () => {
|
|
// The reported case: 20 free wagons on the train, but only 16 of them NW5.
|
|
const ledger = new WagonStockLedger(
|
|
new Map([
|
|
['nw5', 16],
|
|
['pw2', 4],
|
|
]),
|
|
1,
|
|
);
|
|
expect(ledger.availableFor(['nw5'], WHOLE)).toBe(16);
|
|
expect(ledger.availableFor(['pw2'], WHOLE)).toBe(4);
|
|
// A cargo type mapped to both may ride either, so they add up.
|
|
expect(ledger.availableFor(['nw5', 'pw2'], WHOLE)).toBe(20);
|
|
// Duplicates must not double-count.
|
|
expect(ledger.availableFor(['nw5', 'nw5'], WHOLE)).toBe(16);
|
|
// An unconfigured type has no stock.
|
|
expect(ledger.availableFor(['unknown'], WHOLE)).toBe(0);
|
|
});
|
|
|
|
it('consumes what it can and reports the shortfall', () => {
|
|
const ledger = new WagonStockLedger(new Map([['nw5', 16]]), 1);
|
|
// A 20-wagon booking can only take 16 — the caller splits on that number.
|
|
expect(ledger.consume(['nw5'], 20, WHOLE)).toBe(16);
|
|
expect(ledger.availableFor(['nw5'], WHOLE)).toBe(0);
|
|
expect(ledger.consume(['nw5'], 1, WHOLE)).toBe(0);
|
|
});
|
|
|
|
it('drains the deepest stock first across candidate types', () => {
|
|
const ledger = new WagonStockLedger(
|
|
new Map([
|
|
['nw5', 10],
|
|
['nw7', 3],
|
|
]),
|
|
1,
|
|
);
|
|
expect(ledger.consume(['nw5', 'nw7'], 12, WHOLE)).toBe(12);
|
|
// 10 from NW5 then 2 from NW7 — one NW7 left.
|
|
expect(ledger.availableFor(['nw7'], WHOLE)).toBe(1);
|
|
expect(ledger.availableFor(['nw5'], WHOLE)).toBe(0);
|
|
});
|
|
|
|
it('frees stock past an alight yard — disjoint legs never compete', () => {
|
|
// Three stops (A→B→C) = two edges. An intercity booking riding A→B must
|
|
// not consume the wagon on B→C.
|
|
const ledger = new WagonStockLedger(new Map([['nw5', 5]]), 2);
|
|
const firstLeg = { fromEdge: 0, toEdge: 1 };
|
|
const secondLeg = { fromEdge: 1, toEdge: 2 };
|
|
|
|
ledger.consume(['nw5'], 5, firstLeg);
|
|
expect(ledger.availableFor(['nw5'], firstLeg)).toBe(0);
|
|
expect(ledger.availableFor(['nw5'], secondLeg)).toBe(5);
|
|
|
|
// A whole-route booking sees the busiest edge it crosses, so it is blocked.
|
|
expect(ledger.availableFor(['nw5'], { fromEdge: 0, toEdge: 2 })).toBe(0);
|
|
});
|
|
|
|
it('counts the busiest edge within a leg, not the sum of edges', () => {
|
|
const ledger = new WagonStockLedger(new Map([['nw5', 10]]), 3);
|
|
ledger.consume(['nw5'], 4, { fromEdge: 0, toEdge: 1 });
|
|
ledger.consume(['nw5'], 6, { fromEdge: 1, toEdge: 2 });
|
|
// Edge 0 uses 4, edge 1 uses 6 — a booking over both needs 10 free at once.
|
|
expect(ledger.availableFor(['nw5'], { fromEdge: 0, toEdge: 2 })).toBe(4);
|
|
expect(ledger.availableFor(['nw5'], { fromEdge: 2, toEdge: 3 })).toBe(10);
|
|
});
|
|
});
|