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:
@@ -131,6 +131,21 @@ class FpPartCatalog(models.Model):
|
||||
notes = fields.Html(string='Notes')
|
||||
active = fields.Boolean(string='Active', default=True)
|
||||
|
||||
# ---- Direct-order defaults (Phase C — C4) ----
|
||||
x_fc_default_coating_config_id = fields.Many2one(
|
||||
'fp.coating.config',
|
||||
string='Default Treatment',
|
||||
help='Default coating applied when this part is dropped onto a '
|
||||
'direct order line. Updated when "Save as Default" is ticked.',
|
||||
)
|
||||
x_fc_default_treatment_ids = fields.Many2many(
|
||||
'fp.treatment',
|
||||
relation='fp_part_catalog_default_treatment_rel',
|
||||
string='Default Additional Treatments',
|
||||
help='Default additional treatments. Seeded when "Save as Default" '
|
||||
'is ticked on a direct order line.',
|
||||
)
|
||||
|
||||
# Substrate density mapping (g/cm³) for material weight calculation
|
||||
_SUBSTRATE_DENSITY = {
|
||||
'aluminium': 2.70,
|
||||
|
||||
@@ -224,6 +224,20 @@
|
||||
</list>
|
||||
</field>
|
||||
</page>
|
||||
<page string="Defaults" name="direct_order_defaults">
|
||||
<group>
|
||||
<field name="x_fc_default_coating_config_id"
|
||||
options="{'no_create_edit': True}"/>
|
||||
<field name="x_fc_default_treatment_ids"
|
||||
widget="many2many_tags"
|
||||
options="{'no_create_edit': True}"/>
|
||||
</group>
|
||||
<p class="text-muted">
|
||||
Seeds the treatment fields on new direct-order
|
||||
lines. Updated whenever "Save as Default" is
|
||||
ticked while placing an order.
|
||||
</p>
|
||||
</page>
|
||||
<page string="Notes" name="notes">
|
||||
<field name="notes" placeholder="Additional notes about this part..."/>
|
||||
</page>
|
||||
|
||||
@@ -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."""
|
||||
|
||||
@@ -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.'
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user