mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-09 10:58:14 +00:00
Commiting stop based booking
This commit is contained in:
@@ -10,7 +10,7 @@ import { CurrencyService } from "../currency/currency.service";
|
||||
import { FareEngineService } from "../fare-engine/fare-engine.service";
|
||||
import { SegmentsService } from "../segments/segments.service";
|
||||
import { resolveCurrencyFromNationality } from "../fare-engine/fare-engine.dto";
|
||||
import { Currency } from "@prisma/client";
|
||||
import { Currency, Prisma } from "@prisma/client";
|
||||
|
||||
const POINTS_TO_MINOR = 10;
|
||||
|
||||
@@ -220,12 +220,18 @@ export class SearchService {
|
||||
const totalPassengers = adultCount + (childCount ?? 0);
|
||||
const NEEDED = 3;
|
||||
|
||||
const baseWhere = {
|
||||
status: "SCHEDULED",
|
||||
// Include BOARDING alongside SCHEDULED: BOARDING is just an operational display status the
|
||||
// schedule-level cron sets on a fixed 30-min-before-departure timer (see tasks.service.ts) —
|
||||
// it does NOT mean booking is closed. The actual booking cutoff is per-stop and configurable
|
||||
// (RouteStop/Route.checkinMinutesBefore), enforced below by buildScheduleResult's own live
|
||||
// check against each stop's estimated arrival/departure. Excluding BOARDING here would
|
||||
// silently impose a hidden, non-configurable 30-minute cutoff on top of that.
|
||||
const baseWhere: Prisma.TrainScheduleWhereInput = {
|
||||
status: { in: ["SCHEDULED", "BOARDING", "EN_ROUTE"] },
|
||||
isPackageOnly: false,
|
||||
stopTimes: { some: { stationId: originStationId } },
|
||||
coachAssignments: { some: {} },
|
||||
} as const;
|
||||
};
|
||||
|
||||
// Fetch candidates before and after in parallel; take more than needed to
|
||||
// account for routes that don't serve the destination or have no availability.
|
||||
@@ -300,23 +306,21 @@ export class SearchService {
|
||||
const nextDay = new Date(
|
||||
`${String(y)}-${String(m).padStart(2, "0")}-${String(d + 1).padStart(2, "0")}T00:00:00+03:00`,
|
||||
);
|
||||
const now = new Date();
|
||||
const totalPassengers = adultCount + (childCount ?? 0);
|
||||
|
||||
// Use now as the lower bound for today so we don't fetch schedules that have
|
||||
// already fully departed. The per-segment cutoff check in buildScheduleResult
|
||||
// handles the exact check using each stop's own plannedDepartureAt.
|
||||
const isToday =
|
||||
now.getFullYear() === y &&
|
||||
now.getMonth() === m - 1 &&
|
||||
now.getDate() === d;
|
||||
const earliest = isToday ? now : date;
|
||||
|
||||
// Match on the schedule's own departure DATE only — do NOT use `now` as a lower bound here.
|
||||
// A schedule whose origin has already departed (EN_ROUTE) can still have a later stop (e.g.
|
||||
// Lebu, Adama) whose own cutoff hasn't passed; using the overall departureAt as a floor would
|
||||
// wrongly exclude the whole schedule for those still-bookable downstream segments. The
|
||||
// per-segment cutoff check in buildScheduleResult is the sole authority for whether THIS
|
||||
// specific origin stop is still bookable, using each stop's own estimated arrival/departure.
|
||||
const schedules = await this.prisma.trainSchedule.findMany({
|
||||
where: {
|
||||
status: "SCHEDULED",
|
||||
// EN_ROUTE/BOARDING included alongside SCHEDULED — these are operational display
|
||||
// statuses, not booking-closed signals (see comment on searchAlternatives' baseWhere).
|
||||
status: { in: ["SCHEDULED", "BOARDING", "EN_ROUTE"] },
|
||||
isPackageOnly: false,
|
||||
departureAt: { gte: earliest, lt: nextDay },
|
||||
departureAt: { gte: date, lt: nextDay },
|
||||
stopTimes: { some: { stationId: originStationId } },
|
||||
coachAssignments: { some: {} },
|
||||
},
|
||||
@@ -368,7 +372,8 @@ export class SearchService {
|
||||
const [leg1Schedules, allCandidates] = await Promise.all([
|
||||
this.prisma.trainSchedule.findMany({
|
||||
where: {
|
||||
status: "SCHEDULED",
|
||||
// BOARDING included alongside SCHEDULED — see comment on searchAlternatives' baseWhere.
|
||||
status: { in: ["SCHEDULED", "BOARDING", "EN_ROUTE"] },
|
||||
isPackageOnly: false,
|
||||
departureAt: { gte: dayStart, lt: dayEnd },
|
||||
stopTimes: { some: { stationId: originStationId } },
|
||||
@@ -378,7 +383,7 @@ export class SearchService {
|
||||
}),
|
||||
this.prisma.trainSchedule.findMany({
|
||||
where: {
|
||||
status: "SCHEDULED",
|
||||
status: { in: ["SCHEDULED", "BOARDING", "EN_ROUTE"] },
|
||||
isPackageOnly: false,
|
||||
departureAt: { gte: dayStart, lt: leg2WindowEnd },
|
||||
coachAssignments: { some: {} },
|
||||
@@ -547,13 +552,14 @@ export class SearchService {
|
||||
if (!originStop || !destStop || originStop.sequence >= destStop.sequence)
|
||||
return null;
|
||||
|
||||
// Segment-level cutoff: use the origin stop's planned departure, not the
|
||||
// Segment-level cutoff: use the origin stop's own estimated arrival time, not the
|
||||
// schedule's overall departureAt (which is station A's time). This lets
|
||||
// B→D remain bookable even after A→D closes.
|
||||
// B→D remain bookable even after A→D closes. The first stop has no arrival (nothing
|
||||
// to arrive at), so it falls back to its own departure.
|
||||
// Cutoff resolution: stop-level override → route default → 30 min fallback.
|
||||
const now = new Date();
|
||||
const segmentDepartureAt =
|
||||
originStop.plannedDepartureAt ?? schedule.departureAt;
|
||||
originStop.plannedArrivalAt ?? originStop.plannedDepartureAt ?? schedule.departureAt;
|
||||
const routeStop = schedule.route?.stops?.find(
|
||||
(s) => s.stationId === originStationId,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user