This commit is contained in:
gsinghpal
2026-04-26 15:05:17 -04:00
parent 160198edb1
commit d9f58b9851
110 changed files with 6210 additions and 1182 deletions

View File

@@ -374,8 +374,13 @@ rewrite code as new requirements surface. Each sub-project has its own design do
| 6 | Contact Profiles & Communication Routing (per-contact flags + per-location routing + global contact; single resolver helper) | **Shipped 2026-04-22** | client transcript A/B/C |
| 7 | IoT tuning (per-sensor polling interval + ingest rate-limit; entech seeded with 25 tanks / 50 sensors) | **Shipped 2026-04-22** | client transcript D |
| 8 | Receiving / Inspection / QC flow restructure (fp.receiving = box count only; new fp.racking.inspection per MO; WO soft gate; delivery box-parity warning) | **Shipped 2026-04-22** | client transcript E |
| 9 | Process variants per part + persistent draft order wizard + tax per line + payment terms wired + chatter + nicer breadcrumbs across plating models | **Shipped 2026-04-26** | various wizard/UX |
| 10 | Quote → Direct Order promotion (won quotes consolidate onto a single PO instead of spawning standalone 1-line SOs) | **Shipped 2026-04-26** | redundancy concern |
| 11 | **MRP cutout — bridge_mrp deletion + MRP module uninstall** (7-phase migration: relocate models, swap inherits, drop legacy FK columns, uninstall mrp + 10 cascade modules) | **Shipped 2026-04-26** | bridge_mrp removal |
| 12 | **Native Quality — full Odoo `quality_control` replacement + RMA + integration polish** | **In flight** (planned) | quality dependency removal |
| ∞ | First-off / last-off QC | Deferred | client transcript F |
| ∞ | VEC machine auto-ingest (Word-format thickness report from network-connected XRF; different machine from Fischerscope) | Deferred | client transcript G |
| ∞ | RMA customer portal submission | Deferred (Sub 12 phase 2) | follow-on to Sub 12 |
### Sub 2 Locked Decisions (2026-04-21)
@@ -435,3 +440,274 @@ rewrite code as new requirements surface. Each sub-project has its own design do
3. Read the corresponding spec in `docs/superpowers/specs/YYYY-MM-DD-sub<N>-*-design.md`.
4. Read the implementation plan if one exists.
5. Continue from the next un-checked step.
---
## Sub 11 — MRP Cutout (shipped 2026-04-26)
The Odoo `mrp` module + 10 cascade dependents have been **uninstalled**. `fusion_plating_bridge_mrp` is gone. The plating shop runs entirely on `fp.job` / `fp.job.step`. Document this so a fresh session doesn't try to re-add MRP refs.
### Final state
- **0 rows** in `mrp_production`, `mrp_workorder`, `mrp_workcenter`
- **205+** `fp.job` rows, **1,800+** `fp.job.step` rows in production
- 0 custom-table FKs to MRP
- Modules uninstalled: `mrp`, `mrp_workorder`, `mrp_account`, `sale_mrp`, `purchase_mrp`, `quality_mrp`, `quality_mrp_workorder`, `project_mrp*`, `fusion_manufacturing`, `fusion_plating_bridge_mrp`
### Where things ended up after Sub 11
| Model / asset | Old home | New home |
|---|---|---|
| `fp.work.role`, `fp.operator.proficiency`, `hr.employee` shop-roles, `fusion.plating.process.node.x_fc_work_role_id` | `fusion_plating_bridge_mrp` | `fusion_plating` (core) |
| `fp.qc.checklist.template` (+line) | `fusion_plating_bridge_mrp` | `fusion_plating_quality` |
| `fusion.plating.quality.check` (+line) | `fusion_plating_bridge_mrp` | `fusion_plating_quality` |
| `fp.thickness.reading.quality_check_id` link + `auto_extracted` | `fusion_plating_bridge_mrp` | `fusion_plating_quality` |
| `res.partner.x_fc_requires_qc` + `x_fc_qc_template_id` | `fusion_plating_bridge_mrp` | `fusion_plating_quality` |
| `fp.job.consumption` | `fusion_plating_bridge_mrp` | `fusion_plating_jobs` |
| `sale.order.x_fc_workflow_stage` + `x_fc_assigned_manager_id` + workflow buttons | `fusion_plating_bridge_mrp` | `fusion_plating_jobs` |
| QC tablet OWL (`fp_qc_checklist.js/.xml/.scss`) + `/fp/qc/*` controller | `fusion_plating_bridge_mrp` | `fusion_plating_quality` |
| Production Priorities kanban | `fusion_plating_bridge_mrp` (mrp.workorder) | `fusion_plating_jobs` (fp.job.step) |
### Hard rules going forward
1. **Never re-introduce `'mrp'` as a manifest dep.** Use `fp.job` for jobs, `fp.job.step` for operations.
2. **`x_fc_job_id` is the canonical job link**, not `production_id`. Drop legacy MO refs as you find them.
3. **`fusion_plating_quality` depends on `fusion_plating_shopfloor`** for SCSS tokens (`$fp-page`, `$fp-card`, `$fp-accent`). Don't strip that dep — the QC tablet bundle breaks without it.
4. **The QC tablet OWL template namespace is `fusion_plating_quality.FpQcChecklist`** (was `fusion_plating_bridge_mrp.FpQcChecklist`). Don't rename back.
---
## Sub 12 — Native Quality Module (in flight, ~4 working days)
**Goal**: Build a complete native quality stack matching Odoo `quality_control` functionality plus plating-specific extensions (RMA, CAPA effectiveness, holds, 8D reports), with **zero dependency** on Odoo's `quality` / `quality_control`. After Sub 12 lands, those modules + `fusion_plating_bridge_quality` get uninstalled.
### Module choice
**Enrich `fusion_plating_quality`** — no new modules. Existing module already owns NCR / CAPA / Hold / Check / Calibration / AVL / FAIR / Audit / Doc Control / Customer Spec / Contract Review.
### Locked decisions (don't re-ask in fresh session)
| Q | Decision |
|---|---|
| RMA portal submission | **Deferred to phase 2.** Internal-only RMA in Sub 12. |
| 8D format | **Full 8D** (D1D8 sections in the combined NCR + CAPA PDF). |
| Quality Dashboard | **5 tabs** (Holds / Checks / NCRs / CAPAs / RMAs) in one client action with a summary header that totals open + overdue across all five. |
| Auto-NCR + auto-Hold on RMA receive | **Automatic**, with a manager-only "skip this RMA's auto-spawn" toggle on the RMA record. |
| Auto-CAPA on NCR closure | **Automatic when severity in (high, critical)**, with a manager-only override on the NCR. |
| Quality team model | Build a dedicated `fp.quality.team` rather than reusing `res.groups`. Teams need their own kanban grouping + per-team escalation chains, which groups don't model well. |
| Stage model vs. state field on NCR | **Both.** Keep the existing `state` Selection (used by code paths). Add a parallel `stage_id` Many2one to `fp.quality.alert.stage` for the kanban draggable view. Computed bidirectional sync (stage ↔ state). |
| Trigger-based quality.point | Build a new `fp.quality.point` model. Trigger types: `manual`, `receiving_done`, `job_step_done`, `job_done`. Existing `fp.qc.checklist.template` STAYS — it's the *template* a point fires; the point is the *trigger rule*. |
| RMA back-link to original SO line | Required field. Always carry the original SO line so cert / part / coating context follows the return. |
| Module choice (one or many) | **Single module** — enrich `fusion_plating_quality`. |
### Phase A — RMA model (~1 day)
**File**: `fusion_plating_quality/models/fp_rma.py`
#### Model: `fusion.plating.rma`
| Field | Type | Notes |
|---|---|---|
| `name` | Char | Sequence `RMA/YYYY/NNNN` |
| `partner_id` | M2O `res.partner` | Required |
| `sale_order_id` | M2O `sale.order` | The original order being returned |
| `sale_order_line_ids` | M2M `sale.order.line` | Specific lines being returned (subset of the SO) |
| `original_job_ids` | M2O `fp.job` (compute from SO lines) | For navigation only |
| `state` | Selection | `draft / authorised / shipped_to_us / received / triaged / resolving / resolved / closed / cancelled` |
| `trigger_source` | Selection | `customer_complaint / qc_fail_post_ship / inspection_post_delivery / other` |
| `severity` | Selection | `low / medium / high / critical` |
| `complaint_description` | Html | What the customer reported |
| `triage_findings` | Html | What we found on inspection |
| `resolution_type` | Selection | `replace / rework / refund / scrap` |
| `resolution_notes` | Html | Free-form notes on the chosen path |
| `replacement_job_id` | M2O `fp.job` | When replace/rework — the new job created |
| `refund_invoice_id` | M2O `account.move` | When refund — the credit note |
| `inbound_receiving_id` | M2O `fp.receiving` | The receiving record auto-created when carrier delivers |
| `inbound_picking_id` | M2O `stock.picking` | Optional — if a stock.picking is also created |
| `linked_ncr_ids` | O2M `fusion.plating.ncr` (inverse `rma_id`) | NCRs spawned from this RMA |
| `linked_capa_ids` | O2M `fusion.plating.capa` (related via NCRs) | Read-only roll-up |
| `linked_hold_ids` | O2M `fusion.plating.quality.hold` (inverse `rma_id`) | Holds placed on returned parts |
| `qty_returned` | Integer | Total units customer is returning |
| `qty_received` | Integer | Counted on receipt |
| `customer_tracking` | Char | Customer's outbound tracking # |
| `our_tracking` | Char | Our return-to-shop tracking # |
| `carrier_id` | M2O `delivery.carrier` | Optional |
| `qr_code` | Binary (compute) | QR encoding `/fp/rma/<id>` for the authorisation PDF |
| `auto_spawn_ncr` | Boolean | Default True. Manager can toggle off before saving. |
| `auto_spawn_hold` | Boolean | Default True. |
| `tag_ids` | M2M `fp.quality.tag` | (Sub 12 Phase B) |
| `reason_id` | M2O `fp.quality.reason` | (Sub 12 Phase B) |
| `team_id` | M2O `fp.quality.team` | (Sub 12 Phase B) |
| `chatter` | mail.thread | mandatory |
#### Lifecycle hooks
- **`action_authorise`**: state `draft → authorised`. Generate the RMA authorisation PDF + email link/QR to customer (using `fp.notification.template` if installed; falls back to standard mail.template).
- **`action_mark_shipped_to_us`**: customer-driven; updates state when carrier scan logged.
- **On `fp.receiving` create with `rma_id` set**: state `→ received`. If `auto_spawn_ncr`, create an `fusion.plating.ncr` pre-filled (description, severity, customer, parent SO line). If `auto_spawn_hold`, create `fusion.plating.quality.hold` for the returned qty.
- **`action_triage_complete`**: state `→ triaged`. Requires `resolution_type` set.
- **`action_resolve`**: state `→ resolved`. Triggers resolution-specific actions:
- `replace` → spawn new `fp.job` cloned from original
- `rework` → spawn new `fp.job` referencing the returned units (linked to inbound `fp.receiving`)
- `refund` → open `account.move.refund` wizard, link result to `refund_invoice_id`
- `scrap` → create `fp.job.consumption` row tagged 'rma_scrap' + post chatter
- **`action_close`**: state `→ closed`. Locks editing.
- **`action_cancel`**: any state → `cancelled` (manager only).
#### Smart buttons
RMA form gets buttons to: original SO, original Jobs, inbound Receiving, replacement Job, refund Invoice, NCRs (count), CAPAs (count), Holds (count). Per-target button visibility based on resolution_type / state.
#### Sequence
Create `ir.sequence` `fp.rma` with prefix `RMA/%(year)s/`, padding 4. Data file `fp_rma_sequence.xml`.
#### Reports
`fusion_plating_reports/report/report_fp_rma_authorisation.xml` — single-page customer-facing PDF with QR code. Branded "EN Technologies".
### Phase B — Categorisation & kanban infra (~half day)
**Files**: `fusion_plating_quality/models/fp_quality_tag.py`, `fp_quality_reason.py`, `fp_quality_team.py`, `fp_quality_alert_stage.py`
#### `fp.quality.tag`
- `name` (Char, required, translate)
- `color` (Integer, kanban color)
- `active` (Boolean)
- Reused by NCR / CAPA / Hold / RMA / Check via `M2M tag_ids`
#### `fp.quality.reason`
- `name`, `description`, `category` (selection: `process / supplier / equipment / human / material / other`)
- Curated reason library so root-cause classification is consistent
#### `fp.quality.team`
- `name`, `lead_user_id` (M2O res.users), `member_ids` (M2M res.users)
- `escalation_user_id` (manager who gets notified on missed deadlines)
- Used by NCR / RMA — primary owner team
#### `fp.quality.alert.stage`
- `name`, `sequence`, `fold` (Boolean — collapsed-by-default in kanban)
- Default stages seeded: New / Investigating / Containment / Disposition / Awaiting Sign-off / Closed / Cancelled
- Add `stage_id = fields.Many2one('fp.quality.alert.stage')` to `fusion.plating.ncr` AND `fusion.plating.rma`. Map state ↔ stage_id via `_inverse_*` so legacy code paths keep working.
#### Apply tag/reason/team M2M/M2O fields to: NCR, CAPA, Hold, Check, RMA
Each model gets `tag_ids`, `reason_id`, `team_id`. NCR + RMA additionally get `stage_id`.
### Phase C — Trigger-based quality points (~half day)
**File**: `fusion_plating_quality/models/fp_quality_point.py`
#### `fp.quality.point`
- `name`, `active`, `description`
- `trigger_type` (Selection): `manual / receiving_done / job_confirmed / job_step_done / job_done / so_confirmed`
- Filters (any combination): `partner_ids` (M2M), `part_catalog_ids` (M2M), `coating_config_ids` (M2M), `step_kind` (Selection — wet/bake/inspect/etc.)
- `template_id` (M2O `fp.qc.checklist.template`) — required, the checks to spawn
- `assignee_user_id` (M2O `res.users`) — optional default inspector
- Fires `_spawn_check_for(<source_record>)` which creates a `fusion.plating.quality.check` from the template + binds it to the source via `job_id` or `step_id`.
#### Hooks (already partly in place — extend)
- `fp.receiving.write` hook (existing): when state flips to `closed`, walk all `fp.quality.point` with trigger `receiving_done` matching the receiving's partner/parts → spawn checks.
- `fp.job.action_confirm` hook (existing — currently calls `_fp_create_qc_check_if_needed`): replace with quality.point lookup. Keep the existing partner-template fallback as a default point seeded by `fp_qc_data.xml`.
- `fp.job.button_mark_done`: trigger `job_done` points.
- `fp.job.step.button_finish`: trigger `job_step_done` points.
### Phase D — Integration polish (~1 day)
1. **`fp.job` form smart-button row**: add `Holds`, `Checks`, `NCRs`, `CAPAs`, `RMAs` buttons with badge counts. Always-visible (zero is OK).
2. **`sale.order` form smart-button row**: same five, rolled up across all linked jobs.
3. **`res.partner` form**: customer-level "Quality History" smart button that opens a kanban filtered to that partner across all 5 record types.
4. **One-click cross-creation**:
- Hold form → `Open NCR` button — pre-fills NCR with hold's part / customer / quantity / linked job.
- NCR form → `Spawn CAPA` button — visible when state ∈ {disposition, closed} and severity ≥ medium.
- CAPA form → `Verify Effectiveness` button — schedules a follow-up check on the originating NCR.
5. **Unified Quality Dashboard** (`fp_quality_dashboard` client action):
- 5 tabs: Holds / Checks / NCRs / CAPAs / RMAs
- Each tab is a kanban grouped by `stage_id` (NCRs/RMAs) or `state` (Holds/Checks/CAPAs)
- Header summary card: open count + overdue count across all 5 types
- Filters: my team / my customer / overdue / high-severity
- Menu: Plating → Quality → Dashboard
6. **CAPA closure-loop linkage**: when CAPA effectiveness verification fails, auto-spawn a new NCR linked back to the original. Closes the loop "we said we fixed it but it happened again."
### Phase E — Reports (~half day)
**Files**: `fusion_plating_reports/report/report_fp_rma_authorisation.xml`, `report_fp_8d.xml`, `report_fp_quality_monthly.xml`
1. **RMA Authorisation PDF**: single-page customer-facing. Header with our logo + customer info, RMA number, parts listed (table), return-to address, QR code linking to `/fp/rma/<id>` for status tracking, carrier instructions.
2. **8D Report (NCR + CAPA combined)**:
- D1: Team (from `team_id` + member_ids)
- D2: Problem description (NCR description + scope)
- D3: Containment (NCR containment narrative)
- D4: Root cause analysis (CAPA root_cause + reason_id)
- D5: Permanent corrective action (CAPA action_plan)
- D6: Implement & verify (CAPA implementation_date + verification_evidence)
- D7: Prevent recurrence (CAPA preventive_actions)
- D8: Congratulate the team (CAPA closure notes + team sign-offs)
- Auto-renders when both NCR and CAPA exist; degraded mode if CAPA missing.
3. **Monthly Quality Summary** (`fp_quality_monthly` report):
- Counts by record type / severity / customer / month
- Overdue ageing buckets
- CAPA effectiveness rate (verified / total closed)
- Repeat-customer-issue flag (>2 NCRs same customer in 90 days)
- Run via cron monthly + on-demand from dashboard.
### Phase F — Test + verify (~half day)
End-to-end smoke flow on a fresh DB:
1. Customer reports issue → create RMA → authorise → email PDF
2. Customer ships → carrier delivers → `fp.receiving` auto-created → RMA receives → NCR + Hold auto-spawn
3. QA triages NCR → finds root cause → spawns CAPA (auto via severity rule)
4. CAPA assigned to engineering → action plan written → implemented → effectiveness check scheduled
5. Effectiveness verified → CAPA closes → NCR closes → RMA resolves (rework path) → replacement job created from original → ships → CoC issued → invoice
6. Run 8D report on the closed NCR/CAPA pair
7. Verify dashboard counts update at every state transition
8. Confirm legacy NCR/CAPA/Hold/Check forms still work (no regressions)
9. ACL drilldown: operator sees what they should, supervisor more, manager all
### Phase G — Drop Odoo quality cascade (~30 min)
Pre-conditions: Phases AF all merged + smoke-tested.
1. Strip the three custom fields from `fusion.plating.ncr` (`x_fc_quality_alert_id`, `x_fc_quality_alert_synced`, `x_fc_auto_sync` — added by bridge_quality)
2. Remove `fusion_plating_bridge_quality` from `/mnt/extra-addons/custom/`
3. SQL: `UPDATE ir_module_module SET state='to remove' WHERE name IN ('fusion_plating_bridge_quality', 'quality_control', 'quality') AND state='installed';`
4. Restart odoo → cascade uninstall fires
5. ALTER TABLE drop the three NCR columns
6. (Optional) move `/mnt/extra-addons/inventory_manufacturing/quality{,_control}/` out of the path so they can't auto-reinstall
### Server / deployment notes (entech)
- LXC 111 on pve-worker5, native odoo (apt), DB `admin`, addons path `/mnt/extra-addons/custom/`
- Update flow:
```bash
ssh pve-worker5 "pct exec 111 -- bash -c 'systemctl stop odoo && \
su - odoo -s /bin/bash -c \"/usr/bin/odoo -c /etc/odoo/odoo.conf -d admin \
-u fusion_plating_quality --stop-after-init\" && systemctl start odoo'"
```
- File copy:
```bash
cat LOCAL | ssh pve-worker5 "pct exec 111 -- bash -c 'cat > REMOTE'"
```
- Asset cache bust: `DELETE FROM ir_attachment WHERE url LIKE '/web/assets/%';`
- Always bump module version in `__manifest__.py` for migrations to fire (current `fusion_plating_quality`: `19.0.3.0.0`; bump to `19.0.4.0.0` for Sub 12).
### Build order (executable checklist for fresh session)
1. Read this Sub 12 section in full + the Sub 11 section above (for context on what's already native).
2. Bump `fusion_plating_quality/__manifest__.py` version to `19.0.4.0.0`.
3. Phase A — RMA: create `fp_rma.py` model + `fp_rma_views.xml` + `fp_rma_sequence.xml` + ACL rows + add to `__manifest__.py` data list.
4. Phase A migration: not needed (new model, fresh table).
5. Phase B — categorisation: create the 4 small models + their views + ACL. Add `tag_ids / reason_id / team_id` M2M/M2O to NCR, CAPA, Hold, Check, RMA. Add `stage_id` to NCR + RMA.
6. Phase B data: seed default stages + a few starter tags/reasons/teams in `fp_quality_categorisation_data.xml`.
7. Phase C — `fp.quality.point` model + view + ACL + the 4 trigger hooks (in `fp.receiving`, `fp.job.action_confirm`, `fp.job.button_mark_done`, `fp.job.step.button_finish`).
8. Phase D — smart buttons on `fp.job`, `sale.order`, `res.partner`. Cross-creation buttons. Dashboard client action.
9. Phase E — three QWeb reports.
10. Phase F — manual smoke test + ACL drilldown + screenshot the dashboard.
11. Deploy each phase as it lands (don't batch — easier to roll back). Bump version each time.
12. Phase G runs LAST, only after confirmation that AF work end-to-end.
### Things to NOT do
- **Don't add `'quality'` or `'quality_control'` to any manifest dep.** They will be uninstalled by Phase G.
- **Don't import from `odoo.addons.quality.*`.** Use only native models.
- **Don't put RMA in a new module.** It belongs in `fusion_plating_quality`.
- **Don't break the existing QC tablet OWL.** Its template namespace is `fusion_plating_quality.FpQcChecklist`, endpoints are `/fp/qc/*`, and `fusion_plating_quality` depends on `fusion_plating_shopfloor` for SCSS tokens.
- **Don't re-introduce `production_id` references anywhere.** Use `job_id` / `x_fc_job_id`. MRP is gone.
- **Don't forget `rma_id` inverse field on NCR + Hold** — those One2many fields on RMA need an inverse Many2one on the linked model.
### Status check before starting (run this first in the fresh session)
```sql
-- Should show 4: NCR, CAPA, Hold, Check (Sub 12 adds RMA = 5)
SELECT model FROM ir_model WHERE model LIKE 'fusion.plating.%' AND model SIMILAR TO '%(ncr|capa|hold|check|rma)%';
-- Should show 'fusion_plating_quality_bridge_quality_control' state — likely 'installed' until Phase G
SELECT name, state FROM ir_module_module WHERE name LIKE 'quality%' OR name LIKE 'fusion_plating_bridge_quality';
-- Confirm MRP is gone (Sub 11)
SELECT name, state FROM ir_module_module WHERE name = 'mrp'; -- expect 'uninstalled'
-- Live row counts so you know what survives
SELECT 'ncr' AS m, count(*) FROM fusion_plating_ncr
UNION ALL SELECT 'capa', count(*) FROM fusion_plating_capa
UNION ALL SELECT 'hold', count(*) FROM fusion_plating_quality_hold
UNION ALL SELECT 'check', count(*) FROM fusion_plating_quality_check;
```