feat(configurator): 19.0.22.1.0 — recipe-driven orders + auto-sync to part

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).
This commit is contained in:
gsinghpal
2026-05-26 23:20:27 -04:00
parent 4c5ee6143c
commit 48c2a4bfe1
8 changed files with 190 additions and 10 deletions

View File

@@ -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:

View File

@@ -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',