# Invoice Pattern Skill This skill defines the standard for implementing invoice-like forms (Invoice, Estimate, Job Card, Purchase Order, Bill, etc.) in the carage-erp dashboard. All such forms must follow this pattern for layout, discount/tax handling, and summary calculation. The current Invoice form is the canonical reference. --- ## 1. Layout - **Two-column grid:** - **Main column (9/12):** - Subject, invoice number/title - Status select, Discount Type select - Conditional Transaction Discount field - Line item selectors: Parts, Services, Expense Items (with optional line-level discount) - Notes, Terms & Conditions - Submit button - **Sidebar column (3/12):** - Invoice date, Due date - Customer, Vehicle selectors - Tax select (see below) - Department, Payment Terms, Invoice Sequence, Insurance fields - Summary card (see below) ## 2. Discount Implementation - **Discount Type:** - Field: `discount` (enum: 'no', 'line_item_level', 'transaction_level') - Select field in main column - **Transaction-level Discount:** - Field: `discount_amount` (number) - Only shown when `discount === "transaction_level"` - **Line-level Discount:** - Each line item (parts, services, expenses) has `discount_amount` field - Only shown when `discount === "line_item_level"` - **Payload Mapping:** - Only include `discount_amount` at transaction level if `discount === "transaction_level"` - Only include per-line `discount_amount` if `discount === "line_item_level"` ## 3. Tax Type Implementation - **Tax Field:** - Field: `tax` (relationFieldSchema: `{ value: string, label: string } | null`) - Uses `RhfAsyncSelectField` in sidebar - `mapOption`: `{ value: String(item.id), label: `${item.title} (${item.rate}%)` }` - The selected tax's rate is parsed from the label string in the summary (regex: `/\((\d+(?:\.\d+)?)%\)/`) ## 4. Summary Implementation - **Summary Card:** - Always rendered in the sidebar below the Details card - Uses `InvoiceFormSummary` (form-aware adapter) - `InvoiceFormSummary` flattens all line items, reads discount/tax fields, and passes them to `useDocumentTotals` hook - `useDocumentTotals` (pure hook) computes subtotal, discounts, tax, and total - `DocumentTotalsSummary` (pure display component) renders the summary --- ## Reference: Invoice Form - See `apps/dashboard/modules/invoices/invoice-form.tsx` for the canonical implementation. - Schema: `apps/dashboard/modules/invoices/invoice.schema.ts` - Summary logic: `apps/dashboard/modules/invoices/invoice-form-summary.tsx`, `shared/hooks/use-document-totals.ts`, `shared/components/document-totals-summary.tsx` --- ## Required for All Invoice-like Forms - Follow the above layout and field conventions - Use the same discount/tax logic and summary calculation - Use the same field and payload mapping patterns - Use the same summary component structure --- ## Example: Tax Field (in sidebar) ```tsx api.taxes.list()} mapOption={(item: any) => ({ value: String(item.id), label: item.title ? `${item.title} (${item.rate}%)` : `#${item.id}`, })} {...STORE_OBJECT} /> ``` ## Example: Discount Type Select (in main column) ```tsx ``` ## Example: Summary Card ```tsx
```