2026-06-23 06:30:38 +00:00
|
|
|
import { pdf } from "@react-pdf/renderer";
|
|
|
|
|
import { QuoteDocument, type QuoteDocumentProps } from "./quote-document";
|
2026-06-29 11:06:01 +00:00
|
|
|
import {
|
|
|
|
|
PurchaseOrderDocument,
|
|
|
|
|
type PurchaseOrderDocumentProps,
|
|
|
|
|
} from "./purchase-order-document";
|
2026-06-23 06:30:38 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Server-side render of a `<QuoteDocument>` to a PDF Buffer.
|
|
|
|
|
*
|
|
|
|
|
* Uses `@react-pdf/renderer`'s Node API (`pdf(<JSX />).toBuffer()`) which
|
|
|
|
|
* runs entirely in-process — no headless Chromium, no Playwright/Puppeteer,
|
|
|
|
|
* no browser binary in the Docker image.
|
|
|
|
|
*
|
|
|
|
|
* Always returns a fresh Buffer; never cached. Reads of letterhead,
|
|
|
|
|
* quote, items, and customer happen in the API route before this is
|
|
|
|
|
* called, so any edit in PB propagates on the next generation.
|
|
|
|
|
*/
|
|
|
|
|
export async function renderQuotePdf(props: QuoteDocumentProps): Promise<Buffer> {
|
|
|
|
|
const instance = pdf(<QuoteDocument {...props} />);
|
|
|
|
|
// `toBuffer()` works in pure Node, but under jsdom (Vitest's default
|
|
|
|
|
// test environment) it returns a PDFKit document handle instead. We
|
|
|
|
|
// funnel through `toString()` which always resolves to a string of
|
|
|
|
|
// raw PDF bytes, then convert to a real Node Buffer. The string path
|
|
|
|
|
// is ~the same performance as toBuffer in production.
|
|
|
|
|
const pdfString = await instance.toString();
|
|
|
|
|
return Buffer.from(pdfString, "binary");
|
2026-06-29 11:06:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Server-side render of a `<PurchaseOrderDocument>` to a PDF Buffer.
|
|
|
|
|
*
|
|
|
|
|
* Same in-process Node pipeline as `renderQuotePdf` — no headless
|
|
|
|
|
* Chromium, no browser binary. The PO PDF document component is a
|
|
|
|
|
* pure function of its props, so the API route resolves the PO +
|
|
|
|
|
* items + supplier + order + customer + letterhead before calling
|
2026-07-07 15:22:03 +00:00
|
|
|
* this, then uploads the resulting Buffer to
|
|
|
|
|
* `purchase_orders.documents` (the embedded file, multi field on
|
|
|
|
|
* the PO record itself — replaced 2026-07-06 the separate
|
|
|
|
|
* `purchase_order_pdfs` collection).
|
2026-06-29 11:06:01 +00:00
|
|
|
*
|
|
|
|
|
* `toString()` is used for the same jsdom-test compat reason as the
|
|
|
|
|
* quote renderer — both routes are test-covered and we want them to
|
|
|
|
|
* produce the same shape regardless of environment.
|
|
|
|
|
*/
|
|
|
|
|
export async function renderPurchaseOrderPdf(
|
|
|
|
|
props: PurchaseOrderDocumentProps
|
|
|
|
|
): Promise<Buffer> {
|
|
|
|
|
const instance = pdf(<PurchaseOrderDocument {...props} />);
|
|
|
|
|
const pdfString = await instance.toString();
|
|
|
|
|
return Buffer.from(pdfString, "binary");
|
2026-06-23 06:30:38 +00:00
|
|
|
}
|