Merge pull request #896 from Tria-plc/alpha

Ticket generation updates
This commit is contained in:
Stephanos A.
2026-07-22 08:53:03 +03:00
committed by GitHub

View File

@@ -112,6 +112,15 @@ export default function ConfirmationPage() {
// backgrounded tabs, so that can take a very long time.
staleTime: 0,
enabled: !!bookingId,
// Keep polling after CONFIRMED until tickets are issued — ticket generation runs
// async after the booking transaction commits (see finalizePaymentSuccess in
// payments.service.ts), so the first CONFIRMED fetch often returns an empty
// tickets array.
refetchInterval: (query) => {
const data = query.state.data;
if (!data || data.status !== "CONFIRMED") return false;
return (data.tickets?.length ?? 0) >= passengers.length ? false : FAST_POLL_INTERVAL_MS;
},
});
// Poll the payment intent while the booking is PENDING_PAYMENT — fast during the
@@ -153,7 +162,7 @@ export default function ConfirmationPage() {
};
const handleDownloadVoucher = async () => {
if (!pnr) {
if (!pnr || !bookingId) {
alert("Booking data not available. Please try again.");
return;
}
@@ -164,23 +173,28 @@ export default function ConfirmationPage() {
setIsGeneratingVoucher(true);
try {
const { generatePassengerVoucherPDF } =
await import("@/lib/generate-voucher");
const { generatePassengerVoucherPDF } = await import("@/lib/generate-voucher");
// Always fetch fresh booking data so tickets are present even if the cached
// _booking raced ahead of ticket generation (tickets are written async after
// the booking is confirmed — see finalizePaymentSuccess in payments.service.ts).
const freshBooking: BookingWithTicket = await apiClient.get(`/bookings/${bookingId}`);
const bookingData = freshBooking ?? _booking;
const activeSchedule = isRoundTrip ? outboundSchedule : selectedSchedule;
// The server-confirmed settled amount/currency (what was actually charged) is
// authoritative — prefer it over the ETB booking fare once available. Shown exactly
// as returned by the API (no /100, no per-passenger split) on every passenger's
// voucher — see fareIsMajorUnits below.
const settledAmountMinor = _booking?.payment?.amountMinor;
const settledCurrency = _booking?.payment?.currency;
const settledAmountMinor = bookingData?.payment?.amountMinor;
const settledCurrency = bookingData?.payment?.currency;
const hasSettledAmount = settledAmountMinor != null && !!settledCurrency;
// Derive display currency from nationality (same logic as review/payment pages)
const nat = (searchCriteria?.nationality ?? '').toUpperCase();
const passengerDisplayCurrency = nat === 'DJIBOUTIAN' ? 'DJF' : nat === 'ETHIOPIAN' ? 'ETB' : 'USD';
const voucherCurrency = hasSettledAmount ? settledCurrency! : passengerDisplayCurrency;
const createdAt = _booking?.createdAt || new Date().toISOString();
const status = _booking?.status || "CONFIRMED";
const createdAt = bookingData?.createdAt || new Date().toISOString();
const status = bookingData?.status || "CONFIRMED";
// Compute per-passenger fares (in ETB) using the same logic as the review/payment
// pages. reviewedPassengerFares is the authoritative source; rebuild from package
@@ -206,7 +220,7 @@ export default function ConfirmationPage() {
return isPkgChild ? pkgChildFare : pkgAdultFare;
}
const totalFare =
reviewedTotalMinor ?? paidAmountMinor ?? _booking?.totalMinor ?? 0;
reviewedTotalMinor ?? paidAmountMinor ?? bookingData?.totalMinor ?? 0;
return Math.round(totalFare / passengers.length);
};
@@ -254,11 +268,9 @@ export default function ConfirmationPage() {
// synchronous user-activation window and risk iOS Safari silently blocking them.
for (let i = 0; i < passengers.length; i++) {
const p = passengers[i];
// Same match-by-name-then-position as the on-screen ticket list above — no
// fabricated placeholder if there's no backend ticket data (see generate-voucher.ts).
const matchedTicket =
_booking?.tickets?.find((t) => t.passengerName === p.name) ??
_booking?.tickets?.[i] ??
bookingData?.tickets?.find((t) => t.passengerName === p.name) ??
bookingData?.tickets?.[i] ??
null;
const ticketNumber = matchedTicket?.barcodePayload || "Not yet issued";