# Quote PDF Generation (quote-tab-manager.js) ## Entry Points Two user actions, both in `quote-tab-manager.js`: - **`downloadPdf()`** (line ~3696): creates download link, triggers save as `Quote_XXX_CustomerName.pdf` - **`printQuote()`** (line ~3670): opens PDF blob in new window, triggers `window.print()` Both call `generateQuotePDF()` — the only difference is what happens with the returned blob. ## Button Wiring `ensureDownloadPdfBtnListener()` (line ~706): 1. Looks for buttons with IDs `download-pdf-btn` or `generate-pdf-btn` 2. Falls back to scanning all buttons for text/classes containing "pdf" or "download" 3. If still nothing found, dynamically creates a PDF button via `createPdfButton()` ## generateQuotePDF() Structure Location: `quote-tab-manager.js` line ~3727 1. Dynamically imports jsPDF from CDN: `https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js` 2. Accesses via `window.jspdf.jsPDF` 3. Validates customer name + services exist 4. Builds PDF with these sections: ### Header (two-column layout) - **Left column**: "SERVICE PROVIDER" label, business name/address/phone, service advisor - **Right column**: "CUSTOMER INFORMATION" label, name/vehicle/RO#/mileage/VIN/date - Bold separator line between header and content ### Personalized Message - Uses `appSettings.headerMessage` template with `{customerName}` and `{vehicleInfo}` placeholders - Split to fit content width ### Services Section - Split into "SERVICES APPROVED" and "POSTPONED SERVICES" if mixed decisions exist - Each service: green "✓ CUSTOMER APPROVED" or red "✗ CUSTOMER DECLINED" badge - Service name: **bold, 10px** (reduced from 12px) - Price: right-aligned - Priority header (if prioritized): `[CRITICAL]`, `[SAFETY]`, `[RECOMMENDED]`, `[MAINTENANCE]`, `[OPTIONAL]` - Recommendation level text - Service explanation (split to fit width) - Parts/aftermarket notes - Light gray separator between services ### Pricing Summary (totals box) - Subtle `#f8f8f8` rounded-rect background box with `#dcdcdc` border - 45% width from right margin - Line items (9px, labels in gray `#646464`): Subtotal, Approved (green), Discount (green with − sign), Shop charge, Tax - Separator: 0.5px `#b4b4b4` line - TOTAL: bold 10px - Row spacing: 8px throughout ### Shop Charge Note - Positioned at `boxBottomY + 10` — must stay after the box's visual boundary - 8px font, gray, prefixed with `*` ### Footer - Light gray separator line - Centered `appSettings.footerMessage` and `appSettings.quoteFooterNote` - Page numbers: "Page X of Y" at bottom right ## Key Design Choice `technicianNotes` are deliberately excluded from PDFs — they're internal AI context notes, not customer-facing. ## Invoice PDF (repair-orders.js) Separate from quotes. `printInvoice()` at line ~1340 in `repair-orders.js` calls `generateInvoicePDF()` which also uses jsPDF but with a different layout.