714 lines
52 KiB
Markdown
714 lines
52 KiB
Markdown
# Fusion Plating — Claude Code Instructions
|
||
|
||
## Project
|
||
Fusion Plating is a multi-module Odoo 19 ERP for electroless nickel plating and metal finishing shops. Built by Nexa Systems for EN Technologies (the client). Replaces Steelhead Software.
|
||
|
||
## Module Structure (30 modules)
|
||
```
|
||
fusion_plating/ — Core: facilities, process types, tanks, baths, chemistry, recipes
|
||
fusion_plating_batch/ — Rack/barrel batch tracking (FpBatch, FpBatchChemistry)
|
||
fusion_plating_kpi/ — KPI definitions, daily auto-compute, dashboard views
|
||
fusion_plating_configurator/ — Quotation configurator, pricing engine, part catalog, 3D viewer
|
||
fusion_plating_receiving/ — Parts receiving, inspection, damage logging
|
||
fusion_plating_invoicing/ — Invoice strategies (deposit/progress/net/COD), account holds
|
||
fusion_plating_certificates/ — Certificate registry (CoC, thickness reports), Fischerscope data
|
||
fusion_plating_notifications/ — Auto-email engine, notification templates, audit log
|
||
fusion_plating_shopfloor/ — Tablet UI, plant overview kanban, process tree visualization
|
||
fusion_plating_portal/ — Customer portal + self-service configurator wizard
|
||
fusion_plating_reports/ — PDF reports (WO margin, discharge sample, CoC, etc.)
|
||
fusion_plating_compliance/ — Compliance framework, jurisdictions
|
||
fusion_plating_compliance_on/ — Ontario compliance reference data (data-only, no menus)
|
||
fusion_plating_compliance_tor/ — Toronto bylaw discharge limits (data-only, no menus)
|
||
fusion_plating_aerospace/ — AS9100 / Nadcap
|
||
fusion_plating_nuclear/ — CSA N299 / CNSC
|
||
fusion_plating_cgp/ — Controlled Goods Program
|
||
fusion_plating_safety/ — SDS, WHMIS, JHSC
|
||
fusion_plating_quality/ — QMS (NCR, CAPA, calibration)
|
||
fusion_plating_logistics/ — Pickup & delivery, chain of custody
|
||
fusion_plating_culture/ — Values / fundamentals (⚠️ RETIRED — do NOT auto-install)
|
||
fusion_plating_bridge_mrp/ — MRP integration (recipe→WO, portal job, work order priorities)
|
||
fusion_plating_bridge_sign/ — Digital signatures
|
||
fusion_plating_bridge_quality/ — Quality bridge
|
||
fusion_plating_bridge_documents/ — Odoo Documents integration (NCR, CAPA, FAIR, Doc Control)
|
||
fusion_plating_process_en/ — Electroless nickel process pack
|
||
fusion_plating_process_chrome/ — Chrome process pack
|
||
fusion_plating_process_anodize/ — Anodizing process pack
|
||
fusion_plating_process_black_oxide/ — Black oxide process pack
|
||
fusion_tasks/ — Local delivery dispatch (GPS, maps, driver scheduling)
|
||
```
|
||
|
||
## Menu Structure (Plating App)
|
||
The Plating app (`menu_fp_root`, seq 46) has these top-level menus:
|
||
|
||
| Seq | Menu | Module | Children |
|
||
|-----|------|--------|----------|
|
||
| 3 | KPIs | fusion_plating_kpi | KPIs, KPI History, Production/Quality/Finance dashboards |
|
||
| 5 | Sales | fusion_plating_configurator + portal | Quotations, Sale Orders, Customers, Part Catalog, Quote Requests, Portal Jobs |
|
||
| 8 | Configurator | fusion_plating_configurator | New Quote, Coating Configs, Pricing Rules, Treatments |
|
||
| 12 | Shop Floor | fusion_plating_shopfloor | Plant Overview, Tablet Station, Bake Windows, First-Piece Gates |
|
||
| 15 | Receiving | fusion_plating_receiving | All Receiving, Pending Inspection, Discrepancies |
|
||
| 18 | Operations | fusion_plating (core) | Process Recipes, Production Priorities (bridge_mrp), Batches (batch), Baths, Chemistry Logs, Tanks |
|
||
| 25 | Certificates | fusion_plating_certificates | All, CoC, Thickness Reports |
|
||
| 30 | Quality | fusion_plating_quality | Holds, NCRs, CAPAs, FAIR, Audits, Doc Control |
|
||
| 40 | Compliance | fusion_plating_compliance | Permits, Discharge, Waste, Calendar, Spills, Config |
|
||
| 45 | Safety | fusion_plating_safety | SDS, Training, Exposure, JHSC, Incidents, PPE |
|
||
| 50 | Logistics | fusion_plating_logistics + fusion_tasks | Pickups, Deliveries, Routes, CoC, POD, Field Tasks, Task Map, Task Calendar |
|
||
| 60 | Aerospace | fusion_plating_aerospace | AS9100, Nadcap, Counterfeit, Config Items, Risk |
|
||
| 65 | Nuclear | fusion_plating_nuclear | Program, ITP, 10CFR21, Pedigree, CNSC |
|
||
| 70 | CGP | fusion_plating_cgp | Registration, AI, PSA, Visitors, Goods, Shipments, Security, Access Log |
|
||
| ~~80~~ | ~~Culture~~ | ~~fusion_plating_culture~~ | ~~Values, Recognitions~~ **— RETIRED, uninstalled on entech, code kept in repo only** |
|
||
| 90 | Configuration | fusion_plating (core) + many | Facilities, Work Centres, Process Categories/Types, Bath Params, Stations, Ovens, Invoice Strategy, Account Holds, Training Types, Chemicals, Notification Templates/Log, Calibration, Specs, AVL, Value Sets/Rotations, N299 Levels, Vehicles |
|
||
|
||
**Field Service** (`fusion_tasks`) also has its own standalone root app (seq 45) with Map View, Tasks, Calendar, Configuration. The same task actions are also accessible under Plating > Logistics.
|
||
|
||
**Key rule**: Sales menu is unified in `fusion_plating_configurator`. Portal module adds Quote Requests + Portal Jobs as children (referencing `fusion_plating_configurator.menu_fp_sales`). Do NOT create a separate Sales menu in portal.
|
||
|
||
## Retired / Do-Not-Install Modules
|
||
|
||
These modules have **source code in this repo** but are **intentionally NOT installed on entech** (the client's live Odoo). Do not:
|
||
- Include them in any `-i` or `-u` sequence that installs modules automatically.
|
||
- Add them as a `depends` target from any other Fusion Plating module.
|
||
- Re-sync their folders to `/mnt/extra-addons/custom/` on entech.
|
||
- Recommend installing them to the user without explicit confirmation.
|
||
|
||
| Module | State on entech | Retired because | What to do if revisiting |
|
||
|--------|-----------------|-----------------|--------------------------|
|
||
| `fusion_plating_culture` | `state=uninstalled`, dir removed from entech disk | Soft people-ops feature (peer kudos / "Fundamental of the Week"); zero data entered; not a client priority. Top-level "Culture" menu confused operators. | Ask the client whether they want it before reinstalling. If yes: re-sync folder + `-i fusion_plating_culture` + seed a value set. |
|
||
| `fusion_plating_sensors` | deleted entirely (not in repo anymore) | Duplicated `fusion_plating_iot`'s scope but with no working alerting logic. Its valuables (sensor_type taxonomy, dashboard, location flexibility) were ported into `fusion_iot/fusion_plating_iot/`. | N/A — gone. Any new sensor work goes in `fusion_iot/fusion_plating_iot/`. |
|
||
|
||
## Critical Rules — Odoo 19
|
||
1. **NEVER code from memory** — Read reference files from the server first.
|
||
2. **Backend OWL**: `static template`, `static props = ["*"]`, standalone `rpc()` from `@web/core/network/rpc`. NOT `useService("rpc")`.
|
||
3. **HTTP routes**: `type="jsonrpc"` — NOT `type="json"` (deprecated in Odoo 19).
|
||
4. **Search views**: NO `group expand="0"`, NO `string` attribute on `<search>`, NO `<group string="...">` wrapper for group-by filters. Use bare `<group>` for group-by.
|
||
5. **res.config.settings**: Only boolean/integer/float/char/selection/many2one/datetime. NO Date fields.
|
||
6. **res.groups**: Use `privilege_id` (NOT `category_id`). `user_ids` is OK but the deprecated `users` alias is NOT. Always include `sequence` field.
|
||
7. **Field params**: `parent_path` does NOT accept `unaccent` parameter in Odoo 19.
|
||
8. **SCSS borders**: Use `$border-color` (SCSS variable) for card borders, NOT `color-mix()` in border shorthand — the SCSS compiler drops it. `color-mix()` works fine in `background-color`, `box-shadow`, etc.
|
||
9. **Theme awareness**: All colours must use CSS custom properties (`var(--bs-body-bg)`, `var(--bs-body-color)`, `var(--bs-border-color)`, `var(--bs-secondary-color)`, `var(--o-action)`). NO hardcoded hex. See `fusion_plating_shopfloor.scss` as the gold standard.
|
||
10. **XML comments**: No double-hyphens (`--`) inside `<!-- -->` comments — invalid XML, causes lxml parse error.
|
||
11. **XML data ordering**: Window actions must be defined BEFORE `<menuitem>` elements that reference them in the same file.
|
||
12. **Module install on new modules**: Use `--update=base` alongside `-i MODULE` to ensure Odoo rescans the addons path and finds the new module directory.
|
||
13. **Implied group cascade**: `implied_ids` on `res.groups` does NOT reliably propagate to users on module install. Always include `user_ids` to explicitly assign admin, or fix via SQL post-install.
|
||
|
||
## Naming
|
||
- **New custom models** (post-2026-04): `fp.*` prefix (e.g. `fp.part.catalog`, `fp.certificate`)
|
||
- **Existing custom models**: Keep `fusion.plating.*` (e.g. `fusion.plating.portal.job`, `fusion.plating.delivery`)
|
||
- **New fields on standard Odoo models**: `x_fc_*` prefix
|
||
- **Legacy fields**: `x_studio_*`
|
||
- Canadian English for all user-facing text
|
||
- SCSS class prefix: `o_fp_*` (shopfloor: `o_fp_po_*`, `o_fp_pt_*`; recipes: `o_fp_recipe_*`)
|
||
- Monetary fields: always pair with `currency_id` field on the same model
|
||
|
||
## Process Recipe System (NEW — v19.0.2.x)
|
||
**Model**: `fusion.plating.process.node` (in `fusion_plating` core)
|
||
- Hierarchical tree with `_parent_store = True`
|
||
- Node types: `recipe`, `sub_process`, `operation`, `step`
|
||
- Companion model: `fusion.plating.process.node.input` (operator inputs)
|
||
- `icon` is a Selection field (24 curated plating icons), NOT a Char
|
||
- Auto-icon: JS `guessIcon(name)` maps keywords → icons when adding nodes
|
||
- OWL tree editor: registered as `fp_recipe_tree_editor` client action
|
||
- Controller: `fusion_plating/controllers/recipe_controller.py` (7 endpoints)
|
||
- SCSS: `fusion_plating/static/src/scss/recipe_tree_editor.scss`
|
||
|
||
### Recipe Endpoints
|
||
```
|
||
POST /fp/recipe/tree — full nested tree for OWL editor
|
||
POST /fp/recipe/node/create — add child node
|
||
POST /fp/recipe/node/write — update fields
|
||
POST /fp/recipe/node/unlink — delete + cascade
|
||
POST /fp/recipe/node/reorder — bulk sequence update
|
||
POST /fp/recipe/node/move — change parent_id
|
||
POST /fp/recipe/duplicate — deep-copy recipe
|
||
```
|
||
|
||
### Steelhead Features Status
|
||
| Feature | Status |
|
||
|---------|--------|
|
||
| Hierarchical process tree | Done |
|
||
| Node types (recipe/sub/op/step) | Done |
|
||
| Auto-complete flag | Done |
|
||
| Customer visible flag | Done |
|
||
| Manual/automated flag | Done |
|
||
| Requires sign-off | Done |
|
||
| Opt In/Out (disabled/opt-in/opt-out) | Done |
|
||
| Icon picker | Done |
|
||
| Time tracking (created/updated with seconds) | Done |
|
||
| Operator inputs | Done |
|
||
| Description (rich text) | Done |
|
||
| File attachments (via mail.thread) | Done |
|
||
| OWL tree editor with drag-drop | Done |
|
||
| Tags | Not yet |
|
||
| Dashboard Transitions | Not yet |
|
||
| Treatment Groups / Choices | Not yet |
|
||
| Go To Node Options | Not yet |
|
||
| Spec Fields | Not yet |
|
||
|
||
### Client Recipes Created
|
||
- `ENP-ALUM-BASIC` — Electroless Nickel Plating Aluminium Basic (9 operations, 15 steps). Data file: `fusion_plating/data/fp_recipe_enp_alum_basic.xml`
|
||
|
||
## Plant Overview Dashboard
|
||
- OWL client action: `fp_plant_overview` in `fusion_plating_shopfloor`
|
||
- Kanban columns = work centres, cards = active `mrp.workorder` records
|
||
- Drag & drop between columns (writes `workcenter_id` on the work order)
|
||
- Endpoint: `POST /fp/shopfloor/plant_overview`
|
||
- Move endpoint: `POST /fp/shopfloor/plant_overview/move_card`
|
||
- Auto-refreshes every 30s
|
||
|
||
## Deployment
|
||
|
||
### odoo-entech (LXC 111 on pve-worker5)
|
||
- **Type**: Native Odoo (apt package, NOT Docker)
|
||
- **IP**: 10.200.1.26
|
||
- **DB**: `admin` (PostgreSQL local, user `odoo`)
|
||
- **Config**: `/etc/odoo/odoo.conf`
|
||
- **Addons**: `/mnt/extra-addons/custom/` (fusion_plating modules live here)
|
||
- **Service**: `systemctl {start|stop|restart} odoo`
|
||
- **Update command**:
|
||
```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 MODULE_NAME --stop-after-init\" && systemctl start odoo'"
|
||
```
|
||
- **Copy files**: `cat LOCAL_FILE | ssh pve-worker5 "pct exec 111 -- bash -c 'cat > /mnt/extra-addons/custom/REMOTE_PATH'"`
|
||
- **IMPORTANT**: Must pass `-c /etc/odoo/odoo.conf` or Odoo won't find the repackaged enterprise addons
|
||
|
||
### odoo-trial (VM 316 on pve-worker1)
|
||
- **Type**: Docker (container `odoo-trial-app`, db `odoo-trial-db`)
|
||
- **DB**: `trial` (user `odoo`)
|
||
- **Host addons path**: `/opt/odoo/custom-addons/` → mounts as `/mnt/extra-addons/` in Docker
|
||
- **Docker network**: `odoo_odoo-network`
|
||
- **Copy files** (base64 pipe through qm guest exec):
|
||
```bash
|
||
B64=$(base64 -w0 "LOCAL_FILE")
|
||
ssh pve-worker1 "qm guest exec 316 -- bash -c 'echo $B64 | base64 -d > /opt/odoo/custom-addons/REMOTE_PATH'"
|
||
```
|
||
- **Clear asset cache** (required after SCSS/JS changes):
|
||
```bash
|
||
ssh pve-worker1 "qm guest exec 316 -- bash -c \"docker exec odoo-trial-db psql -U odoo -d trial -c \\\"DELETE FROM ir_attachment WHERE url LIKE '%/web/assets/%';\\\"\""
|
||
```
|
||
- **Update command**:
|
||
```bash
|
||
ssh pve-worker1 "qm guest exec 316 -- bash -c 'docker stop odoo-trial-app && docker run --rm --network odoo_odoo-network -v odoo_odoo-data:/var/lib/odoo -v /opt/odoo/custom-addons:/mnt/extra-addons -v /opt/odoo/enterprise-addons:/mnt/enterprise-addons -v /opt/odoo/odoo.conf:/etc/odoo/odoo.conf odoo:19 odoo -d trial -u MODULE_NAME --stop-after-init && docker start odoo-trial-app'"
|
||
```
|
||
|
||
### Git Push
|
||
```bash
|
||
cd K:/Github/Odoo-Modules/fusion-plating && git push origin main
|
||
```
|
||
Pushes to both GitHub and Gitea (nexasystems.ca) via multiple remotes.
|
||
|
||
## Supabase Knowledge Base
|
||
Project: `nexasystems` (id: `ikvdlqkbqsitabxidvnq`)
|
||
- `fusionapps.decisions` — past architecture decisions
|
||
- `fusionapps.issues` — known issues and fixes
|
||
- `fusionapps.code_snippets` — reference code
|
||
- `fusionapps.quick_commands` — deployment and admin commands
|
||
- `fusionapps.vm_registry` — VM inventory
|
||
- `fusionapps.proxmox_nodes` — cluster node specs
|
||
|
||
## End-to-End Business Workflow
|
||
|
||
### Full Lifecycle (What Exists Today)
|
||
|
||
```
|
||
┌─ QUOTATION ──────────────────────────────────────────────────────┐
|
||
│ 1. Customer submits RFQ on portal [DONE] │
|
||
│ → FpQuoteRequest (state: new → under_review → quoted) │
|
||
│ → Model: fusion_plating_portal/models/fp_quote_request.py │
|
||
│ │
|
||
│ 2. Customer accepts → "Create Sale Order" button [DONE] │
|
||
│ → action_create_sale_order() creates SO with lines │
|
||
│ → Links SO origin back to RFQ ref │
|
||
│ │
|
||
│ 3. SO confirmed → MRP creates Manufacturing Order [DONE] │
|
||
│ → Standard Odoo sale_mrp flow │
|
||
└──────────────────────────────────────────────────────────────────┘
|
||
|
||
┌─ MANUFACTURING ──────────────────────────────────────────────────┐
|
||
│ 4. MO confirmed → Portal Job auto-created [DONE] │
|
||
│ → MrpProduction.action_confirm() override │
|
||
│ → Creates FpPortalJob (state: in_progress) │
|
||
│ → Links via x_fc_portal_job_id │
|
||
│ │
|
||
│ 5. Planner assigns recipe + configures steps [DONE] │
|
||
│ → x_fc_recipe_id set on MO │
|
||
│ → Opens fp.recipe.config.wizard for opt-in/out │
|
||
│ → Creates fusion.plating.job.node.override records │
|
||
│ │
|
||
│ 6. Work orders generated from recipe [DONE] │
|
||
│ → _generate_workorders_from_recipe() in bridge_mrp │
|
||
│ → One WO per operation node, steps become WO instructions │
|
||
│ → Respects opt-in/out overrides from job.node.override │
|
||
│ │
|
||
│ 7. Operators execute WOs on shopfloor [DONE] │
|
||
│ → Plant Overview kanban (drag between work centres) │
|
||
│ → Batch chemistry tracking (FpBatch + FpBatchChemistry) │
|
||
│ → Quality holds (FpQualityHold → FpNcr → FpCapa) │
|
||
│ │
|
||
│ 8. MO marked done → Portal job ready_to_ship [DONE] │
|
||
│ → MrpProduction.button_mark_done() override │
|
||
│ → Auto-creates FpDelivery (draft) │
|
||
└──────────────────────────────────────────────────────────────────┘
|
||
|
||
┌─ SHIPPING & INVOICING ───────────────────────────────────────────┐
|
||
│ 9. CoC report generated [DONE] │
|
||
│ → report_coc.xml (PDF with job info, certification, sig) │
|
||
│ → Attached to delivery + portal job │
|
||
│ │
|
||
│ 10. Delivery scheduled & executed [DONE] │
|
||
│ → FpDelivery: draft → scheduled → en_route → delivered │
|
||
│ → Chain of custody auto-logged (FpChainOfCustody) │
|
||
│ → Proof of delivery captured (FpProofOfDelivery) │
|
||
│ → Routes with stops (FpRoute + FpRouteStop) │
|
||
│ │
|
||
│ 11. Delivery marked → Portal job shipped [DONE] │
|
||
│ → FpDelivery.action_mark_delivered() override │
|
||
│ → Sets actual_ship_date + tracking_ref on portal job │
|
||
│ │
|
||
│ 12. Account hold check before invoicing [DONE] │
|
||
│ → x_fc_account_hold on res.partner (fusion_plating_invoicing)│
|
||
│ → Blocks SO confirm, invoice post, shipping for non-managers │
|
||
│ │
|
||
│ 13. Invoice posted → Portal job complete [DONE] │
|
||
│ → AccountMove.action_post() override │
|
||
│ → Sets invoice_ref on portal job, state → complete │
|
||
│ │
|
||
│ 14. Auto-email with CoC + Invoice + Tracking [DONE] │
|
||
│ → fusion_plating_notifications module │
|
||
│ → fp.notification.template (configurable per trigger event) │
|
||
│ → fp.notification.log (audit trail) │
|
||
└──────────────────────────────────────────────────────────────────┘
|
||
|
||
┌─ CUSTOMER PORTAL ────────────────────────────────────────────────┐
|
||
│ 15. Customer sees on portal [DONE] │
|
||
│ → Job progress bar (received → complete) │
|
||
│ → CoC download, invoice access, tracking ref │
|
||
│ → Quote request history │
|
||
└──────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### Per-Job Recipe Overrides (v19.0.2.0.0 bridge_mrp)
|
||
- `x_fc_recipe_id` on `mrp.production` → links MO to recipe
|
||
- `fusion.plating.job.node.override` → per-job opt-in/out decisions
|
||
- `fp.recipe.config.wizard` → checklist wizard for planner
|
||
- "Overrides" stat button on MO form
|
||
- Located in `fusion_plating_bridge_mrp`
|
||
|
||
### All Gaps Resolved (2026-04-12/13)
|
||
|
||
| Gap | Resolution | Module |
|
||
|-----|-----------|--------|
|
||
| **Recipe → Work Orders** | `_generate_workorders_from_recipe()` — one WO per operation, steps become instructions | `fusion_plating_bridge_mrp` v2.1.0 |
|
||
| **Account Hold Check** | `x_fc_account_hold` on res.partner, blocks SO/invoice/shipping for non-managers | `fusion_plating_invoicing` |
|
||
| **Auto-Email Package** | `fp.notification.template` + `fp.notification.log` with hooks on SO confirm, receiving, invoice | `fusion_plating_notifications` |
|
||
| **Quotation Configurator** | Part catalog, coating configs, pricing engine, 3D STL viewer, portal wizard | `fusion_plating_configurator` |
|
||
| **Parts Receiving** | Receiving records, inspection, damage logging, SO auto-create, MRP soft gate | `fusion_plating_receiving` |
|
||
| **Certificate Registry** | Unified fp.certificate with thickness readings, CoC/thickness/Nadcap types | `fusion_plating_certificates` |
|
||
| **Local Delivery** | Forked fusion_tasks with GPS/maps, stripped of claims/sync, delivery-specific fields | `fusion_tasks` |
|
||
|
||
### Architectural Decisions Made
|
||
1. **Recipe → WO**: One WO per `operation` node, child `step` nodes become numbered instructions in WO description
|
||
2. **Account hold**: Manual flag on `res.partner` (auto from aging is roadmap)
|
||
3. **Email triggers**: SO confirmed, parts received, invoice posted (configurable per trigger)
|
||
4. **Configurator**: Custom build with formula-based pricing, estimator override, portal self-service wizard
|
||
5. **Model naming**: New models use `fp.*` prefix, existing keep `fusion.plating.*`
|
||
6. **Security groups**: Role-based (Estimator, Receiving, Accounting, Shop Manager) layered on existing privilege hierarchy (Operator→Supervisor→Manager→Admin)
|
||
|
||
### Key Models Quick Reference
|
||
|
||
| Model | Module | Purpose |
|
||
|-------|--------|---------|
|
||
| `fusion.plating.process.node` | `fusion_plating` | Recipe tree (template) |
|
||
| `fusion.plating.process.node.input` | `fusion_plating` | Operator input definitions |
|
||
| `fusion.plating.job.node.override` | `fusion_plating_bridge_mrp` | Per-job opt-in/out |
|
||
| `fp.part.catalog` | `fusion_plating_configurator` | Customer part library (geometry, material) |
|
||
| `fp.coating.config` | `fusion_plating_configurator` | Coating configuration templates |
|
||
| `fp.treatment` | `fusion_plating_configurator` | Pre/post treatment steps |
|
||
| `fp.pricing.rule` | `fusion_plating_configurator` | Formula-based pricing engine |
|
||
| `fp.pricing.complexity.surcharge` | `fusion_plating_configurator` | Complexity surcharge lines |
|
||
| `fp.quote.configurator` | `fusion_plating_configurator` | Configurator session + price calc |
|
||
| `fp.receiving` | `fusion_plating_receiving` | Parts receiving record |
|
||
| `fp.receiving.line` | `fusion_plating_receiving` | Per-part receiving detail |
|
||
| `fp.receiving.damage` | `fusion_plating_receiving` | Damage log entry |
|
||
| `fp.invoice.strategy.default` | `fusion_plating_invoicing` | Customer-level invoice strategy |
|
||
| `fp.certificate` | `fusion_plating_certificates` | Certificate registry (CoC, thickness, etc.) |
|
||
| `fp.thickness.reading` | `fusion_plating_certificates` | Fischerscope measurement data |
|
||
| `fp.notification.template` | `fusion_plating_notifications` | Configurable email notification |
|
||
| `fp.notification.log` | `fusion_plating_notifications` | Email audit trail |
|
||
| `fusion.plating.quote.request` | `fusion_plating_portal` | Customer RFQ |
|
||
| `fusion.plating.portal.job` | `fusion_plating_portal` | Portal-facing job tracker |
|
||
| `fusion.plating.customer.spec` | `fusion_plating_quality` | Spec library |
|
||
| `fusion.plating.quality.hold` | `fusion_plating_quality` | Parts on hold |
|
||
| `fusion.plating.ncr` | `fusion_plating_quality` | Non-conformance reports |
|
||
| `fusion.plating.capa` | `fusion_plating_quality` | Corrective actions |
|
||
| `fusion.plating.batch` | `fusion_plating_batch` | Rack/barrel batch tracking |
|
||
| `fusion.plating.kpi` | `fusion_plating_kpi` | KPI definition (OTD, yield, throughput, etc.) |
|
||
| `fusion.plating.kpi.value` | `fusion_plating_kpi` | KPI daily value (auto-computed or manual) |
|
||
| `fusion.plating.delivery` | `fusion_plating_logistics` | Delivery with chain of custody |
|
||
| `fusion.plating.pickup.request` | `fusion_plating_logistics` | Customer pickup requests |
|
||
| `fusion.plating.route` | `fusion_plating_logistics` | Driver routes with stops |
|
||
| `fusion.technician.task` | `fusion_tasks` | Local delivery task (GPS, maps) |
|
||
| `fusion.technician.location` | `fusion_tasks` | Driver GPS tracking |
|
||
|
||
## Repackaged Enterprise Modules
|
||
See `K:\Github\RePackaged-Odoo\CLAUDE.md` for full details. Key points:
|
||
- Odoo 19 enterprise modules repackaged for community edition
|
||
- All OEEL-1 licenses changed to LGPL-3
|
||
- Phone-home/telemetry gutted
|
||
- `web_enterprise` and `mail_enterprise` are installed on odoo-entech
|
||
- Addons path includes: `_dependencies`, `accounting`, `inventory_manufacturing`, `hr`, `sales`, `ai`, `fusion_backend`, `custom`, `website`
|
||
|
||
## Fine-Tuning Initiative (Started 2026-04-21)
|
||
|
||
System-wide UX gap closure. Running PLAN → SPEC → IMPLEMENT per sub-project so we don't
|
||
rewrite code as new requirements surface. Each sub-project has its own design doc in
|
||
`docs/superpowers/specs/` and its own implementation plan before any code lands.
|
||
|
||
### Sub-Project Roadmap
|
||
| # | Sub-project | Status | Gaps |
|
||
|---|---|---|---|
|
||
| 1 | Direct Order Wizard fix (no auto-confirm/auto-email) | **Shipped 2026-04-22** (commit afd8bae+) | Gap 1 |
|
||
| 2 | Part Data Model Overhaul (part#/rev required, dual descriptions, per-part cert requirement, SKU→Part Number on customer docs) | **Shipped 2026-04-22** (commits 868b418..afd8bae) | 2b, 2c, 2d, 4 |
|
||
| 3 | Default Process + Composer per part (reuse recipe tree) | **Shipped 2026-04-22** (commits ce07daa..f059348) | 2e, 2f |
|
||
| 4 | Contract Review (optional, per-part, settings-driven QA roster, QA-005 1:1 PDF) | **Shipped 2026-04-22** | 2i |
|
||
| 5 | Order-line fields (fp.serial registry, auto job#, coating-scoped thickness dropdown, revision picker) | **Shipped 2026-04-22** | 5, 6, Q2 |
|
||
| 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)
|
||
|
||
| Q | Decision |
|
||
|---|---|
|
||
| Q1 — Cert requirement precedence | Part wins; partner is fallback. New selection `certificate_requirement` on `fp.part.catalog`: `inherit` / `none` / `coc` / `coc_thickness`. Default `inherit` preserves current behaviour for existing records. |
|
||
| Q2 — Revision handling | Keep existing chain (`parent_part_id`, `is_latest_revision`, `revision_ids`). Out-of-scope for Sub 2. The "revision picker at order entry" moves to Sub 5. |
|
||
| Q3 — Required-field flip | Strict + backfill. On upgrade: `part_number = name` if empty; `revision = 'A'` if empty. Then `required=True` for both. `name` becomes optional. |
|
||
| Q4 — Descriptions shape | Split `fp.sale.description.template.description` into `internal_description` + `customer_facing_description`. Repeater on the part's Descriptions tab gains two columns. Old `description` column dropped in migration. |
|
||
| Q5 — SKU vs Part Number | Use `fp.part.catalog.part_number` directly as the source of truth. Don't sync to `default_code`. Customer-facing reports print `part_number`; internal reports keep showing `default_code` (service code). Odoo-native screens untouched. |
|
||
| Q6 — Description required at order entry | **Both required.** SO line carries `name` (customer-facing, already Odoo standard) + new `x_fc_internal_description` (ops workflow). Both required before save. |
|
||
|
||
### Sub 2 Defensive Measures (Prevent Rework When Later Subs Land)
|
||
|
||
1. **Single-source cert resolution function** — `mrp.production._fp_resolve_cert_requirement(self)` returns `(want_coc, want_thickness)`. Every caller (cert cascade, QC gate, notification routing) goes through this. When Sub 6 restructures partner-level flags into location / contact permissions, one function updates — no call-site hunt.
|
||
2. **Shared QWeb line-header macro** — `fusion_plating_reports.customer_line_header` renders `part_number + revision + customer-facing description` with fallback to product name for non-part lines. All 4 customer-facing reports (SO, invoice, packing slip, BoL) call the macro. Sub 5's revision picker updates the macro once, all reports follow.
|
||
3. **Isolated migration** — Sub 2's `post_init_hook` is idempotent (NULL/empty checks). Safe to re-run. Doesn't fight Sub 3/4/5/6 migrations.
|
||
4. **Additive SO line fields** — `x_fc_internal_description`, `x_fc_description_template_id` sit alongside future Sub 5 fields (`x_fc_serial_number`, `x_fc_job_number`, `x_fc_thickness`, `x_fc_revision_snapshot`) with zero touchpoints.
|
||
5. **Clean removal of old `description` column** — migrated then dropped. Not kept as deprecated. One clean break now beats two migrations later.
|
||
|
||
### Sub 6 Preview — Contact Profiles & Communication Routing (client transcript A/B/C)
|
||
- Sub-contacts under `res.partner` with per-contact permissions: certs / QC / quotes+SO / invoices.
|
||
- Multiple delivery locations per customer; each location has its own notification list.
|
||
- Global contact (company-level + location-level) gets all communications.
|
||
- Will restructure or augment the partner-level `x_fc_send_coc` / `x_fc_send_thickness_report` flags that Sub 2 currently falls back to. Sub 2's `_fp_resolve_cert_requirement` is the update point.
|
||
|
||
### Sub 7 Preview — IoT Tuning (client transcript D)
|
||
- 6–10 active tanks (of ~20–25 total) need continuous monitoring.
|
||
- Polling interval: **30 minutes acceptable, 15 minutes ideal.** Configurable per tank.
|
||
- Temperature, pH, nickel concentration — all on automated controller (existing `fusion_plating_iot` module).
|
||
- Work scope: ensure per-sensor interval field exists + defaults + seed 6–10 tank.sensor records.
|
||
|
||
### Sub 8 Preview — Receiving / Inspection / QC Restructure (client transcript E)
|
||
**Current flow (wrong):** Direct order → receiving entry → receiver inspects on arrival.
|
||
**Correct flow:**
|
||
1. Customer ships parts in boxes. Receiver counts boxes (does NOT inspect individual parts).
|
||
2. Boxes sit in staging until racking.
|
||
3. Racking crew opens boxes, inspects each part as they load racks (inspection ≠ receiving).
|
||
4. Parts go through plating process.
|
||
5. Post-plate QC on machine (thickness / depth / coating thickness) — existing QC gate (Phase 1–3 work).
|
||
6. Pack back into the SAME boxes they arrived in. Same qty out as in.
|
||
|
||
**Implication:** The current `fusion_plating_receiving` module conflates receiving + inspection. Sub 8 splits them. Racking-time inspection becomes its own record, linked to WOs not to receiving.
|
||
|
||
### Deferred Items (Future)
|
||
- **First-off / last-off QC** — first and last part of each batch get full QC inspection; middle parts sampled. Not priority.
|
||
- **VEC machine auto-ingest** — different from Fischerscope. Exports a Word doc (picture + data) named `workorder_PO.docx` to a network share. Plan: auto-scan the share, parse, attach to QC as thickness_report. Defer until core flow is solid.
|
||
|
||
### Client-Confirmed Operational Thresholds
|
||
- Tank polling: 15–30 min, half-hour acceptable
|
||
- Active tanks: 6–10 (not all 20–25)
|
||
- Boxes round-trip: parts ship back in the same boxes they arrived in, same quantity per box
|
||
|
||
### How to Resume This Work in a Fresh Session
|
||
1. Read this section (Fine-Tuning Initiative).
|
||
2. Check the sub-project status table — which sub is in flight.
|
||
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** (D1–D8 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 A–F 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 A–F 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;
|
||
```
|