diff --git a/apps/edr-freight-api/src/modules/train-scheduling/booking-batch.service.ts b/apps/edr-freight-api/src/modules/train-scheduling/booking-batch.service.ts index 41c8023f0..a5957a285 100644 --- a/apps/edr-freight-api/src/modules/train-scheduling/booking-batch.service.ts +++ b/apps/edr-freight-api/src/modules/train-scheduling/booking-batch.service.ts @@ -1286,6 +1286,31 @@ export class BookingBatchService implements OnModuleInit { (s.scheduleBookings ?? []).map((l) => l.bookingId), ); const bookings = await this.bookingsRepository.findAllBySchedule(s.id); + // Under day-level pooling a booking is only pinned to a schedule by + // reserve() — until then its train_schedule_id is NULL and the query above + // misses it. Merge in the corridor-day candidates so staff see the whole + // waiting pool (the 7 that lost the batch), not just the winners. These are + // display-only candidates: they are excluded from the capacity meters below. + const pinnedIds = new Set(bookings.map((b) => b.id)); + if (s.scheduledDepartureDate) { + try { + const stops = await this.stopsForSchedule(s); + const candidates = + await this.bookingsRepository.findBatchPoolByCorridorDay( + stops, + eatDay(s.scheduledDepartureDate), + ); + for (const b of candidates) { + if (!pinnedIds.has(b.id)) bookings.push(b); + } + } catch (err) { + // The board must still render the pinned bookings. + this.logger.warn( + `Corridor-day candidate merge failed for schedule ${s.id}: ` + + `${(err as Error).message}`, + ); + } + } let allocationPreview: Awaited< ReturnType @@ -1437,7 +1462,13 @@ export class BookingBatchService implements OnModuleInit { maxTrainLengthMeters: Number(loco.maxTrainLengthMeters), } : null, - capacity: this.computeBoardCapacity(items, loco, s.maxWagons ?? null), + // Capacity holds come from bookings actually pinned to this train — + // unpinned day-pool candidates are shown in the lists but hold nothing. + capacity: this.computeBoardCapacity( + items.filter((i) => pinnedIds.has(i.id)), + loco, + s.maxWagons ?? null, + ), counts: { allocated: items.filter((i) => i.state === "ALLOCATED").length, selectedForBatch: items.filter((i) => i.state === "SELECTED_FOR_BATCH")