Add booking window management and locomotive scheduling features

- Implemented migration to release stuck assigned locomotives.
- Added schedule window phases to train schedules.
- Created booking batch offers table for partial capacity bookings.
- Developed BookingSplitService to handle partial booking offers and splits.
- Introduced BookingWindowService to manage booking window lifecycle and transitions.
- Added BookingBatchOffer entity to represent offers made during booking splits.
- Enhanced locomotive options with warnings for scheduling.
- Created UpcomingWindowsSection component to display upcoming booking windows.
This commit is contained in:
Marshal
2026-07-03 03:36:06 +00:00
parent 18c158fb61
commit 56de90892d
41 changed files with 2480 additions and 124 deletions

View File

@@ -35,6 +35,7 @@ describe('BookingBatchService — PAID reconcile', () => {
let trainSchedulingService: {
tryAutoWagonAllocation: jest.Mock;
getBookableSchedules: jest.Mock;
getWindowConfig: jest.Mock;
};
let dataSource: {
getRepository: jest.Mock;
@@ -77,6 +78,15 @@ describe('BookingBatchService — PAID reconcile', () => {
violations: [],
}),
getBookableSchedules: jest.fn().mockResolvedValue([]),
getWindowConfig: jest.fn().mockResolvedValue({
importWindowLeadDays: 3,
exportBookingLeadHours: 24,
windowOpenHour: 8,
windowDurationHours: 3,
docReviewMinutes: 30,
paymentWindowMinutes: 60,
reopenDelayMinutes: 90,
}),
};
const bookingRepo = {
@@ -187,17 +197,24 @@ describe('BookingBatchService — PAID reconcile', () => {
}) as unknown as Booking;
beforeEach(() => {
// Two OPEN trains on the same route + day, train A earlier than train B.
trainSchedulingService.getBookableSchedules.mockResolvedValue([
// Two OPEN legacy trains on the same route + day, train A earlier than train B.
// fillRouteDay now selects fillable schedules straight from the repository.
trainSchedulesRepository.findAll.mockResolvedValue([
{
id: trainA,
scheduleDate: '2026-06-20T06:00:00.000Z',
originStationId: originYardId,
destinationStationId: destinationYardId,
scheduledDepartureDate: new Date('2026-06-20T06:00:00.000Z'),
bookingWindowStatus: 'OPEN',
windowPhase: null,
},
{
id: trainB,
scheduleDate: '2026-06-20T09:00:00.000Z',
originStationId: originYardId,
destinationStationId: destinationYardId,
scheduledDepartureDate: new Date('2026-06-20T09:00:00.000Z'),
bookingWindowStatus: 'OPEN',
windowPhase: null,
},
]);
trainSchedulesRepository.findByIdWithFullGraph.mockImplementation((id: string) =>