PDFs exported manually from the create screen looked different from the PDFs exported inside the ZIP bundle. The ZIP export rendered invoices server-side with PDFKit (styled table, colored header, payment box, embedded QR code), while the create screen built a separate HTML page and opened it in a print window with its own, simpler styling.
Approach
Extracted the ZIP export's rendering logic in app/src/app.js into a shared renderInvoicePdf(document, invoice) function, reused by both appendInvoicePdf (ZIP export) and a new POST /api/invoices/pdf endpoint.
The new endpoint accepts the invoice form data from the editor, normalizes it the same way POST /api/invoices does, and streams back a PDF generated with the exact same PDFKit layout used in the ZIP export.
Updated the "Vygenerovat a vytisknout fakturu" button in app/src/static/script.js to call this endpoint and download the resulting PDF, instead of building a standalone HTML document and invoking the browser print dialog.
Removed the now-unused HTML-template rendering helpers (buildInvoiceHtml, renderPerson, renderItems, getPersonName, getAddress, the duplicate normalizeIban/domesticAccountToIban/buildPaymentQrPayload client-side implementations) since the server-side renderer is now the single source of truth for invoice PDF styling.
Notes for reviewers
The manually generated PDF is now downloaded (like the ZIP invoices) rather than opened in a print dialog. This is an intentional UX change to keep both paths consistent and reuse the same code path.
Existing tests (npm test in app/) pass unchanged.
## Why
PDFs exported manually from the create screen looked different from the PDFs exported inside the ZIP bundle. The ZIP export rendered invoices server-side with PDFKit (styled table, colored header, payment box, embedded QR code), while the create screen built a separate HTML page and opened it in a print window with its own, simpler styling.
## Approach
- Extracted the ZIP export's rendering logic in `app/src/app.js` into a shared `renderInvoicePdf(document, invoice)` function, reused by both `appendInvoicePdf` (ZIP export) and a new `POST /api/invoices/pdf` endpoint.
- The new endpoint accepts the invoice form data from the editor, normalizes it the same way `POST /api/invoices` does, and streams back a PDF generated with the exact same PDFKit layout used in the ZIP export.
- Updated the "Vygenerovat a vytisknout fakturu" button in `app/src/static/script.js` to call this endpoint and download the resulting PDF, instead of building a standalone HTML document and invoking the browser print dialog.
- Removed the now-unused HTML-template rendering helpers (`buildInvoiceHtml`, `renderPerson`, `renderItems`, `getPersonName`, `getAddress`, the duplicate `normalizeIban`/`domesticAccountToIban`/`buildPaymentQrPayload` client-side implementations) since the server-side renderer is now the single source of truth for invoice PDF styling.
## Notes for reviewers
- The manually generated PDF is now downloaded (like the ZIP invoices) rather than opened in a print dialog. This is an intentional UX change to keep both paths consistent and reuse the same code path.
- Existing tests (`npm test` in `app/`) pass unchanged.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Why
PDFs exported manually from the create screen looked different from the PDFs exported inside the ZIP bundle. The ZIP export rendered invoices server-side with PDFKit (styled table, colored header, payment box, embedded QR code), while the create screen built a separate HTML page and opened it in a print window with its own, simpler styling.
Approach
app/src/app.jsinto a sharedrenderInvoicePdf(document, invoice)function, reused by bothappendInvoicePdf(ZIP export) and a newPOST /api/invoices/pdfendpoint.POST /api/invoicesdoes, and streams back a PDF generated with the exact same PDFKit layout used in the ZIP export.app/src/static/script.jsto call this endpoint and download the resulting PDF, instead of building a standalone HTML document and invoking the browser print dialog.buildInvoiceHtml,renderPerson,renderItems,getPersonName,getAddress, the duplicatenormalizeIban/domesticAccountToIban/buildPaymentQrPayloadclient-side implementations) since the server-side renderer is now the single source of truth for invoice PDF styling.Notes for reviewers
npm testinapp/) pass unchanged.