# Sale Order + Job Quality Smart Buttons — hide-at-zero + order-scoped counts **Date:** 2026-06-04 **Modules:** `fusion_plating_quality`, `fusion_plating_jobs` **Status:** approved (brainstorming sign-off) ## Problem The `sale.order` form shows eight Fusion Plating smart buttons: Receiving, WO, Certificates, Holds, Checks, NCRs, CAPAs, RMAs. On a typical order only three carry data (Receiving / WO / Certificates) yet six of the eight render permanently — five quality buttons (Holds / Checks / NCRs / CAPAs / RMAs) and the WO button all show even at a count of zero. The row reads as noise. Two of those counts are also **wrong on an order**: - **NCRs** counts the *entire customer's* NCR history (`customer_partner_id == partner`), not this order's. A repeat customer's brand-new order shows "NCRs 5". - **CAPAs** counts the CAPAs under those customer-wide NCRs — same over-count. This contradicts the module's own documented smart-button convention ("don't add a button that always shows zero… NCRs/RMAs visible only when present"). The Sub-12 Phase D plan that introduced these buttons chose "always visible (zero is OK)"; this spec reverts to the convention. The identical button row + identical over-count exists on the `fp.job` form and is fixed in the same change. ## Decision 1. **Hide every quality button when its count is 0**, on both the `sale.order` and `fp.job` forms. Also hide the **WO** button at 0. (Receiving and Certificates already hide at 0 — untouched.) 2. **Re-scope the NCR and CAPA counts to the order/job**, dropping the customer-wide union. Use only the real order-linked paths. ### Order-scoped NCR set There is no direct `ncr.sale_order_id` or `ncr.job_id` field. The only honest paths from an order to its NCRs (confirmed by model inspection) are: - **RMA path:** SO → its RMAs (`rma.sale_order_id`) → NCRs (`ncr.rma_id`). - **Hold path:** SO → its jobs (`fp.job.sale_order_id`) → holds (`hold.job_id`) → the NCR a hold spawned (`hold.ncr_id`). NCR set = union of those two. CAPA set = CAPAs whose `ncr_id` is in that set. For the `fp.job` form the same definition applies, narrowed to the one job: the job's SO's RMAs' NCRs, plus *this job's* holds' NCRs. Trade-off accepted: an NCR raised with neither an RMA nor a hold link (e.g. a QA team logs one directly against the customer) no longer appears on any order or job. That is correct — such an NCR has no order/job linkage to honestly attach it to, and surfacing it on every one of the customer's orders was the bug. ## Changes ### `fusion_plating_quality` - `models/fp_quality_smart_buttons.py` - Add `sale.order._fp_quality_ncr_ids()` and `fp.job._fp_quality_ncr_ids()` helpers returning the order/job-scoped NCR id list (single source of truth). - Rewrite both `_compute_*` methods to set the NCR count from the helper and the CAPA count from `[('ncr_id', 'in', )]`. Holds / Checks / RMAs counts are already correctly scoped — leave them. - Point `action_view_fp_ncrs`, `action_view_fp_ncrs_so`, and both `action_view_fp_capas` at the helper-derived ids so each opened list matches its badge. - Narrow `fp.job.action_view_fp_rmas` from SO-OR-partner to SO-only so the RMA list matches its (already SO-scoped) badge count (caught in review — the SO form's RMA button already agreed). - `views/fp_quality_smart_button_views.xml` — add `invisible=" == 0"` to the five SO quality buttons. - `__manifest__.py` — version `19.0.8.1.0` → `19.0.8.2.0`. ### `fusion_plating_jobs` - `views/fp_job_quality_buttons.xml` — add `invisible=" == 0"` to the five job-form quality buttons. - `views/sale_order_views.xml` — add `invisible="x_fc_fp_job_count == 0"` to the WO smart button; update the now-stale "always visible" comment. - `__manifest__.py` — version `19.0.12.4.0` → `19.0.12.5.0`. ### Docs - `fusion_plating/CLAUDE.md` — short note in the smart-button section recording that the SO/job quality buttons are hide-at-zero with order-scoped NCR/CAPA counts as of 2026-06-04 (reconciling the Sub-12 "always visible" record). ## Out of scope - The `res.partner` "Quality History" button stays as-is. It is customer-wide *by design*, and the user opted not to touch it. - No schema changes, no migration — pure view attributes + non-stored compute logic over existing fields. ## Verification The plating modules cannot be installed on the local Community dev DB (enterprise deps). Verification is: 1. Static: `pyflakes` on the edited `.py`; `lxml` parse on each edited `.xml`. 2. Behavioural (read-only, on an entech clone/shell): for a sample SO and job, confirm the new helper returns only RMA-/hold-linked NCRs and that the counts match, with `env.cr.rollback()` at the end. 3. Deploy to entech via the revert-on-failure guard only after the above pass and with the owner's go-ahead (live client box).