feat(configurator): Phase C polish — to-node picker, WO description, one-off flag

C1: start_at_node_id per wizard line, mirrors to x_fc_start_at_node_id
on sale.order.line. Domain filters to nodes descending from the
coating_config's recipe so the estimator only picks valid resume
points. bridge_mrp will use this in a follow-up to skip ancestor
steps in the generated work order.

C2: part_wo_description (separate from customer-facing line_description)
lets the planner add internal-only notes that appear on the travelling
sheet only. Mirrors to x_fc_part_wo_description on sale.order.line.

C5: is_one_off flag for prototype / non-catalog parts. Mirrors to
x_fc_is_one_off. Actual skip-catalog behaviour will be wired in a
later pass.

All three fields appear in the wizard line drill-in form (under a new
"Work Order (internal)" group) and as togglable columns on the
sale.order.line tree.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-04-19 21:01:25 -04:00
parent 059276886d
commit 43a26b6849
5 changed files with 48 additions and 0 deletions

View File

@@ -25,3 +25,19 @@ class SaleOrderLine(models.Model):
help='Lines sharing a tag (e.g. "WO#1") will be batched into one ' help='Lines sharing a tag (e.g. "WO#1") will be batched into one '
'manufacturing order when bridge_mrp generates MOs.', 'manufacturing order when bridge_mrp generates MOs.',
) )
x_fc_part_wo_description = fields.Text(
string='On Work Order',
help='Extra detail printed on the work order travelling sheet. '
'Separate from the customer-facing line description.',
)
x_fc_start_at_node_id = fields.Many2one(
'fusion.plating.process.node',
string='Start at Node',
help='For re-work jobs: pick the recipe step where this job '
'should begin. bridge_mrp skips ancestor steps.',
)
x_fc_is_one_off = fields.Boolean(
string='One-off Part',
help='Flag for prototype / non-catalog parts that should not be '
'reused after this order.',
)

View File

@@ -101,6 +101,8 @@
<field name="x_fc_treatment_ids" widget="many2many_tags" optional="hide"/> <field name="x_fc_treatment_ids" widget="many2many_tags" optional="hide"/>
<field name="x_fc_part_deadline" optional="hide"/> <field name="x_fc_part_deadline" optional="hide"/>
<field name="x_fc_wo_group_tag" optional="hide"/> <field name="x_fc_wo_group_tag" optional="hide"/>
<field name="x_fc_start_at_node_id" optional="hide"/>
<field name="x_fc_is_one_off" optional="hide"/>
<field name="x_fc_rush_order" optional="hide"/> <field name="x_fc_rush_order" optional="hide"/>
</xpath> </xpath>
</field> </field>

View File

@@ -85,6 +85,25 @@ class FpDirectOrderLine(models.TransientModel):
'will be batched into one manufacturing order.', 'will be batched into one manufacturing order.',
) )
# ---- Phase C: polish ----
part_wo_description = fields.Text(
string='On Work Order',
help='Extra detail printed on the work order travelling sheet. '
'Kept separate from the customer-facing description.',
)
start_at_node_id = fields.Many2one(
'fusion.plating.process.node',
string='Start at Node',
domain="[('parent_id', 'child_of', coating_config_id and coating_config_id.recipe_id.id)]",
help='For re-work jobs: pick the recipe step where this job should '
'begin. Skips ancestor steps in the generated work order.',
)
is_one_off = fields.Boolean(
string='One-off Part',
help='Do not save this as a reusable part in the catalog after the '
'order is created. Useful for quote-only or prototype parts.',
)
# ---- Description ---- # ---- Description ----
description_template_id = fields.Many2one( description_template_id = fields.Many2one(
'fp.sale.description.template', 'fp.sale.description.template',

View File

@@ -243,6 +243,9 @@ class FpDirectOrderWizard(models.TransientModel):
'x_fc_part_deadline': line.part_deadline, 'x_fc_part_deadline': line.part_deadline,
'x_fc_rush_order': line.rush_order, 'x_fc_rush_order': line.rush_order,
'x_fc_wo_group_tag': line.wo_group_tag or False, 'x_fc_wo_group_tag': line.wo_group_tag or False,
'x_fc_part_wo_description': line.part_wo_description or False,
'x_fc_start_at_node_id': line.start_at_node_id.id or False,
'x_fc_is_one_off': line.is_one_off,
})) }))
# 5. Create + confirm # 5. Create + confirm

View File

@@ -149,6 +149,14 @@
nolabel="1" colspan="2" nolabel="1" colspan="2"
placeholder="Pick a template above, then tweak the text here."/> placeholder="Pick a template above, then tweak the text here."/>
</group> </group>
<group string="Work Order (internal)">
<field name="part_wo_description"
nolabel="1" colspan="2"
placeholder="Extra detail for the travelling sheet. Not shown to the customer."/>
<field name="start_at_node_id"
options="{'no_create': True}"/>
<field name="is_one_off"/>
</group>
</form> </form>
</field> </field>
<group class="mt-3"> <group class="mt-3">