Merge pull request #1269 from Tria-plc/alpha

fix: ( notifications ) stop group-booking SMS greeting the wrong pass…
This commit is contained in:
Abubeker Yasin
2026-08-13 12:23:49 +03:00
committed by GitHub
3 changed files with 275 additions and 17 deletions

View File

@@ -8,6 +8,7 @@ import { EmailClientService } from './email-client.service';
import { SmsClientService } from './sms-client.service';
import { CreateTemplateDto, UpdateTemplateDto } from './notifications.dto';
import { resolveBookingSegment } from '../../common/utils/segment-resolver.utils';
import { buildSeatSummary } from '../../common/utils/booking-sms.utils';
export type NotificationChannelType = 'EMAIL' | 'SMS' | 'PUSH' | 'IN_APP';
@@ -305,7 +306,7 @@ export class NotificationsService {
where: { id: bookingId },
include: {
schedule: { include: { originStation: true, destinationStation: true, train: true, stopTimes: { include: { station: true } } } },
seats: { include: { seat: { include: { coach: { include: { coachType: true } } } } } },
seats: { include: { seat: { include: { coach: { include: { coachType: true } } } } }, orderBy: { leg: 'asc' } },
},
});
@@ -367,30 +368,19 @@ export class NotificationsService {
}
/**
* 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
* several lines).
* Builds the interpolation context for the `booking.created` template. `passengerName` and
* `trainSeatLines` both come from buildSeatSummary — a solo booking is greeted by name with
* bare "coach, seat no." lines, while a group is greeted as "Passengers" and each line names
* its own occupant (one SMS goes to Booking.contactPhone for the whole party).
*/
private buildBookingCreatedContext(booking: any, ref: string): Record<string, unknown> {
const s = booking?.schedule ?? {};
const trainName = s.train?.name ?? s.train?.number ?? '';
const fmtDate = (d: any) =>
d ? new Date(d).toLocaleDateString('en-US', { month: 'short', day: '2-digit', year: 'numeric' }) : 'TBD';
const fmtTime = (d: any) =>
d ? new Date(d).toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: true }) : 'TBD';
const seats = booking?.seats ?? [];
const trainSeatLines = seats
.map((bs: any) => {
const coach = bs.seat?.coach?.number ?? '-';
const cls = bs.seat?.coach?.coachType?.name ?? '';
const seatNo = bs.seat?.seatNumber ?? '-';
return `Train/Seat: Train ${trainName}, ${coach} ${cls}, seat no. ${seatNo}`.replace(/ +/g, ' ').trim();
})
.join('\n');
// Lead passenger (leg-1 seat). Booking has no contactName; the traveller name lives on the seat.
const passengerName = seats[0]?.passengerName ?? 'Passenger';
const { passengerName, trainSeatLines } = buildSeatSummary(booking?.seats ?? [], booking?.bookingType);
const payLink = `${process.env.PORTAL_URL ?? 'http://localhost:5174'}/booking/detail?ref=${ref}`;
const segment = resolveBookingSegment(s, booking?.originStationId, booking?.destinationStationId);