From c31a337a989eab9182fc253b05c5585467d2363c Mon Sep 17 00:00:00 2001 From: Roba Boru Date: Sun, 19 Jul 2026 23:58:14 +0300 Subject: [PATCH] Include coach number to voucher --- .../src/app/booking/confirmation/page.tsx | 27 +++++++----- .../portal/src/lib/generate-voucher.ts | 44 ++++++++++++------- 2 files changed, 43 insertions(+), 28 deletions(-) diff --git a/apps/edr-passenger-web/portal/src/app/booking/confirmation/page.tsx b/apps/edr-passenger-web/portal/src/app/booking/confirmation/page.tsx index 7d9cd691a..1039b1465 100644 --- a/apps/edr-passenger-web/portal/src/app/booking/confirmation/page.tsx +++ b/apps/edr-passenger-web/portal/src/app/booking/confirmation/page.tsx @@ -263,21 +263,24 @@ export default function ConfirmationPage() { const ticketNumber = matchedTicket?.barcodePayload || "Not yet issued"; await generatePassengerVoucherPDF({ - bookingRef: pnr, + bookingRef: pnr, ticketNumber, - passengerName: p.name || `Passenger ${i + 1}`, - dateOfBirth: p.dateOfBirth, - nationality: p.nationality, - seatNumber: p.seatNumber, - outboundSeatNumber: (p as any).outboundSeatNumber, - inboundSeatNumber: (p as any).inboundSeatNumber, + passengerName: p.name || `Passenger ${i + 1}`, + dateOfBirth: p.dateOfBirth, + nationality: p.nationality, + seatNumber: p.seatNumber, + coachNumber: p.coachNumber, + outboundSeatNumber: p.outboundSeatNumber, + outboundCoachNumber: p.outboundCoachNumber, + inboundSeatNumber: p.inboundSeatNumber, + inboundCoachNumber: p.inboundCoachNumber, status, - outboundSchedule: outbound, - inboundSchedule: inbound, + outboundSchedule: outbound, + inboundSchedule: inbound, isRoundTrip, - fareMinor: hasSettledAmount ? settledAmountMinor! : getEtbFare(i), - currency: voucherCurrency, - fareIsMajorUnits: hasSettledAmount, + fareMinor: hasSettledAmount ? settledAmountMinor! : getEtbFare(i), + currency: voucherCurrency, + fareIsMajorUnits: hasSettledAmount, createdAt, }); } diff --git a/apps/edr-passenger-web/portal/src/lib/generate-voucher.ts b/apps/edr-passenger-web/portal/src/lib/generate-voucher.ts index 894795c52..439c26c29 100644 --- a/apps/edr-passenger-web/portal/src/lib/generate-voucher.ts +++ b/apps/edr-passenger-web/portal/src/lib/generate-voucher.ts @@ -24,8 +24,11 @@ interface PassengerVoucherData { dateOfBirth?: string; nationality?: string; seatNumber?: string; + coachNumber?: string; outboundSeatNumber?: string; + outboundCoachNumber?: string; inboundSeatNumber?: string; + inboundCoachNumber?: string; status: string; outboundSchedule: ScheduleInfo; inboundSchedule?: ScheduleInfo; @@ -314,16 +317,21 @@ function drawPassengerDetails(doc: jsPDF, data: PassengerVoucherData, y: number, label(doc, 'Passenger details', margin, y); y += 7; + const formatSeat = (coach: string | undefined, seat: string | undefined): string => { + if (!seat) return '—'; + return coach ? `Coach ${coach} · Seat ${seat}` : `Seat ${seat}`; + }; + const rows: [string, string][] = [ ['Full name', data.passengerName || '—'], ['Date of birth', data.dateOfBirth ? new Date(data.dateOfBirth).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' }) : '—'], ['Nationality', data.nationality || '—'], ]; if (data.isRoundTrip) { - rows.push(['Outbound seat', data.outboundSeatNumber || '—']); - rows.push(['Return seat', data.inboundSeatNumber || '—']); + rows.push(['Outbound seat', formatSeat(data.outboundCoachNumber, data.outboundSeatNumber)]); + rows.push(['Return seat', formatSeat(data.inboundCoachNumber, data.inboundSeatNumber)]); } else { - rows.push(['Seat', data.seatNumber || '—']); + rows.push(['Seat', formatSeat(data.coachNumber, data.seatNumber)]); } const rowH = 7; @@ -485,9 +493,10 @@ export const generateVoucherPDF = async (booking: VoucherData): Promise => // Group leg rows back into one entry per real passenger — without this, a round trip // produced two half-passenger vouchers (one per leg, each showing only its own leg's // seat) instead of one voucher per passenger covering both legs. + type SeatInfo = VoucherData['passengers'][number]['seat']; const grouped = new Map< string, - { fullName: string; category: string; outboundSeat?: VoucherData['passengers'][number]['seat']; returnSeat?: VoucherData['passengers'][number]['seat'] } + { fullName: string; category: string; outboundSeat?: SeatInfo; returnSeat?: SeatInfo } >(); booking.passengers.forEach((p) => { const key = `${p.fullName}|${p.dateOfBirth}|${p.category}`; @@ -514,20 +523,23 @@ export const generateVoucherPDF = async (booking: VoucherData): Promise => const ticketNumber = matchedTicket?.barcodePayload || 'Not yet issued'; await generatePassengerVoucherPDF({ - bookingRef: booking.bookingRef, + bookingRef: booking.bookingRef, ticketNumber, - passengerName: p.fullName, - status: booking.status, - outboundSchedule: { ...booking.schedule, seatClass: p.outboundSeat?.seatClass }, - inboundSchedule: isRoundTrip ? { ...booking.returnSchedule!, seatClass: p.returnSeat?.seatClass } : undefined, + passengerName: p.fullName, + status: booking.status, + outboundSchedule: { ...booking.schedule, seatClass: p.outboundSeat?.seatClass }, + inboundSchedule: isRoundTrip ? { ...booking.returnSchedule!, seatClass: p.returnSeat?.seatClass } : undefined, isRoundTrip, - seatNumber: isRoundTrip ? undefined : p.outboundSeat?.number, - outboundSeatNumber: isRoundTrip ? p.outboundSeat?.number : undefined, - inboundSeatNumber: isRoundTrip ? p.returnSeat?.number : undefined, - fareMinor: voucherFareMinor, - currency: voucherCurrency, - fareIsMajorUnits: useSettledAmount, - createdAt: booking.createdAt, + seatNumber: isRoundTrip ? undefined : p.outboundSeat?.number, + coachNumber: isRoundTrip ? undefined : p.outboundSeat?.coach, + outboundSeatNumber: isRoundTrip ? p.outboundSeat?.number : undefined, + outboundCoachNumber: isRoundTrip ? p.outboundSeat?.coach : undefined, + inboundSeatNumber: isRoundTrip ? p.returnSeat?.number : undefined, + inboundCoachNumber: isRoundTrip ? p.returnSeat?.coach : undefined, + fareMinor: voucherFareMinor, + currency: voucherCurrency, + fareIsMajorUnits: useSettledAmount, + createdAt: booking.createdAt, }); } };