From dcd5d2a1ec861199fe31becfe99f7836f1c546fd Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Tue, 21 Apr 2026 22:51:53 -0400 Subject: [PATCH] feat(configurator): direct-order wizard dual-description inputs + onchange (Sub 2 Task 16) Adds an `internal_description` text field to the direct-order wizard line so the shop-floor copy is captured at order entry alongside the customer-facing text. Picking a template now fires both sides of the onchange: `line_description` gets `customer_facing_description` (with fallback to the legacy `description` field for backward compat) and `internal_description` gets the template's internal text. The auto-suggest onchange was refactored around a tiny `_apply` helper so all three fallback paths populate both fields consistently. The template picker is surfaced as an optional column on the wizard list (hidden until a part is chosen, domain-scoped to that part) and as a dedicated labeled row in the per-line form. The internal text field is also surfaced in the form under "Line Description" so the estimator can review / edit it before confirm. On create_order, both `x_fc_description_template_id` and `x_fc_internal_description` are written through to the generated sale.order.line so the audit trail and WO printout stay linked. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../wizard/fp_direct_order_line.py | 41 +++++++++++++++---- .../wizard/fp_direct_order_wizard.py | 2 + .../wizard/fp_direct_order_wizard_views.xml | 16 +++++++- 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/fusion_plating/fusion_plating_configurator/wizard/fp_direct_order_line.py b/fusion_plating/fusion_plating_configurator/wizard/fp_direct_order_line.py index f0334f8b..dff3df07 100644 --- a/fusion_plating/fusion_plating_configurator/wizard/fp_direct_order_line.py +++ b/fusion_plating/fusion_plating_configurator/wizard/fp_direct_order_line.py @@ -125,9 +125,15 @@ class FpDirectOrderLine(models.TransientModel): ) line_description = fields.Text( string='Line Description', - help='This text becomes the description of the sale order line. ' + help='Customer-facing text. Becomes the SO line description and ' + 'prints on the acknowledgement, invoice, and packing slip. ' 'Edit freely — your changes override the template.', ) + internal_description = fields.Text( + string='Internal Description', + help='Shop-floor instructions. Prints on WO / traveler. Never on ' + 'customer docs. Edit freely — your changes override the template.', + ) # ---- Missing info per line ---- is_missing_info = fields.Boolean( @@ -195,8 +201,22 @@ class FpDirectOrderLine(models.TransientModel): @api.onchange('description_template_id') def _onchange_description_template(self): + """Auto-fill both descriptions from the chosen template. + + Customer-facing text lands in `line_description` (ends up on the + SO line `name`, prints on customer docs). Internal text lands in + `internal_description` (ends up in x_fc_internal_description on + the SO line, prints on WO / traveler only). Falls back to the + legacy `description` field when the new dual fields are empty so + pre-Sub-2 templates keep working. + """ if self.description_template_id: - self.line_description = self.description_template_id.description + tpl = self.description_template_id + customer_text = tpl.customer_facing_description or tpl.description + if customer_text: + self.line_description = customer_text + if tpl.internal_description: + self.internal_description = tpl.internal_description @api.onchange('part_catalog_id', 'coating_config_id') def _onchange_suggest_template(self): @@ -213,14 +233,21 @@ class FpDirectOrderLine(models.TransientModel): Template = self.env['fp.sale.description.template'] partner = self.wizard_id.partner_id + def _apply(match): + self.description_template_id = match.id + customer_text = match.customer_facing_description or match.description + if customer_text: + self.line_description = customer_text + if match.internal_description: + self.internal_description = match.internal_description + if self.part_catalog_id: match = Template.search([ ('active', '=', True), ('part_catalog_id', '=', self.part_catalog_id.id), ], order='sequence', limit=1) if match: - self.description_template_id = match.id - self.line_description = match.description + _apply(match) return if partner: @@ -230,8 +257,7 @@ class FpDirectOrderLine(models.TransientModel): ('partner_id', '=', partner.id), ], order='sequence', limit=1) if match: - self.description_template_id = match.id - self.line_description = match.description + _apply(match) return if self.coating_config_id: @@ -242,8 +268,7 @@ class FpDirectOrderLine(models.TransientModel): ('coating_config_id', '=', self.coating_config_id.id), ], order='sequence', limit=1) if match: - self.description_template_id = match.id - self.line_description = match.description + _apply(match) # ---- Helpers ---- def _get_or_bump_revision(self): diff --git a/fusion_plating/fusion_plating_configurator/wizard/fp_direct_order_wizard.py b/fusion_plating/fusion_plating_configurator/wizard/fp_direct_order_wizard.py index c134acf1..1f172c4e 100644 --- a/fusion_plating/fusion_plating_configurator/wizard/fp_direct_order_wizard.py +++ b/fusion_plating/fusion_plating_configurator/wizard/fp_direct_order_wizard.py @@ -259,6 +259,8 @@ class FpDirectOrderWizard(models.TransientModel): 'product_uom_qty': line.quantity, 'price_unit': line.unit_price or 0.0, 'x_fc_part_catalog_id': part.id, + 'x_fc_description_template_id': line.description_template_id.id or False, + 'x_fc_internal_description': line.internal_description or False, 'x_fc_coating_config_id': line.coating_config_id.id, 'x_fc_treatment_ids': [(6, 0, line.treatment_ids.ids)], 'x_fc_part_deadline': line.part_deadline, diff --git a/fusion_plating/fusion_plating_configurator/wizard/fp_direct_order_wizard_views.xml b/fusion_plating/fusion_plating_configurator/wizard/fp_direct_order_wizard_views.xml index fa848c42..52ab676c 100644 --- a/fusion_plating/fusion_plating_configurator/wizard/fp_direct_order_wizard_views.xml +++ b/fusion_plating/fusion_plating_configurator/wizard/fp_direct_order_wizard_views.xml @@ -98,6 +98,13 @@ context="{'default_partner_id': parent.partner_id}" domain="[('partner_id', '=', parent.partner_id), ('is_latest_revision', '=', True)]" options="{'no_create_edit': True}"/> + + +