feat(configurator): C4 — push coating + treatments back to part catalog defaults

Adds x_fc_default_coating_config_id and x_fc_default_treatment_ids
fields on fp.part.catalog. Wizard line gets a push_to_defaults
toggle. After action_create_order confirms the SO, any line with
push_to_defaults=True writes its coating + treatments back onto the
part catalog entry as the new defaults.

Reverse direction too: onchange on part_catalog_id in the wizard
line seeds coating + treatments from the part's defaults (if set and
the line doesn't already have them).

Part catalog form gets a new "Defaults" tab showing the stored
defaults. Smoke-tested: pushing default on order 1 populates the
catalog entry; new wizard line for that part auto-seeds the coating.

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

View File

@@ -103,6 +103,11 @@ class FpDirectOrderLine(models.TransientModel):
help='Do not save this as a reusable part in the catalog after the '
'order is created. Useful for quote-only or prototype parts.',
)
push_to_defaults = fields.Boolean(
string='Save as Default',
help='After submit, write this line\'s coating + additional '
'treatments back onto the part catalog as its new defaults.',
)
# ---- Description ----
description_template_id = fields.Many2one(
@@ -138,6 +143,16 @@ class FpDirectOrderLine(models.TransientModel):
)
# ---- Onchange ----
@api.onchange('part_catalog_id')
def _onchange_part_defaults(self):
"""When a part is picked, seed coating + treatments from its catalog defaults."""
if not self.part_catalog_id:
return
if not self.coating_config_id and self.part_catalog_id.x_fc_default_coating_config_id:
self.coating_config_id = self.part_catalog_id.x_fc_default_coating_config_id
if not self.treatment_ids and self.part_catalog_id.x_fc_default_treatment_ids:
self.treatment_ids = self.part_catalog_id.x_fc_default_treatment_ids
@api.onchange('coating_config_id', 'quantity', 'part_catalog_id')
def _onchange_lookup_price(self):
"""Auto-fill unit_price from customer price list when available."""

View File

@@ -251,6 +251,20 @@ class FpDirectOrderWizard(models.TransientModel):
# 5. Create + confirm
so = self.env['sale.order'].create(so_vals)
so.action_confirm()
# 6. Push-to-defaults (C4) — after the part has been resolved /
# revision-bumped, write coating + treatments back onto the part
# catalog entry so the next order inherits the same defaults.
for line in self.line_ids:
if not line.push_to_defaults:
continue
part = line.part_catalog_id
if not part or line.is_one_off:
continue
part.write({
'x_fc_default_coating_config_id': line.coating_config_id.id or False,
'x_fc_default_treatment_ids': [(6, 0, line.treatment_ids.ids)],
})
so.message_post(body=_(
'Direct order created from PO %s with %d line(s). '
'Quotation stage skipped.'

View File

@@ -156,6 +156,8 @@
<field name="start_at_node_id"
options="{'no_create': True}"/>
<field name="is_one_off"/>
<field name="push_to_defaults"
invisible="is_one_off"/>
</group>
</form>
</field>