# Feature: Invoices (quotes + invoices)

## Purpose

Team-scoped quoting and invoicing for jobs/appointments: discount codes, customer payments, provider payout hold-until-invoice-paid, Dashboard profit/outstanding widgets, CSV exports for Xero / QuickBooks / Sage, editable PDF templates, and email delivery with additional recipients.

## Boundaries

- **Owns:** `invoice_settings`, `quotes`, `quote_line_items`, `invoices`, `invoice_line_items`, `invoice_payments`, `discount_codes`, `discount_code_redemptions`, `invoice_document_sends`; Inertia under `Pages/Invoices`, `Pages/Quotes`, `Pages/DiscountCodes`; Blade PDF/email views under `resources/views/invoices`, `resources/views/quotes`, `resources/views/emails/invoices`
- **Does not own:** Jobs appointments, Providers CRM, company business hours, Customers CRM
- **Depends on (platform only):** User / Team / auth; Laravel Mail; Dompdf (`barryvdh/laravel-dompdf`)
- **Depends on (other domains):** none required — soft IDs to customers/jobs/appointments/provider payments via DB helpers; soft-reads `customers` / `customer_contacts` emails for recipient pickers
- **Platform UI:** Quotes / Invoices / Discount codes nav in `AppLayout.vue`; Dashboard overview via soft `DashboardMetrics`; Company Settings hold flag

## Models

| Model | Table | Notes |
|-------|-------|-------|
| `InvoiceSetting` | `invoice_settings` | Prefixes/next numbers; due/valid days; currency; company letterhead; invoice/quote header/intro/footer HTML templates |
| `Quote` | `quotes` | Soft customer/job/discount; statuses draft/sent/accepted/declined/expired/converted |
| `QuoteLineItem` | `quote_line_items` | Quantity × unit |
| `Invoice` | `invoices` | Soft customer/job/appointment/quote/discount; statuses draft/sent/paid/void/overdue |
| `InvoiceLineItem` | `invoice_line_items` | |
| `InvoicePayment` | `invoice_payments` | Customer payments |
| `DiscountCode` | `discount_codes` | Fixed/%, date range, weekdays, max usage, eligibility, booking type, apply_to |
| `DiscountCodeRedemption` | `discount_code_redemptions` | Soft invoice/quote |
| `InvoiceDocumentSend` | `invoice_document_sends` | Audit of emailed documents; soft `document_id`; **intentional denormalisation** of `to_email` / `cc_emails` / `subject` as a send snapshot |

Jobs soft pricing: `service_jobs.unit_price`, `pricing_unit` (`per_visit`|`flat`|`hourly`).  
Providers: `provider_payments.status` includes `held`; soft `invoice_id`.  
Company settings: `hold_provider_payments_until_invoice_paid`.

Migrations: `2026_08_12_180000_create_invoices_tables.php`, `2026_08_13_003200_add_invoice_document_templates_and_sends.php`.

## Document templates & email

- Templates live on `invoice_settings` (one set per team). Placeholders: `{{document_number}}`, `{{customer_name}}`, `{{total}}`, `{{currency}}`, `{{due_on}}` / `{{valid_until}}`, `{{issued_on}}`.
- PDF via Dompdf Blade views; download at `GET /invoices/{invoice}/pdf` and `GET /quotes/{quote}/pdf`.
- Email (`POST .../email`): PDF attachment + short text body (amount + brief line summary). To required; up to 10 CC addresses (contact checkboxes + free-text).
- Soft recipient options from customer primary email + `customer_contacts`.
- Emailing a **draft** invoice/quote also marks it sent (same side-effects as Mark sent). Mark sent remains status-only without email.

## Behaviour highlights

- Quote accept → convert copies lines to draft invoice (`accepted` only).
- One invoice per appointment (generate from completed appointments).
- Draft/sent invoice edit UI includes discount code selection (same options as create).
- Invoice paid → release held provider payments.
- Exports: `GET /invoices/export?format=csv|xero|quickbooks|sage`.
- Profit = paid invoice totals − paid provider payouts (tips excluded).

## Permissions

Editor+ create/read/update; owner/admin delete; staff/customer/provider forbidden. Email uses update ability.

## Tests

`laravel/tests/Feature/Domains/Invoices/` — includes `InvoiceDocumentEmailTest` (Mail::fake, PDF download, template settings, staff denial).
