diff --git a/fusion_plating/fusion_plating/__manifest__.py b/fusion_plating/fusion_plating/__manifest__.py index fac84e44..6eff726f 100644 --- a/fusion_plating/fusion_plating/__manifest__.py +++ b/fusion_plating/fusion_plating/__manifest__.py @@ -5,7 +5,7 @@ { 'name': 'Fusion Plating', - 'version': '19.0.21.1.3', + 'version': '19.0.21.2.0', 'category': 'Manufacturing/Plating', 'summary': 'Core plating / metal finishing ERP: facilities, processes, tanks, baths, jobs, operators.', 'description': """ diff --git a/fusion_plating/fusion_plating/controllers/simple_recipe_controller.py b/fusion_plating/fusion_plating/controllers/simple_recipe_controller.py index 70fee115..e929d41d 100644 --- a/fusion_plating/fusion_plating/controllers/simple_recipe_controller.py +++ b/fusion_plating/fusion_plating/controllers/simple_recipe_controller.py @@ -484,8 +484,15 @@ class SimpleRecipeController(http.Controller): type='jsonrpc', auth='user') def kinds_list(self): """Sub 14b — Step Kind dropdown options for the inline library - form. User-extensible via /fp/simple_recipe/kinds/create.""" + form. User-extensible via /fp/simple_recipe/kinds/create. + + 2026-05-24 — payload now includes `area_kind` + a humanized + `area_kind_label` so the Simple Editor picker can render + "Masking — Masking column" and authors see which Shop Floor + column they're routing the step to. + """ Kind = request.env['fp.step.kind'] + area_labels = dict(Kind._fields['area_kind'].selection) return { 'kinds': [ { @@ -494,6 +501,8 @@ class SimpleRecipeController(http.Controller): 'name': k.name or '', 'icon': k.icon or '', 'sequence': k.sequence, + 'area_kind': k.area_kind or '', + 'area_kind_label': area_labels.get(k.area_kind, ''), } for k in Kind.search( [('active', '=', True)], order='sequence, name', diff --git a/fusion_plating/fusion_plating/data/fp_step_kind_data.xml b/fusion_plating/fusion_plating/data/fp_step_kind_data.xml index 1203e68b..b09b9c77 100644 --- a/fusion_plating/fusion_plating/data/fp_step_kind_data.xml +++ b/fusion_plating/fusion_plating/data/fp_step_kind_data.xml @@ -18,7 +18,15 @@ (covers all bath-based steps). - `mask` covers Masking + De-Masking, `racking` covers Racking + De-Racking — operators differentiate by the - step name. --> + step name. + + 2026-05-24 update (19.0.21.2.0 — Shop Floor live-step fix): + - New `area_kind` field on fp.step.kind drives plant-view + column routing. Every record below carries an + area_kind. New `blast` kind for the Blasting column. + - `derack`, `demask`, `gating` get re-activated via the + pre-migrate (they're listed under "ACTIVE KINDS" here + now since they're meant to be active going forward). --> @@ -29,13 +37,7 @@ Other 5 fa-circle-o - - - - wet_process - Wet Process (Clean / Rinse / Etch / Dry / etc.) - 55 - fa-tint + plating @@ -43,144 +45,182 @@ Receiving / Incoming Inspection 10 fa-truck + receiving contract_review Contract Review (QA-005) 20 fa-file-text-o + receiving racking Racking 30 fa-server + racking + + + blast + Blasting / Media Blast + 35 + fa-bullseye + blasting mask Masking 40 fa-eye-slash + masking cleaning Cleaning 50 fa-tint + plating + + + wet_process + Wet Process (Clean / Rinse / Etch / Dry / etc.) + 55 + fa-tint + plating electroclean Electroclean 60 fa-bolt + plating etch Etch / Activation 70 fa-flask + plating rinse Rinse 80 fa-tint + plating strike Strike (Wood's Nickel / Activation) 90 fa-bolt + plating plate Plating 100 fa-shield + plating replenishment Tank Replenishment 110 fa-plus-circle + plating wbf_test Water Break Free Test 120 fa-check-square-o + plating dry Drying 130 fa-sun-o + plating bake Bake (HE Relief / Stress Relief) 140 fa-fire + baking demask De-Masking 150 fa-eye + de_racking derack De-Racking 160 fa-server + de_racking inspect Inspection 170 fa-search + inspection hardness_test Hardness Test (HV / HK / HRC) 180 fa-tachometer + inspection adhesion_test Adhesion Test 190 fa-link + inspection salt_spray Salt Spray / Corrosion Test 200 fa-cloud + inspection final_inspect Final Inspection 210 fa-check-circle + inspection packaging Packaging / Pre-Ship 220 fa-archive + shipping ship Shipping 230 fa-paper-plane + shipping gating Gating 240 fa-pause-circle + receiving + + diff --git a/fusion_plating/fusion_plating/data/fp_step_template_data.xml b/fusion_plating/fusion_plating/data/fp_step_template_data.xml index 5dc76a46..40e5f047 100644 --- a/fusion_plating/fusion_plating/data/fp_step_template_data.xml +++ b/fusion_plating/fusion_plating/data/fp_step_template_data.xml @@ -103,4 +103,30 @@ ]]> + + + + Hot Water Porosity Test (A-15) + HWP_A15 + + fa-tint + Hot-water porosity test for plated samples. Verify continuity + of the deposit across the test panel; record any porosity sites + and attach a photo when a defect is found.

+ ]]>
+
+ + + Final Inspection / Packaging + FINAL_PKG_STD + + fa-check-circle + Combined final visual + dimensional inspection followed by + packaging into the customer's original boxes for shipment. + Verify part count, attach certs, photo the sealed load.

+ ]]>
+
+ diff --git a/fusion_plating/fusion_plating/migrations/19.0.21.2.0/pre-migrate.py b/fusion_plating/fusion_plating/migrations/19.0.21.2.0/pre-migrate.py new file mode 100644 index 00000000..8b7feb94 --- /dev/null +++ b/fusion_plating/fusion_plating/migrations/19.0.21.2.0/pre-migrate.py @@ -0,0 +1,100 @@ +# -*- coding: utf-8 -*- +# Copyright 2026 Nexa Systems Inc. +# License OPL-1 (Odoo Proprietary License v1.0) +"""19.0.21.2.0 — Shop Floor live-step + kind taxonomy. + +Seeds fp.step.kind.area_kind on existing kinds BEFORE the required +NOT NULL constraint on the new field hits the schema. Also activates +the three kinds (derack/demask/gating) that were deactivated in +19.0.20.6.0 but are needed for the full area_kind taxonomy. + +Idempotent: only fills NULL / inactive rows. + +See docs/superpowers/specs/2026-05-24-shopfloor-live-step-fix-design.md. +""" +import logging + +_logger = logging.getLogger(__name__) + +KIND_TO_AREA = { + 'other': 'plating', + 'wet_process': 'plating', + 'receiving': 'receiving', + 'contract_review': 'receiving', + 'gating': 'receiving', + 'racking': 'racking', + 'derack': 'de_racking', + 'mask': 'masking', + 'demask': 'de_racking', + 'cleaning': 'plating', + 'electroclean': 'plating', + 'etch': 'plating', + 'rinse': 'plating', + 'strike': 'plating', + 'plate': 'plating', + 'replenishment': 'plating', + 'wbf_test': 'plating', + 'dry': 'plating', + 'bake': 'baking', + 'inspect': 'inspection', + 'final_inspect': 'inspection', + 'hardness_test': 'inspection', + 'adhesion_test': 'inspection', + 'salt_spray': 'inspection', + 'packaging': 'shipping', + 'ship': 'shipping', + 'blast': 'blasting', + 'bead_blast': 'blasting', + 'media_blast': 'blasting', +} + + +def migrate(cr, version): + # Phase 1 — Pre-create the column NULL-permitting so we can seed it + # BEFORE Odoo's schema sync tries to enforce NOT NULL. + cr.execute( + "ALTER TABLE fp_step_kind " + "ADD COLUMN IF NOT EXISTS area_kind VARCHAR" + ) + + # Phase 2 — Seed area_kind on existing kinds. Idempotent: only fills + # NULLs, so re-running -u is safe. + seeded = 0 + for code, area in KIND_TO_AREA.items(): + cr.execute( + "UPDATE fp_step_kind SET area_kind = %s " + "WHERE code = %s " + "AND (area_kind IS NULL OR area_kind = '')", + (area, code), + ) + seeded += cr.rowcount + _logger.info( + '[live-step-fix] kind.area_kind seeded on %s known-code rows', + seeded, + ) + + # Phase 3 — Fallback: any user-created custom kinds not in our seed + # map → 'plating'. Clears the NOT NULL constraint for any leftover. + cr.execute( + "UPDATE fp_step_kind SET area_kind = 'plating' " + "WHERE area_kind IS NULL OR area_kind = ''" + ) + if cr.rowcount: + _logger.info( + '[live-step-fix] %s unknown kinds defaulted to plating', + cr.rowcount, + ) + + # Phase 4 — Activate kinds we need for full coverage. + activated = 0 + for code in ('derack', 'demask', 'gating'): + cr.execute( + "UPDATE fp_step_kind SET active = TRUE " + "WHERE code = %s AND active = FALSE", + (code,), + ) + activated += cr.rowcount + _logger.info( + '[live-step-fix] %s kinds activated (derack/demask/gating)', + activated, + ) diff --git a/fusion_plating/fusion_plating/models/fp_step_kind.py b/fusion_plating/fusion_plating/models/fp_step_kind.py index a863c218..af897cad 100644 --- a/fusion_plating/fusion_plating/models/fp_step_kind.py +++ b/fusion_plating/fusion_plating/models/fp_step_kind.py @@ -34,6 +34,32 @@ class FpStepKind(models.Model): string='Icon', default='fa-cog', ) + # 2026-05-24 — Shop Floor live-step fix. + # Each kind self-declares which plant-view column its steps land in. + # Replaces the hardcoded _STEP_KIND_TO_AREA dict (removed from + # fusion_plating_jobs/models/fp_job_step.py). Pre-migrate + # 19.0.21.2.0 seeds existing rows before NOT NULL hits the schema. + area_kind = fields.Selection( + [ + ('receiving', 'Receiving'), + ('masking', 'Masking'), + ('blasting', 'Blasting'), + ('racking', 'Racking'), + ('plating', 'Plating'), + ('baking', 'Baking'), + ('de_racking', 'De-Racking'), + ('inspection', 'Final Inspection'), + ('shipping', 'Shipping'), + ], + string='Shop Floor Column', + required=True, + index=True, + tracking=True, + help='Determines which column on the Shop Floor plant kanban shows ' + 'cards whose active step uses this kind. Step kinds drive ' + 'routing automatically — picking a kind tells the system both ' + 'what gates fire AND where the card lives.', + ) company_id = fields.Many2one( 'res.company', string='Company', default=lambda self: self.env.company, diff --git a/fusion_plating/fusion_plating/static/src/xml/simple_recipe_editor.xml b/fusion_plating/fusion_plating/static/src/xml/simple_recipe_editor.xml index 1240c484..147a10b9 100644 --- a/fusion_plating/fusion_plating/static/src/xml/simple_recipe_editor.xml +++ b/fusion_plating/fusion_plating/static/src/xml/simple_recipe_editor.xml @@ -509,6 +509,7 @@