The package builder (at /app/package-builder) is a point-of-sale screen built for walking a customer through your menu while they're standing in front of you. It used to live at /app/sales-matrix — that URL now points to the analytics Sales Matrix report instead, so update any old bookmarks.
How the tile grid works
The left side shows your services as a tile grid, grouped into cards by category (Tint, PPF, Detail, Removal, Wrap, Solar Glass, Security Glass, Decorative Glass, Privacy Glass, Anti-Graffiti, Other), each with its own colored badge. Within a category, tiles are sorted by price from low to high, so a "good / better / best" tier reads left to right. Category cards themselves are sorted alphabetically by label.
Tap a tile to add it to the invoice draft on the right. Tap the same tile again and it doesn't add a duplicate line — it bumps the quantity by one, and the tile shows a small badge with the current qty so you can see what's already in the draft at a glance. If your catalog is empty, the page shows a prompt to add your first service under Settings → Services instead of an empty grid.
The draft panel
The right-hand "Live invoice draft" panel is sticky so it stays visible while you scroll the tile grid. Each line lets you adjust quantity with +/- buttons (dropping quantity to zero removes the line) or tap the × to remove it outright. You can also edit the unit price inline — this only changes that one draft line, it does not change the service's catalog price. Subtotal, tax, and total update live as you edit.
Above the grid, pick a Customer (required) and optionally a Vehicle. If you land here from a customer's detail page, the customer is pre-filled automatically. The Tax rate % field defaults from your shop's configured tax rate but you can override it per transaction — whatever you type here is what gets applied.
Turning the draft into a sale
Two buttons at the bottom of the draft panel: "Create invoice" builds a real invoice via invoice.create and jumps straight to the invoice detail page; "Save as quote instead" creates a quote with a 30-day validity window and jumps to the quote page. Both stay disabled until you've picked a customer and added at least one tile, so there's no way to submit an incomplete draft. "Clear draft" wipes the current draft and only appears once you've added something.
Things to know
- The tax rate you type is a percent (e.g. 8.25), but under the hood it's converted to basis points before being sent — this matches how the regular quote/invoice forms store tax, so there's nothing to configure differently, but it's why you'll see it expressed differently if you ever inspect the underlying invoice.
- Every line item the package builder creates is marked taxable, and there's no way to apply a per-line discount from this screen — both are fixed at the code level (taxable: true, discountCents: 0) regardless of category.
- The draft only lives in the page's local state. Navigating away or refreshing clears it, so don't build a big draft and then wander off — get to invoice or quote before you leave the page.
- The package builder maps directly onto your existing services catalog; it doesn't support more complex tier/window-set grids that don't reduce to flat services and prices.