| @@ -22,10 +22,9 @@ | ||
| 22 | 22 | const nonce = w?.yatraAdmin?.nonce || ""; |
| 23 | 23 | return { base, nonce }; |
| 24 | 24 | } |
| 25 | 25 | |
| 26 | -function buildInvoiceUrl(base: string, paymentId: number): string { | |
| 27 | - const suffix = `/yatra/v1/payment/${paymentId}/invoice`; | |
| 26 | +function buildInvoiceUrl(base: string, suffix: string): string { | |
| 28 | 27 | const origin = |
| 29 | 28 | typeof window !== "undefined" ? window.location.origin : "http://localhost"; |
| 30 | 29 | |
| 31 | 30 | let u: URL; |
| @@ -64,24 +63,24 @@ | ||
| 64 | 63 | return msg; |
| 65 | 64 | } |
| 66 | 65 | |
| 67 | 66 | /** |
| 68 | - * Download a payment invoice PDF as a file. | |
| 67 | + * Fetch an invoice PDF from `suffix` and save it, falling back to | |
| 68 | + * `fallbackName` when the response carries no Content-Disposition. | |
| 69 | 69 | * |
| 70 | 70 | * Authentication is handled server-side via the admin REST nonce + cookie |
| 71 | - * (administrators bypass the ownership check inside `download_invoice`). | |
| 71 | + * (administrators bypass the ownership check inside the endpoint). | |
| 72 | 72 | */ |
| 73 | -export async function downloadAdminInvoice(paymentId: number): Promise<void> { | |
| 74 | - if (!paymentId || paymentId <= 0) { | |
| 75 | - throw new Error("Invalid payment ID"); | |
| 76 | - } | |
| 77 | - | |
| 73 | +async function downloadInvoicePdf( | |
| 74 | + suffix: string, | |
| 75 | + fallbackName: string, | |
| 76 | +): Promise<void> { | |
| 78 | 77 | const { base, nonce } = getAdminRestConfig(); |
| 79 | 78 | if (!nonce) { |
| 80 | 79 | throw new Error("Missing REST nonce; please reload the page."); |
| 81 | 80 | } |
| 82 | 81 | |
| 83 | - const url = buildInvoiceUrl(base, paymentId); | |
| 82 | + const url = buildInvoiceUrl(base, suffix); | |
| 84 | 83 | const res = await fetch(url, { |
| 85 | 84 | method: "GET", |
| 86 | 85 | credentials: "include", |
| 87 | 86 | headers: { |
| @@ -95,9 +94,9 @@ | ||
| 95 | 94 | } |
| 96 | 95 | |
| 97 | 96 | const blob = await res.blob(); |
| 98 | 97 | const dispo = res.headers.get("Content-Disposition"); |
| 99 | - let filename = `invoice-${paymentId}.pdf`; | |
| 98 | + let filename = fallbackName; | |
| 100 | 99 | if (dispo) { |
| 101 | 100 | const m = /filename\*?=(?:UTF-8'')?["']?([^";\n]+)/i.exec(dispo); |
| 102 | 101 | if (m?.[1]) { |
| 103 | 102 | try { |
| @@ -115,5 +114,38 @@ | ||
| 115 | 114 | document.body.appendChild(link); |
| 116 | 115 | link.click(); |
| 117 | 116 | document.body.removeChild(link); |
| 118 | 117 | URL.revokeObjectURL(objectUrl); |
| 118 | +} | |
| 119 | + | |
| 120 | +/** | |
| 121 | + * Download a payment invoice (receipt for one recorded payment). | |
| 122 | + */ | |
| 123 | +export async function downloadAdminInvoice(paymentId: number): Promise<void> { | |
| 124 | + if (!paymentId || paymentId <= 0) { | |
| 125 | + throw new Error("Invalid payment ID"); | |
| 126 | + } | |
| 127 | + | |
| 128 | + await downloadInvoicePdf( | |
| 129 | + `/yatra/v1/payment/${paymentId}/invoice`, | |
| 130 | + `invoice-${paymentId}.pdf`, | |
| 131 | + ); | |
| 132 | +} | |
| 133 | + | |
| 134 | +/** | |
| 135 | + * Download a booking invoice — the whole booking rather than a single | |
| 136 | + * payment, so it also works for bookings with no payment recorded yet | |
| 137 | + * (bank transfer, pay later), where it renders as a pro-forma invoice with | |
| 138 | + * the gateway's payment instructions. | |
| 139 | + */ | |
| 140 | +export async function downloadAdminBookingInvoice( | |
| 141 | + bookingId: number, | |
| 142 | +): Promise<void> { | |
| 143 | + if (!bookingId || bookingId <= 0) { | |
| 144 | + throw new Error("Invalid booking ID"); | |
| 145 | + } | |
| 146 | + | |
| 147 | + await downloadInvoicePdf( | |
| 148 | + `/yatra/v1/booking/${bookingId}/invoice`, | |
| 149 | + `invoice-booking-${bookingId}.pdf`, | |
| 150 | + ); | |
| 119 | 151 | } |