mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 07:38:10 +00:00
Implement clearance-first booking flow and completion process for customs contracts
This commit is contained in:
@@ -700,6 +700,16 @@ describe('BookingBatchService — PAID reconcile', () => {
|
||||
bookingsRepository.findBatchPoolByCorridorDay
|
||||
.mockResolvedValueOnce([waiting])
|
||||
.mockResolvedValue([]);
|
||||
// expire()'s paid-guard and reserve()'s idempotency guard both re-read the
|
||||
// booking fresh — answer with the matching row, not the paidBooking default
|
||||
// (which would make the guard rescue-allocate the lapsed reservation).
|
||||
const byId: Record<string, Booking> = { lapsed, waiting };
|
||||
dataSource
|
||||
.getRepository()
|
||||
.findOne.mockImplementation(
|
||||
async (opts: { where?: { id?: string } }) =>
|
||||
byId[opts?.where?.id ?? ''] ?? null,
|
||||
);
|
||||
|
||||
await service.settleDueReservations(trainId);
|
||||
|
||||
@@ -725,6 +735,14 @@ describe('BookingBatchService — PAID reconcile', () => {
|
||||
return Promise.resolve(reads === 1 ? [lapsed] : []);
|
||||
});
|
||||
bookingsRepository.findBatchPoolByCorridorDay.mockResolvedValue([]);
|
||||
// expire()'s paid-guard re-reads the booking fresh — answer with the
|
||||
// (unpaid) lapsed row, not the paidBooking default.
|
||||
dataSource
|
||||
.getRepository()
|
||||
.findOne.mockImplementation(
|
||||
async (opts: { where?: { id?: string } }) =>
|
||||
opts?.where?.id === 'lapsed' ? lapsed : null,
|
||||
);
|
||||
|
||||
await Promise.all([
|
||||
service.settleDueReservations(trainId),
|
||||
@@ -733,6 +751,37 @@ describe('BookingBatchService — PAID reconcile', () => {
|
||||
|
||||
expect(notifier.expired).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('never expires a reservation whose payment landed — allocates it instead', async () => {
|
||||
const latePaid = booking('late-paid', 50, {
|
||||
status: 'SELECTED_FOR_BATCH',
|
||||
paymentDeadline: new Date(Date.now() - 60_000),
|
||||
});
|
||||
bookingsRepository.findReservedForSchedule
|
||||
.mockResolvedValueOnce([latePaid])
|
||||
.mockResolvedValue([]);
|
||||
bookingsRepository.findBatchPoolByCorridorDay.mockResolvedValue([]);
|
||||
// The payment webhook flipped paymentStatus between the settle's list
|
||||
// read and expire()'s fresh re-read — the deadline had already passed.
|
||||
dataSource
|
||||
.getRepository()
|
||||
.findOne.mockImplementation(
|
||||
async (opts: { where?: { id?: string } }) =>
|
||||
opts?.where?.id === 'late-paid'
|
||||
? { ...latePaid, paymentStatus: 'PAID' }
|
||||
: null,
|
||||
);
|
||||
|
||||
await service.settleDueReservations(trainId);
|
||||
|
||||
// Money was taken → the booking boards. Never expired.
|
||||
expect(notifier.expired).not.toHaveBeenCalled();
|
||||
expect(notifier.secured).toHaveBeenCalledTimes(1);
|
||||
expect(trainScheduleBookingsRepository.createMany).toHaveBeenCalledWith(
|
||||
[{ trainScheduleId: trainId, bookingId: 'late-paid' }],
|
||||
expect.anything(),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user