# Inventory Documents — PDFs & Email

_Enterprise_

Four document templates ship with the inventory subsystem: packing slip (US-Letter, FROM/TO + items + totals), box label (4×6" thermal-style with QR + box number), reorder report (paginated table grouped by manufacturer), and sales invoice (full FinanceInvoice template with line items + tax/discount/total stack). All render server-side via pdf-lib, upload to R2, and return 1-hour presigned URLs. Three of them also have an email-out path with sandbox interception baked in.

## Steps
1. Packing slip: from a box detail page (web or mobile), click "Packing Slip" — opens the PDF in a new tab. Click "Email Slip" — compose modal pre-fills with the customer email; attaches PDF; sends via Resend.
2. Box label: same box detail page, click "Print Label" — opens a 4×6" PDF in a new tab, ready for a Brother/Zebra thermal printer or a regular printer with paper.
3. Reorder report: from the Reorder tab, every group has an "Email Report" button. The preview-then-send modal is described in the Reorder Report article.
4. Sales invoice: triggered from the finance subsystem via /enterprise/inventory/invoices/:id/pdf (UI buttons in the finance UI are a follow-up; the endpoint is live). Email-out flips the invoice from "draft" to "sent" and stamps sentAt.
5. Every PDF uses your org's brand color, secondary color (Settings > Customize > Brand Colors), and logo (Settings > Account > Organization). PNG/JPG logos render; WebP/AVIF/SVG fall back to no-logo gracefully.

## Tips
- Multi-box numbering: when a box is one of multiple boxes on the same PO, both the label and the packing slip automatically show "BOX N OF M" — the label gets a big accent-colored line, the packing slip appends "· BOX N OF M" to the Box Number meta row.
- Packing slips paginate cleanly for boxes with 30+ items — continuation pages get a slim "PACKING SLIP (cont.)" header with re-rendered column headers, and "Page N of M" appears at the bottom when the doc spans 2+ pages.
- PDFs are uploaded to R2 under inventory-pdfs/<orgId>/<kind>/<id>-<timestamp>.pdf. Re-rendering doesn't overwrite — every render gets a fresh timestamp key, so you have implicit version history.
- Sandbox interception: in sandbox orgs, sending an email captures the body + filenames to SandboxInterceptedEmail (visible at Enterprise > Sandbox > <id> > Intercepted emails) instead of dispatching. Reviewers see the filename list appended to the body so they can verify which artifacts would have been attached.

## Example
A fulfillment team processes 300 outbound boxes a week. Each one needs a packing slip in the carton, a 4×6" QR label on the outside, and an email to the customer with the PDF attached. The old workflow took 90 seconds per box (open spreadsheet, copy SKUs, open Word, mail merge, print, email). The new workflow is 3 clicks: Print Label, Packing Slip, Email Slip. Total: under 10 seconds per box. The fulfillment manager calls it "the single biggest QoL change we shipped this year."

## Troubleshooting
- **PDF opens but the logo is missing** — The brand logo URL points to a WebP, AVIF, or SVG file. pdf-lib only embeds PNG and JPG. Fix: Re-upload the logo as PNG (preferred) or JPG at Settings > Account > Organization. The next render will include it.
- **PDF shows a teal accent even though the brand color is set to something else** — The brand color is malformed (not a valid 6-digit hex code). The renderer falls back to teal (#00c4b4) on bad input rather than crashing. Fix: Settings > Customize > Brand Colors — set a valid 6-digit hex color like #FF6B35. Save, re-trigger the PDF.
- **"Sandbox" emails not arriving at the real recipient** — You're inside a sandbox session. Sandbox orgs intercept every email — nothing reaches Resend. This is by design to prevent test workflows from leaking. Fix: Exit the sandbox before sending real emails. Check Enterprise > Sandbox > Intercepted emails to verify what the sandbox would have sent.
- **"Failed to render PDF" error in console** — Could be R2 connectivity, malformed Box/Invoice data, or a transient pdf-lib failure on bad input. Fix: Refresh and retry. If it persists, the response body has the upstream error — share it with support.

## Plans
Enterprise suite required. Email-out uses Resend (one API call per send).
