diff --git a/apps/edr-passenger-api/src/modules/notifications/notifications.service.ts b/apps/edr-passenger-api/src/modules/notifications/notifications.service.ts index fc8bffa27..a1678d131 100644 --- a/apps/edr-passenger-api/src/modules/notifications/notifications.service.ts +++ b/apps/edr-passenger-api/src/modules/notifications/notifications.service.ts @@ -303,7 +303,7 @@ export class NotificationsService { const booking = await this.prisma.booking.findUnique({ where: { id: bookingId }, include: { - schedule: { include: { originStation: true, destinationStation: true, train: true } }, + schedule: { include: { originStation: true, destinationStation: true, train: true, stopTimes: { include: { station: true } } } }, seats: { include: { seat: { include: { coach: { include: { coachType: true } } } } } }, }, }); @@ -353,6 +353,27 @@ export class NotificationsService { } } + /** + * Resolves the user's actual boarding/alighting stations from the booking's originStationId / + * destinationStationId via stopTimes, falling back to the schedule's full-route endpoints when + * the booking has no segment override (e.g. older records or packages). + */ + private resolveSegmentStations(booking: any): { originStation: any; destinationStation: any } { + const s = booking?.schedule ?? {}; + const stopTimes: any[] = s.stopTimes ?? []; + const findStation = (stationId: string | null | undefined, fallback: any) => { + if (stationId && stopTimes.length > 0) { + const stop = stopTimes.find((st: any) => st.stationId === stationId); + if (stop?.station) return stop.station; + } + return fallback ?? null; + }; + return { + originStation: findStation(booking?.originStationId, s.originStation), + destinationStation: findStation(booking?.destinationStationId, s.destinationStation), + }; + } + /** * Builds the interpolation context for the `booking.created` template. `trainSeatLines` is a * pre-joined block of one "Train/Seat: …" line per booked seat (multi-passenger bookings get @@ -379,12 +400,13 @@ export class NotificationsService { // Lead passenger (leg-1 seat). Booking has no contactName; the traveller name lives on the seat. const passengerName = seats[0]?.passengerName ?? 'Passenger'; const payLink = `${process.env.PORTAL_URL ?? 'http://localhost:5174'}/booking/detail?ref=${ref}`; + const { originStation: originSt, destinationStation: destSt } = this.resolveSegmentStations(booking); return { passengerName, bookingRef: ref, - origin: s.originStation?.name ?? '', - destination: s.destinationStation?.name ?? '', + origin: originSt?.name ?? '', + destination: destSt?.name ?? '', trainSeatLines, travelDate: fmtDate(s.departureAt), departureTime: fmtTime(s.departureAt), @@ -406,7 +428,7 @@ export class NotificationsService { const booking = await this.prisma.booking.findUnique({ where: { id: bookingId }, include: { - schedule: { include: { originStation: true, destinationStation: true, train: true } }, + schedule: { include: { originStation: true, destinationStation: true, train: true, stopTimes: { include: { station: true } } } }, seats: { include: { seat: { include: { coach: { include: { coachType: true } } } } } }, }, }); @@ -489,9 +511,10 @@ export class NotificationsService { const s = booking.schedule ?? {}; const dep = s.departureAt ? new Date(s.departureAt).toLocaleString('en-GB') : 'TBD'; const passengers = (booking.seats ?? []).map((bs: any) => bs.passengerName).filter(Boolean).join(', '); + const { originStation: originSt, destinationStation: destSt } = this.resolveSegmentStations(booking); return [ `Booking ${booking.bookingRef} confirmed.`, - `${s.originStation?.name ?? ''} -> ${s.destinationStation?.name ?? ''}`, + `${originSt?.name ?? ''} -> ${destSt?.name ?? ''}`, `Train: ${s.train?.name ?? s.train?.number ?? ''}`, `Departs: ${dep}`, passengers ? `Passengers: ${passengers}` : '', @@ -504,6 +527,7 @@ export class NotificationsService { const s = booking.schedule ?? {}; const fmt = (d: any) => d ? new Date(d).toLocaleString('en-GB', { dateStyle: 'medium', timeStyle: 'short' }) : 'TBD'; + const { originStation: originSt, destinationStation: destSt } = this.resolveSegmentStations(booking); const seatRows = (booking.seats ?? []) .map((bs: any) => { const coach = bs.seat?.coach?.number ?? '-'; @@ -532,11 +556,11 @@ export class NotificationsService { - + - + @@ -612,8 +636,9 @@ export class NotificationsService { const fmt = (d: any) => d ? new Date(d).toLocaleString('en-GB', { dateStyle: 'medium', timeStyle: 'short' }) : 'TBD'; const legLabel = leg ? ` (${leg.replace(/_/g, ' ')})` : ''; - const origin = s.originStation?.name ?? ''; - const dest = s.destinationStation?.name ?? ''; + const { originStation: originSt, destinationStation: destSt } = this.resolveSegmentStations(booking); + const origin = originSt?.name ?? ''; + const dest = destSt?.name ?? ''; const train = s.train?.name ?? s.train?.number ?? ''; const dep = fmt(s.departureAt); const arr = fmt(s.arrivalAt); diff --git a/apps/edr-passenger-api/src/modules/tickets/tickets.service.ts b/apps/edr-passenger-api/src/modules/tickets/tickets.service.ts index 1a9c88d4e..656e726ab 100644 --- a/apps/edr-passenger-api/src/modules/tickets/tickets.service.ts +++ b/apps/edr-passenger-api/src/modules/tickets/tickets.service.ts @@ -386,7 +386,7 @@ export class TicketsService { let booking = await this.prisma.booking.findUnique({ where: { bookingRef }, include: { - schedule: { include: { originStation: true, destinationStation: true, train: true } }, + schedule: { include: { originStation: true, destinationStation: true, train: true, stopTimes: { include: { station: true } } } }, returnSchedule: { include: { originStation: true, destinationStation: true } }, tickets: true, seats: { include: { seat: { include: { coach: true } } } }, @@ -400,7 +400,7 @@ export class TicketsService { booking = await this.prisma.booking.findUnique({ where: { bookingRef: ticket.bookingRef }, include: { - schedule: { include: { originStation: true, destinationStation: true, train: true } }, + schedule: { include: { originStation: true, destinationStation: true, train: true, stopTimes: { include: { station: true } } } }, returnSchedule: { include: { originStation: true, destinationStation: true } }, tickets: true, seats: { include: { seat: { include: { coach: true } } } }, @@ -453,6 +453,18 @@ export class TicketsService { // Send notifications after successful boarding await this.sendBoardingNotifications(booking, ticket, result.leg || 'OUTBOUND'); + // Resolve user-selected segment rather than the full schedule route + const _schedStops = (booking as any).schedule?.stopTimes ?? []; + const _resolveStation = (id: string | null | undefined, fallback: any) => { + if (id) { + const found = _schedStops.find((st: any) => st.stationId === id)?.station; + if (found) return found; + } + return fallback; + }; + const boardingOrigin = _resolveStation((booking as any).originStationId, (booking as any).schedule?.originStation); + const boardingDest = _resolveStation((booking as any).destinationStationId, (booking as any).schedule?.destinationStation); + return { success: true, message: `Passenger boarded successfully (${result.leg || 'OUTBOUND'} leg)`, @@ -461,7 +473,7 @@ export class TicketsService { ticketNumber: ticket.barcodePayload, bookingRef: booking.bookingRef, passengerName: seatInfo?.passengerName || ticket.passengerName || 'N/A', - route: `${(booking as any).schedule?.originStation?.name || 'N/A'} → ${(booking as any).schedule?.destinationStation?.name || 'N/A'}`, + route: `${boardingOrigin?.name || 'N/A'} → ${boardingDest?.name || 'N/A'}`, seat: seatNumber, coach: coachNumber, trainName: (booking as any).schedule?.train?.name || (booking as any).schedule?.train?.number || 'N/A', diff --git a/apps/edr-passenger-web/portal/src/app/booking/auth-check/page.tsx b/apps/edr-passenger-web/portal/src/app/booking/auth-check/page.tsx index 43775b1c7..9e1cdc9c9 100644 --- a/apps/edr-passenger-web/portal/src/app/booking/auth-check/page.tsx +++ b/apps/edr-passenger-web/portal/src/app/booking/auth-check/page.tsx @@ -81,20 +81,6 @@ export default function AuthCheckPage() {

- - - - + + + +
From${s.originStation?.name ?? ''} (${s.originStation?.code ?? ''})${originSt?.name ?? ''} (${originSt?.code ?? ''})
To${s.destinationStation?.name ?? ''} (${s.destinationStation?.code ?? ''})${destSt?.name ?? ''} (${destSt?.code ?? ''})
Train