feat: expand customer relation in PDF generation

Enhanced the PDF generation for quotes by expanding the customer relation to include the associated company information. This allows the company name to be displayed prominently in the "TO:" block of the PDF, improving clarity for users. Updated test data to reflect the new structure and ensure proper rendering of the company name when available.
This commit is contained in:
Dave 2026-09-02 11:40:50 +02:00
parent ccb27db82f
commit c64e5dc2ab
3 changed files with 52 additions and 6 deletions

View file

@ -142,9 +142,15 @@ export async function POST(
try {
const pb = await getAdminPocketBase();
// Quote + customer
// Quote + customer. We expand the customer's company relation
// too so the PDF can show the company name (not just the contact)
// in the "TO:" block. The Company record's `company` field is
// what the form picker shows in the form, and what the approvals
// list / customer search already surface — the PDF was the odd
// one out. PB inlines the relation in the same response, no
// extra round-trip.
const quote = await pb.collection("quotes").getOne<Quote>(quoteId, {
expand: "customer",
expand: "customer,customer.company",
});
// No-quote / decline-letter flag. When true, we render every
// active item through to the PDF regardless of price — this is

View file

@ -51,16 +51,35 @@ const baseCustomer: Customer = {
collectionName: "customers",
created: "2026-08-17T00:00:00.000Z",
updated: "2026-08-17T00:00:00.000Z",
customer: "Acme Mining (Pty) Ltd",
email: "buyer@acme.co.za",
// Contact name (was the company string before the 2026-09-02 fix
// that surfaces the company separately in the PDF "TO:" block).
customer: "Boetie van der Merwe",
email: "boetie@acme.co.za",
number: "+27 11 555 0123",
company: "Acme",
company: "acme1",
alternative_email: "",
buyer_email: "",
dateadded: "2026-01-01",
description: "",
lastvisiteddate: "",
rep: "",
// Expanded company relation — mirrors the shape PB returns when
// the PDF route asks for `expand: "customer,customer.company"`.
// Without this the new "TO:" block can't render the company name.
expand: {
company: {
id: "acme1",
collectionId: "pbc_companies",
collectionName: "companies",
created: "2026-01-01T00:00:00.000Z",
updated: "2026-01-01T00:00:00.000Z",
company: "Acme Mining (Pty) Ltd",
address: "1 Mining Road, Carletonville",
vendor: "ACME001",
company_email: "info@acme.co.za",
company_tel: "+27 11 555 0100",
},
},
};
const baseQuote: Quote = {

View file

@ -190,10 +190,21 @@ export function QuoteDocument({
{/* QUOTATION heading */}
<Text style={styles.title}>QUOTATION</Text>
{/* TO + Quote meta two-column row */}
{/* TO + Quote meta two-column row.
Company name (when present via the customer.company expand)
sits in bold above the contact name, mirroring the form
picker's "Company · Customer" pattern at
quote-form-contact-picker.tsx:94-95. The company line is
only rendered when the relation is expanded AND the
company record has a non-empty name — old PDFs / customers
without a linked company row just keep the contact-only
layout. */}
<View style={styles.metaRow}>
<View style={styles.metaCol}>
<Text style={styles.bold}>TO:</Text>
{customer.expand?.company?.company ? (
<Text style={styles.toCompany}>{customer.expand.company.company}</Text>
) : null}
<Text style={styles.body}>{customer.customer}</Text>
<Text style={styles.body}>{customer.email}</Text>
<Text style={styles.body}>{customer.number}</Text>
@ -335,6 +346,16 @@ const styles = StyleSheet.create({
companyName: { fontSize: 16, fontFamily: "Helvetica-Bold", marginBottom: 6 },
body: { fontSize: 10, marginBottom: 2 },
bold: { fontFamily: "Helvetica-Bold" },
// Company name in the "TO:" block (added 2026-09-02). Sits above
// the contact name in bold, mirroring the form picker's "Company
// bold, Contact smaller" pattern. Same font size as the rest of
// the meta column so it doesn't shout, just signals "this is the
// legal entity" before the contact's personal name.
toCompany: {
fontFamily: "Helvetica-Bold",
fontSize: 10,
marginBottom: 2,
},
// Logo — absolutely-positioned so it floats over the header without
// pushing the QUOTATION heading down or fighting @react-pdf's
// flexbox-Image placement bug. `top` is from the page top edge