feat(configurator): direct-order line shows effective Process alongside Treatment

User asked why the direct-order wizard only showed "Primary
Treatment" and not Process — aren't they the same? They're not,
but the distinction was invisible on the order line until now.

Mental model (preserved here to keep future decisions aligned with
the user's question):

  * Primary Treatment (fp.coating.config) = "WHAT coating" (process
    type, thickness range, spec reference — the contractual
    deliverable).
  * Process (fusion.plating.process.node tree) = "HOW we make it"
    (the floor-level sequence of operations and steps that WO
    generation turns into work).

  Each coating carries a default process (recipe_id). Parts can
  override that via the Process Composer, storing a part-scoped
  clone (default_process_id on fp.part.catalog). Resolution:
  part's composed process wins; coating default is the fallback.

Added a computed read-only `effective_process_id` field on
fp.direct.order.line that displays exactly what process will drive
WO generation for the line, plus a one-line `effective_process_source`
showing whether it came from the part ("customised") or the
coating ("default"). Both surfaced on the wizard list and form so
the estimator can verify before confirming the order.

No behaviour change — this is pure visibility. WO generation still
uses the same resolution chain it did before.

fusion_plating_configurator → 19.0.13.2.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-04-23 09:20:40 -04:00
parent 625f6560f1
commit 381a750902
3 changed files with 57 additions and 1 deletions

View File

@@ -5,7 +5,7 @@
{
'name': 'Fusion Plating — Configurator',
'version': '19.0.13.1.0',
'version': '19.0.13.2.0',
'category': 'Manufacturing/Plating',
'summary': 'Quotation configurator with part catalog, coating configs, and formula-based pricing engine.',
'description': """

View File

@@ -59,6 +59,47 @@ class FpDirectOrderLine(models.TransientModel):
string='Additional Treatments',
help='Extra pre/post treatments applied to this line.',
)
# Read-only preview of the process tree that WILL drive WO generation
# for this line. Resolution priority:
# 1. Part's composed process (fp.part.catalog.default_process_id)
# — a part-scoped customisation set via the Process Composer.
# 2. Primary Treatment's default recipe (fp.coating.config.recipe_id)
# — the shared template used if the part has no override.
# Shown so operators can see *what will run* before confirming the
# order. Treatment answers the "what coating"; process answers the
# "how" — they're distinct but coupled via the resolution chain.
effective_process_id = fields.Many2one(
'fusion.plating.process.node',
string='Process',
compute='_compute_effective_process',
help='Process tree that will generate work orders for this line. '
'Uses the part-composed process if one exists, otherwise the '
"primary treatment's default recipe.",
)
effective_process_source = fields.Char(
compute='_compute_effective_process',
help='Tells the estimator whether the process comes from the '
'part (customised) or the coating (shared default).',
)
@api.depends('part_catalog_id.default_process_id',
'coating_config_id.recipe_id')
def _compute_effective_process(self):
for rec in self:
part_proc = (rec.part_catalog_id.default_process_id
if rec.part_catalog_id else False)
if part_proc:
rec.effective_process_id = part_proc
rec.effective_process_source = 'Part (customised)'
continue
cc_proc = (rec.coating_config_id.recipe_id
if rec.coating_config_id else False)
if cc_proc:
rec.effective_process_id = cc_proc
rec.effective_process_source = 'Coating default'
continue
rec.effective_process_id = False
rec.effective_process_source = False
# ---- Qty / price ----
quantity = fields.Integer(string='Qty', default=1, required=True)

View File

@@ -106,6 +106,14 @@
<field name="internal_description"
optional="hide"/>
<field name="coating_config_id"/>
<field name="effective_process_id"
string="Process"
readonly="1"
optional="show"/>
<field name="effective_process_source"
string="Process Source"
readonly="1"
optional="hide"/>
<field name="thickness_id"
options="{'no_create': True}"
invisible="not coating_config_id"
@@ -143,6 +151,13 @@
<field name="coating_config_id"/>
<field name="treatment_ids"
widget="many2many_tags"/>
<field name="effective_process_id"
string="Effective Process"
readonly="1"/>
<field name="effective_process_source"
string="Source"
readonly="1"
invisible="not effective_process_id"/>
</group>
<group string="Qty &amp; Price">
<field name="quote_id"