enhance train scheduling logic to exclude cancelled trains and refine window filtering

This commit is contained in:
Marshal
2026-07-15 07:07:10 +00:00
parent b102a31fc1
commit 9be7f356f0

View File

@@ -435,7 +435,12 @@ export class TrainSchedulingService {
.where('s.originStationId = :originStationId', { originStationId })
.andWhere('s.destinationStationId = :destinationStationId', { destinationStationId })
.andWhere('s.scheduledDepartureDate >= :dayStart', { dayStart })
.andWhere('s.scheduledDepartureDate < :nextDayStart', { nextDayStart });
.andWhere('s.scheduledDepartureDate < :nextDayStart', { nextDayStart })
// A cancelled train is not a sibling: cancel retires its window as DONE,
// and a newborn anchoring to it would inherit that dead window verbatim.
.andWhere('s.status != :cancelledStatus', {
cancelledStatus: TrainScheduleStatusEnum.Cancelled,
});
if (excludeScheduleId) {
qb.andWhere('s.id != :excludeScheduleId', { excludeScheduleId });
}
@@ -471,7 +476,12 @@ export class TrainSchedulingService {
departure,
);
if (siblings.length === 0) return null;
const withWindow = siblings.filter((s) => s.windowOpensAt != null);
// A DONE window is retired (the day's last cycle already ran) — anchoring
// to it would hand the newborn a dead window no tick ever advances. With no
// live or pending sibling left, fall back to fresh times (return null).
const withWindow = siblings.filter(
(s) => s.windowOpensAt != null && s.windowPhase !== 'DONE',
);
if (withWindow.length === 0) return null;
// A group whose window is live (some sibling has moved past PRE_WINDOW but is