From 48c2a4bfe17e270056b11a44716469b7b38f0790 Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Tue, 26 May 2026 23:20:27 -0400 Subject: [PATCH] =?UTF-8?q?feat(configurator):=2019.0.22.1.0=20=E2=80=94?= =?UTF-8?q?=20recipe-driven=20orders=20+=20auto-sync=20to=20part?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Four customer-feedback fixes (G1-G4): G1 — Part cell display redundancy. fp.part.catalog.display_name was showing 'PART (Rev X) — Name' which duplicated with my Part cell widget's separately-rendered revision + name rows. Added @api.depends_context ('fp_express_part_picker') to _compute_display_name: when the context flag is True, display_name returns JUST the part_number. The Express view passes the flag on the part_catalog_id field, so the picker shows '9876699373' and the widget's row 2/3 show the rev + name. G2 — Material/Process Tag is now the order's RECIPE, not a free-text shop tag. Converted material_process from Char to Many2One(fusion. plating.process.node) with domain [('node_type','=','recipe')] on both fp.direct.order.wizard AND sale.order. Pre-migration (19.0.22.1.0/ pre-migrate.py) drops the old VARCHAR column so Odoo recreates as INTEGER FK. Per dev-stage policy, old tag data is dropped. G3 — Auto-apply order recipe to every line. New onchange _onchange_material_process_apply_to_lines on the wizard: when the header recipe is picked / changed, propagate to every line's process_variant_id (unless the line has an explicit per-line override that doesn't match the previous header value). Plus an override on fp.direct.order.line.create that seeds new lines' process_variant_id from wizard.material_process. So a newly-added line auto-inherits the order's recipe. G4 — Auto-sync line edits back to the part catalog. New _fp_sync_to_part method called from create() + write() on fp.direct.order.line. Tracked fields: - line_description → part.default_specification_text - bake_instructions → part.default_bake_instructions - thickness_range → part.x_fc_default_thickness_range - masking_enabled → part.default_masking_enabled - process_variant_id → part.default_process_variant_id Future orders for the same part will auto-pull these updated defaults via the existing _onchange_part_default_thickness chain. Last-write- wins semantics across concurrent edits (acceptable per dev-stage). --- .../__manifest__.py | 2 +- .../migrations/19.0.22.1.0/__init__.py | 0 .../migrations/19.0.22.1.0/pre-migrate.py | 37 ++++++++ .../models/fp_part_catalog.py | 12 +++ .../models/sale_order.py | 10 +- .../views/fp_express_order_views.xml | 7 +- .../wizard/fp_direct_order_line.py | 91 +++++++++++++++++++ .../wizard/fp_direct_order_wizard.py | 41 ++++++++- 8 files changed, 190 insertions(+), 10 deletions(-) create mode 100644 fusion_plating/fusion_plating_configurator/migrations/19.0.22.1.0/__init__.py create mode 100644 fusion_plating/fusion_plating_configurator/migrations/19.0.22.1.0/pre-migrate.py diff --git a/fusion_plating/fusion_plating_configurator/__manifest__.py b/fusion_plating/fusion_plating_configurator/__manifest__.py index ae1be85c..0ce6d31e 100644 --- a/fusion_plating/fusion_plating_configurator/__manifest__.py +++ b/fusion_plating/fusion_plating_configurator/__manifest__.py @@ -5,7 +5,7 @@ { 'name': 'Fusion Plating — Configurator', - 'version': '19.0.22.0.0', + 'version': '19.0.22.1.0', 'category': 'Manufacturing/Plating', 'summary': 'Quotation configurator with part catalog, coating configs, and formula-based pricing engine.', 'description': """ diff --git a/fusion_plating/fusion_plating_configurator/migrations/19.0.22.1.0/__init__.py b/fusion_plating/fusion_plating_configurator/migrations/19.0.22.1.0/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/fusion_plating/fusion_plating_configurator/migrations/19.0.22.1.0/pre-migrate.py b/fusion_plating/fusion_plating_configurator/migrations/19.0.22.1.0/pre-migrate.py new file mode 100644 index 00000000..43cc3b79 --- /dev/null +++ b/fusion_plating/fusion_plating_configurator/migrations/19.0.22.1.0/pre-migrate.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +"""Pre-migration for 19.0.22.1.0 — material_process Char → Many2One. + +The material_process field on fp.direct.order.wizard was originally a +free-text Char tag for shop-level metadata (e.g. "ENP-STEEL-HP-ADVANCED"). +Per 2026-05-27 customer feedback, it should instead link directly to a +recipe (fusion.plating.process.node, node_type='recipe') so that picking +a tag auto-applies the recipe to every order line. + +Drop the old VARCHAR column so Odoo can recreate it as an INTEGER FK +when the new field declaration loads. Per the Express Orders spec +section 12 (dev-stage, ignore past orders), losing the old Char values +is acceptable. + +Idempotent — IF EXISTS guards mean a re-run is safe. +""" + + +def migrate(cr, version): + # Same model needs the same pre-migration on sale.order too + for table, column in ( + ('fp_direct_order_wizard', 'material_process'), + ('sale_order', 'x_fc_material_process'), + ): + cr.execute(""" + SELECT data_type FROM information_schema.columns + WHERE table_name = %s AND column_name = %s + """, (table, column)) + row = cr.fetchone() + if not row: + continue + data_type = row[0] + # Only drop if the existing column is the old Char shape + if data_type in ('character varying', 'text'): + cr.execute( + f"ALTER TABLE {table} DROP COLUMN IF EXISTS {column}" + ) diff --git a/fusion_plating/fusion_plating_configurator/models/fp_part_catalog.py b/fusion_plating/fusion_plating_configurator/models/fp_part_catalog.py index 85733956..6ac7c051 100644 --- a/fusion_plating/fusion_plating_configurator/models/fp_part_catalog.py +++ b/fusion_plating/fusion_plating_configurator/models/fp_part_catalog.py @@ -543,6 +543,7 @@ class FpPartCatalog(models.Model): part.description_template_count = len(part.description_template_ids) @api.depends('part_number', 'revision', 'name') + @api.depends_context('fp_express_part_picker') def _compute_display_name(self): """Display = 'PART-NUMBER (Rev X) — Optional Name'. @@ -552,8 +553,19 @@ class FpPartCatalog(models.Model): Defensive: some legacy rows stored revision as "Rev 1" (with the prefix baked in). Strip any leading "rev " so the wrapper doesn't render "(Rev Rev 1)". + + Express Orders override (2026-05-27): when called with the + `fp_express_part_picker=True` context, return JUST part_number. + The FpExpressPartCell OWL widget shows revision and part name on + their own rows, so the picker display should be just the bare + part number to avoid 'PART (Rev A) — NAME' duplicating with the + widget's separate rev / name rows. """ + express = self.env.context.get('fp_express_part_picker') for rec in self: + if express and rec.part_number: + rec.display_name = rec.part_number + continue if rec.part_number: core = f"{rec.part_number}" if rec.revision: diff --git a/fusion_plating/fusion_plating_configurator/models/sale_order.py b/fusion_plating/fusion_plating_configurator/models/sale_order.py index 670d3446..9ca54c22 100644 --- a/fusion_plating/fusion_plating_configurator/models/sale_order.py +++ b/fusion_plating/fusion_plating_configurator/models/sale_order.py @@ -123,10 +123,14 @@ class SaleOrder(models.Model): ) # ---- Express Orders header-level (2026-05-26) ---- - x_fc_material_process = fields.Char( + # 2026-05-27: changed from Char to Many2One — Material/Process Tag + # IS the order's recipe. Auto-applies to every line at confirm time. + x_fc_material_process = fields.Many2one( + 'fusion.plating.process.node', string='Material / Process Tag', - help='Free-text order-level shop tag (e.g. ENP-STEEL-HP-ADVANCED). ' - 'Informational; not used by the workflow.', + domain="[('node_type', '=', 'recipe')]", + help='Order-level recipe — auto-applies to every line. Individual ' + 'lines can still override via x_fc_process_variant_id.', ) x_fc_internal_notes = fields.Text( string='Order-Level Internal Notes', diff --git a/fusion_plating/fusion_plating_configurator/views/fp_express_order_views.xml b/fusion_plating/fusion_plating_configurator/views/fp_express_order_views.xml index 7d1882d5..afbdbe3c 100644 --- a/fusion_plating/fusion_plating_configurator/views/fp_express_order_views.xml +++ b/fusion_plating/fusion_plating_configurator/views/fp_express_order_views.xml @@ -140,9 +140,10 @@
- + + options="{'no_create_edit': True}" + placeholder="Pick a recipe..."/>
@@ -239,7 +240,7 @@ string="Part Number" widget="fp_express_part_cell" width="230px" - context="{'default_partner_id': parent.partner_id, 'default_revision': 'A'}" + context="{'default_partner_id': parent.partner_id, 'default_revision': 'A', 'fp_express_part_picker': True}" domain="[('partner_id', '=', parent.partner_id), ('is_latest_revision', '=', True)]" options="{'no_quick_create': True}"/>