Two coherent feature drops shipping together because their fp_job_step
edits overlap. Both target operator workflow correctness.
## Sub 13 — Sequential step enforcement (recipe + per-step)
Background:
Investigation on WH/JOB/00339 showed operators starting Incoming
Inspection while Contract Review was still in_progress. Audit:
98.7% of recipe operations system-wide had requires_predecessor_done
= false (the legacy per-step opt-in defaults off, recipe authors
rarely tick the box).
Architecture:
Recipe-level toggle + per-step opt-out (Option A from /investigate).
* fusion.plating.process.node.enforce_sequential — Boolean on the
recipe root. Default True. When True, every operation under this
recipe waits for earlier-sequence steps to finish before it can
start.
* fusion.plating.process.node.parallel_start — Boolean on operation
nodes. When True, this step bypasses the sequential gate (e.g.
paperwork or QA review that runs alongside production).
* Mirrored on fp.step.template (parallel_start) so library steps
carry the flag into snapshots.
* fp.job.enforce_sequential — related from recipe_id. Snapshotted
at job creation so a recipe author flipping the recipe's flag
AFTER job generation does NOT change behaviour mid-run.
* fp.job.step.parallel_start — related from recipe_node_id.
* Decision matrix (encapsulated in
fp.job.step._fp_should_block_predecessors):
recipe.enforce_sequential | step.parallel_start | step.req_pred_done | block?
--------------------------|---------------------|--------------------|------
True | False | any | YES
True | True | any | no
False | any | True | YES
False | any | False | no
* Manager bypass via context fp_skip_predecessor_check=True (existing).
Runtime gates:
* fp.job.step.button_start — calls _fp_should_block_predecessors;
raises UserError naming the blocking earlier step(s).
* fp.job.step.can_start — computed Boolean for view-side disable.
* Move wizard predecessor check
(fusion_plating_shopfloor/controllers/move_controller.py) — uses
the same helper so tablet + backend behave identically.
UI surface:
* Recipe form (fp_process_node_views.xml) — enforce_sequential
toggle on recipe root, parallel_start checkbox on operations.
* Step template form — parallel_start checkbox.
* Simple Recipe Editor (inline library form) — Parallel Start
checkbox + legacy flag demoted with muted styling + supervisor
group gate.
* Recipe Tree Editor (properties panel) — both flags exposed,
only-show on the right node_type.
* Controllers updated to allowlist + payload the new fields.
Migration:
fusion_plating/migrations/19.0.18.12.0/post-migrate.py — sets
enforce_sequential = TRUE on every existing recipe-root node.
Idempotent. User confirmed dev-stage data, so retroactive flip
is safe (no production jobs to disrupt).
Tests:
TestSequentialEnforcement (10 tests) covering:
* sequential mode blocks out-of-order start
* first step always startable
* predecessor finish/skip unlocks next
* parallel_start opts out of gate
* free-flow mode bypasses gate
* legacy requires_predecessor_done still honoured in free-flow
* manager bypass via context
* can_start compute reflects state correctly
* library template parallel_start snapshots into recipe-node
## Sub 12e — Record Inputs Wizard v3 (card layout, dark-mode aware)
Background:
v2 wizard was a 17-column wide editable table. Operators got lost
finding which value column applied to their row's type, horizontal
scroll required on tablets, composite types crammed into one row.
New layout:
* Each measurement renders as a stacked card (CSS Grid + display
transformation on the existing list widget — preserves inline
editing, no JS rewrite).
* Card header: prompt name (large, bold) + type/unit pills.
* Card body: ONLY the value widget for this row's type
(number / boolean / date / text / photo / multi-point / panel).
* Composite types (multi-point thickness 5x reading + avg, bath
panel 4 fields) get inline sub-grid inside the card.
* Empty state ("no measurement prompts") with friendly CTA.
Dark mode:
* SCSS branches at compile time on $o-webclient-color-scheme
(per fusion-plating/CLAUDE.md note).
* Tokens: 7 surface colours + 4 ink levels with light/dark hex
pairs, all behind var(--fp-*) custom properties for per-deploy
override.
* Registered in BOTH web.assets_backend AND web.assets_web_dark
so each bundle compiles its own palette.
Tablet polish:
@media (max-width: 900px) — collapse meta below prompt + bump
numeric input min-height to 56px.
Defensive:
* v2 view kept in the XML file (instant rollback by changing one
view_id ref).
* `:has(.o_invisible_modifier)` rule drops empty cells out of the
grid so Odoo's invisible="..." doesn't punch holes in layout.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
146 lines
5.8 KiB
Python
146 lines
5.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright 2026 Nexa Systems Inc.
|
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
|
# Part of the Fusion Plating product family.
|
|
|
|
{
|
|
'name': 'Fusion Plating',
|
|
'version': '19.0.18.12.0',
|
|
'category': 'Manufacturing/Plating',
|
|
'summary': 'Core plating / metal finishing ERP: facilities, processes, tanks, baths, jobs, operators.',
|
|
'description': """
|
|
Fusion Plating — Core
|
|
=====================
|
|
|
|
Part of the Fusion Plating product family by Nexa Systems Inc.
|
|
|
|
Fusion Plating is a configurable, multi-tenant capable ERP for plating and metal
|
|
finishing shops. This core module provides the process-agnostic foundation that
|
|
every shop needs regardless of size, process mix, jurisdiction, or industry.
|
|
|
|
The core ships intentionally empty of region-specific or process-specific
|
|
content — that comes from add-on modules:
|
|
|
|
* fusion_plating_process_en — Electroless nickel plating
|
|
* fusion_plating_process_chrome — Chrome coating (hex or trivalent)
|
|
* fusion_plating_process_anodize — Aluminum anodizing (Type II, III)
|
|
* fusion_plating_process_black_oxide — Black oxidizing
|
|
* fusion_plating_quality — QMS (NCR, CAPA, calibration, CoC, doc control)
|
|
* fusion_plating_compliance — Generic compliance framework
|
|
* fusion_plating_compliance_on — Ontario regulatory pack
|
|
* fusion_plating_compliance_tor — Toronto Ch. 681 municipal pack
|
|
* fusion_plating_safety — SDS, WHMIS/TDG training, JHSC, exposure
|
|
* fusion_plating_shopfloor — Tablet operator stations, QR scanning
|
|
* fusion_plating_portal — Customer portal
|
|
* fusion_plating_aerospace — AS9100 + Nadcap AC7108 pack
|
|
* fusion_plating_nuclear — CSA N299, CNSC, NQA-1 pack
|
|
* fusion_plating_cgp — Controlled Goods Program pack
|
|
* fusion_plating_logistics — Pickup & delivery
|
|
* fusion_plating_culture — Values / fundamentals framework
|
|
|
|
Core concepts
|
|
-------------
|
|
* Facility — a physical site with its own tanks, operators, compliance profile
|
|
* Process Type — extensible taxonomy of finishing processes
|
|
* Work Center — production line or station within a facility
|
|
* Tank — physical vessel with QR code and state
|
|
* Bath — the chemistry currently in a tank, with its own lifecycle
|
|
* Bath Log — daily chemistry readings with pass/fail vs target
|
|
* KPI — configurable headline metrics per shop
|
|
* Delegation Inbox — single pane of "things waiting for someone"
|
|
|
|
Design principles
|
|
-----------------
|
|
1. No client-specific strings in core.
|
|
2. No region-specific data in core.
|
|
3. No process-specific chemistry in core.
|
|
4. Works on both Odoo Community and Enterprise editions.
|
|
5. Theme-aware: respects user light/dark mode preference.
|
|
6. Multi-facility, multi-company, multi-currency capable.
|
|
|
|
Copyright (c) 2026 Nexa Systems Inc. All rights reserved.
|
|
""",
|
|
'author': 'Nexa Systems Inc.',
|
|
'website': 'https://www.nexasystems.ca',
|
|
'maintainer': 'Nexa Systems Inc.',
|
|
'support': 'support@nexasystems.ca',
|
|
'license': 'OPL-1',
|
|
'price': 0.00,
|
|
'currency': 'CAD',
|
|
'depends': [
|
|
'base',
|
|
'mail',
|
|
'contacts',
|
|
'product',
|
|
'stock',
|
|
'sale_management',
|
|
'purchase',
|
|
'hr',
|
|
'uom',
|
|
],
|
|
'data': [
|
|
'security/fp_security.xml',
|
|
'security/ir.model.access.csv',
|
|
'data/fp_landing_data.xml',
|
|
'data/fp_sequence_data.xml',
|
|
'data/fp_job_sequences.xml',
|
|
'data/fp_process_category_data.xml',
|
|
# fp_menu.xml MUST load early — defines menu_fp_root, menu_fp_config,
|
|
# menu_fp_compliance_hub, plus the 7 Phase-2 Configuration sub-folder
|
|
# buckets. Every other view file (in this module and downstream)
|
|
# that creates a child menu under those buckets references them
|
|
# by xmlid, which has to already exist at parse time.
|
|
'views/fp_menu.xml',
|
|
'views/fp_process_type_views.xml',
|
|
'views/fp_work_center_views.xml',
|
|
'views/fp_tank_views.xml',
|
|
'views/fp_bath_log_views.xml',
|
|
'views/fp_facility_views.xml',
|
|
'views/fp_bath_views.xml',
|
|
'views/fp_process_node_views.xml',
|
|
'views/fp_step_template_views.xml',
|
|
'views/fp_rack_tag_views.xml',
|
|
'views/fp_job_step_move_views.xml',
|
|
'views/fp_job_step_timelog_views.xml',
|
|
'views/fp_rack_views.xml',
|
|
'views/fp_bath_replenishment_views.xml',
|
|
'views/fp_operator_certification_views.xml',
|
|
'views/res_config_settings_views.xml',
|
|
'views/fp_landing_views.xml',
|
|
'views/fp_work_centre_views.xml',
|
|
'views/fp_job_views.xml',
|
|
'views/fp_job_step_views.xml',
|
|
'views/fp_jobs_menu.xml',
|
|
'data/fp_work_role_data.xml',
|
|
'views/fp_work_role_views.xml',
|
|
'data/fp_recipe_enp_alum_basic.xml',
|
|
'data/fp_recipe_enp_steel_basic.xml',
|
|
'data/fp_recipe_enp_sp.xml',
|
|
'data/fp_recipe_general_processing.xml',
|
|
'data/fp_recipe_anodize.xml',
|
|
'data/fp_recipe_chem_conversion.xml',
|
|
'data/fp_step_template_data.xml',
|
|
],
|
|
'post_init_hook': 'post_init_hook',
|
|
'assets': {
|
|
'web.assets_backend': [
|
|
'fusion_plating/static/src/scss/fusion_plating.scss',
|
|
'fusion_plating/static/src/scss/recipe_tree_editor.scss',
|
|
'fusion_plating/static/src/scss/fp_chatter_dark.scss',
|
|
'fusion_plating/static/src/scss/simple_recipe_editor.scss',
|
|
'fusion_plating/static/src/xml/recipe_tree_editor.xml',
|
|
'fusion_plating/static/src/xml/simple_recipe_editor.xml',
|
|
'fusion_plating/static/src/js/recipe_tree_editor.js',
|
|
'fusion_plating/static/src/js/simple_recipe_editor.js',
|
|
],
|
|
},
|
|
'demo': [
|
|
'data/fp_demo_data.xml',
|
|
'data/fp_demo_recipe_data.xml',
|
|
],
|
|
'images': ['static/description/icon.png'],
|
|
'installable': True,
|
|
'auto_install': False,
|
|
'application': True,
|
|
}
|