---
name: evolution_job_optional_extras
description: "Optional extras can be added/removed on a job after quote import; jobs.price is written last by getForecastedRevenue(), not setPrice()"
metadata: 
  node_type: memory
  type: project
  originSessionId: 4b271d60-ce1a-4319-839e-a6a20336745d
  modified: 2026-07-27T06:36:24.299Z
---

Quote **Optional Extra** sections (`quoteSections.type='Optional Extra'` + `.accepted`) can now be ticked on/off a job *after* the quote is imported — job **Quotes** tab cell → `jobQuoteOptions()` modal → `jobeditsave.php` handlers `getJobQuoteOptions` / `addJobQuoteOption` / `removeJobQuoteOption` (shipped 2026-07-27; docs `docs/projects/optional-extras.php`, prod release note id 146 `status=0`).

**Key facts / gotchas:**
- `jobInventory` has **no** `sectionId` — the only join back to a section is `jobInventory.referenceId = quoteitems.id → quoteitems.sectionId`. `jobInventory.reference` is a truncated varchar(25) and not unique.
- Remove is a **soft delete** (`status='0'`) so re-adding *reinstates* the same rows; add inserts parents before children via `getParentIDs()`.
- Removal is blocked when lines have progress/complete/dispatched, an `invoiceid`, an `mfshoporders.jobinvid` or a `requisitionitems.jobitemid` — checked server-side too, not just in the UI.
- **`jobs.price` / `estimated_revenue` is last written by `job::getForecastedRevenue()` + `updateJobInvoicingFields()`, which `jobedit.inc` calls on every page load** — NOT by `job::setPrice()`. setPrice deducted un-accepted extras correctly but its value was clobbered on the next page render. getForecastedRevenue now deducts them too (both writers must stay in step). See [[evolution_invoice_billto_vs_project_owner]] for other job-header vs line-level divergences.
- The quote screen's `inv_option[]` checkboxes were doubly dead (empty `value`, never submitted) — now wired into `createInvoice`, and disabled once the quote is on a job so the job's Quotes tab owns acceptance.
- `invoice::importQuote()`'s `sections` line-item format billed declined extras; only reachable from jobeditsave.php's Invoice-Job flow (`lineMethod`). `job::importQuote()` is dead code.
