Implement clearance-first booking flow and completion process for customs contracts

This commit is contained in:
Marshal
2026-07-10 21:51:59 +00:00
parent 9ed473c309
commit 1121e9ce82
19 changed files with 482 additions and 106 deletions

View File

@@ -19,6 +19,7 @@ describe('BookingWindowService — window state machine', () => {
isScheduleFull: jest.Mock;
hasLiveReservations: jest.Mock;
refreshWindowStatus: jest.Mock;
expireLeftoverDayPool: jest.Mock;
};
let trainSchedulesRepository: { findById: jest.Mock; findAll: jest.Mock };
let trainSchedulingService: { finalizeSchedule: jest.Mock; getWindowConfig: jest.Mock };
@@ -73,6 +74,7 @@ describe('BookingWindowService — window state machine', () => {
// No reservation is mid-pay-window by default, so the cycle concludes.
hasLiveReservations: jest.fn().mockResolvedValue(false),
refreshWindowStatus: jest.fn().mockResolvedValue(undefined),
expireLeftoverDayPool: jest.fn().mockResolvedValue(0),
};
trainSchedulesRepository = {
findById: jest.fn().mockResolvedValue(null),
@@ -186,6 +188,8 @@ describe('BookingWindowService — window state machine', () => {
expect(batch.setWindow).toHaveBeenCalledWith(scheduleId, 'FULL');
expect(s.windowPhase).toBe('DONE');
expect(trainSchedulingService.finalizeSchedule).toHaveBeenCalledWith(scheduleId);
// The day's leftover waiting list is swept once this train is done.
expect(batch.expireLeftoverDayPool).toHaveBeenCalledWith(scheduleId);
});
it('conclude: NOT full + a cycle fits before departure → REOPEN (back to PRE_WINDOW)', async () => {
@@ -210,6 +214,8 @@ describe('BookingWindowService — window state machine', () => {
});
await concludeCycle(s, new Date('2026-07-01T02:30:04.000Z'));
expect(s.windowPhase).toBe('DONE');
// No further train can run for this day → leftover waiting list is swept.
expect(batch.expireLeftoverDayPool).toHaveBeenCalledWith(scheduleId);
});
it('no transition fires before its deadline (idempotent tick)', async () => {