# 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 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 | | 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. ## 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 ``, NO `` wrapper for group-by filters. Use bare `` 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 `` 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`