feat(configurator): auto-load latest part description version on order entry
Wizard line (direct + express) and SO line now pre-fill BOTH internal + customer-facing from the part's latest version (fallback to default_specification_text), without clobbering typed text. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -42,6 +42,20 @@ class SaleOrderLine(models.Model):
|
|||||||
return tail.lstrip(' \t\r\n-—–:').strip()
|
return tail.lstrip(' \t\r\n-—–:').strip()
|
||||||
return name
|
return name
|
||||||
|
|
||||||
|
@api.onchange('x_fc_part_catalog_id')
|
||||||
|
def _fp_onchange_part_load_description(self):
|
||||||
|
"""Pre-fill name (customer-facing) + x_fc_internal_description from
|
||||||
|
the part's latest description version, when empty (spec 2026-05-29)."""
|
||||||
|
for line in self:
|
||||||
|
part = line.x_fc_part_catalog_id
|
||||||
|
if not part:
|
||||||
|
continue
|
||||||
|
descs = part._fp_resolve_line_descriptions()
|
||||||
|
if not line.name and descs['customer_facing']:
|
||||||
|
line.name = descs['customer_facing']
|
||||||
|
if not line.x_fc_internal_description and descs['internal']:
|
||||||
|
line.x_fc_internal_description = descs['internal']
|
||||||
|
|
||||||
x_fc_part_catalog_id = fields.Many2one(
|
x_fc_part_catalog_id = fields.Many2one(
|
||||||
'fp.part.catalog', string='Part',
|
'fp.part.catalog', string='Part',
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -72,3 +72,13 @@ class TestPartDescriptionHistory(TransactionCase):
|
|||||||
[('part_catalog_id', '=', self.part.id)])
|
[('part_catalog_id', '=', self.part.id)])
|
||||||
self.assertEqual(len(versions), 2)
|
self.assertEqual(len(versions), 2)
|
||||||
self.assertEqual(self.part.default_specification_text, 'c2')
|
self.assertEqual(self.part.default_specification_text, 'c2')
|
||||||
|
|
||||||
|
# ----- Task 5: SO line auto-load -----
|
||||||
|
def test_so_line_onchange_loads_latest_version(self):
|
||||||
|
self.part._fp_save_description_version('shop notes', 'cust spec')
|
||||||
|
line = self.env['sale.order.line'].new({
|
||||||
|
'x_fc_part_catalog_id': self.part.id,
|
||||||
|
})
|
||||||
|
line._fp_onchange_part_load_description()
|
||||||
|
self.assertEqual(line.name, 'cust spec')
|
||||||
|
self.assertEqual(line.x_fc_internal_description, 'shop notes')
|
||||||
|
|||||||
@@ -629,12 +629,16 @@ class FpDirectOrderLine(models.Model):
|
|||||||
if bake_default:
|
if bake_default:
|
||||||
rec.bake_instructions = bake_default
|
rec.bake_instructions = bake_default
|
||||||
|
|
||||||
# ---- Express line_description (Specification) ----
|
# ---- Description history auto-load (spec 2026-05-29) ----
|
||||||
# Only seed if currently empty (don't clobber operator-typed text).
|
# Latest per-part version wins; _fp_resolve_line_descriptions
|
||||||
if not rec.line_description:
|
# falls back to default_specification_text (customer-facing only)
|
||||||
spec_default = getattr(part, 'default_specification_text', None)
|
# for parts with no version yet. Loads BOTH fields; never
|
||||||
if spec_default:
|
# clobbers text the operator already typed.
|
||||||
rec.line_description = spec_default
|
descs = part._fp_resolve_line_descriptions()
|
||||||
|
if not rec.line_description and descs['customer_facing']:
|
||||||
|
rec.line_description = descs['customer_facing']
|
||||||
|
if not rec.internal_description and descs['internal']:
|
||||||
|
rec.internal_description = descs['internal']
|
||||||
|
|
||||||
# ---- Express masking_enabled (always re-seed from part default) ----
|
# ---- Express masking_enabled (always re-seed from part default) ----
|
||||||
# Boolean has no "empty" state; explicit reseed on every part-change
|
# Boolean has no "empty" state; explicit reseed on every part-change
|
||||||
|
|||||||
Reference in New Issue
Block a user