fix(configurator): part-level saved descriptions (not generic)
The earlier description templates were global — same 8 generic texts
applied to any part. That's useless when a customer has 3,500 parts
and each part has 3–5 canned variants (standard, masked threads,
masked bore, rework, rush packaging). That's ~17,500 rows total, and
the variants ONLY make sense in the context of a specific part number.
Restructured so descriptions live on each part:
Model changes:
fp.sale.description.template.part_catalog_id (new M2O, indexed,
ondelete cascade) — the primary scoping field
fp.sale.description.template.partner_id — now a related store=True
field pulled from the part, so customer-level search still works
fp.part.catalog.description_template_ids (new O2M inverse) — the
5–10 canned descriptions attached to this specific part
fp.part.catalog.description_template_count (computed)
UI changes:
Part Catalog form: new "Descriptions" notebook page with inline
editable list (sequence + name + tag + description + usage_count).
5 variants take 30 seconds to enter.
Part Catalog form: new smart button "Descriptions" showing the count,
jumps to the full list filtered by this part.
Template list view: part_catalog_id column added, list ordered by
part first. Search view adds Part filter + Part-Specific /
Generic (No Part) filters + Group By Part.
Wizard changes:
description_template_id domain now prioritises part-specific, falls
through to partner, coating, or generic on a single dynamic domain.
_onchange_suggest_template priority: part → customer → coating →
none. No longer auto-picks a random global template when a part
has its own.
Smoke-tested on VS-HSA201-B (Amphenol):
5 canned variants seeded on the part form
Wizard with this part auto-suggested the lowest-sequence one
The part's Descriptions smart button shows "5"
Bulk data entry path for the client's 3,500 parts: either use the
inline list on each part form, or import via CSV with the new
part_catalog_id column (external_id or DB id).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -76,6 +76,13 @@
|
||||
invisible="revision_count < 2">
|
||||
<field name="revision_count" widget="statinfo" string="Revisions"/>
|
||||
</button>
|
||||
<button name="%(action_fp_sale_description_template)d"
|
||||
type="action"
|
||||
class="oe_stat_button"
|
||||
icon="fa-file-text-o"
|
||||
context="{'search_default_part_catalog_id': id, 'default_part_catalog_id': id}">
|
||||
<field name="description_template_count" widget="statinfo" string="Descriptions"/>
|
||||
</button>
|
||||
</div>
|
||||
<widget name="web_ribbon" title="Archived" bg_color="text-bg-danger" invisible="active"/>
|
||||
<widget name="web_ribbon" title="Superseded" bg_color="text-bg-warning" invisible="is_latest_revision"/>
|
||||
@@ -181,6 +188,28 @@
|
||||
<field name="model_attachment_id" widget="fp_3d_preview" nolabel="1"/>
|
||||
</div>
|
||||
</page>
|
||||
<page string="Descriptions" name="descriptions">
|
||||
<p class="text-muted">
|
||||
Canned descriptions for this part. Whichever one the
|
||||
estimator picks on the order wizard lands on the SO
|
||||
line — they can tweak the text before confirming.
|
||||
Typically 3–5 variants per part (e.g. <em>Standard</em>,
|
||||
<em>With threaded holes masked</em>, <em>Special
|
||||
packaging</em>).
|
||||
</p>
|
||||
<field name="description_template_ids"
|
||||
context="{'default_part_catalog_id': id, 'default_partner_id': partner_id}">
|
||||
<list editable="bottom">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name" placeholder="e.g. Standard, or With masking, etc."/>
|
||||
<field name="tag"/>
|
||||
<field name="description"
|
||||
placeholder="Full description text that lands on the order line..."/>
|
||||
<field name="usage_count" readonly="1" optional="show"/>
|
||||
<field name="active" widget="boolean_toggle"/>
|
||||
</list>
|
||||
</field>
|
||||
</page>
|
||||
<page string="Revision History" name="revisions"
|
||||
invisible="not parent_part_id and not revision_ids">
|
||||
<field name="revision_ids" mode="list">
|
||||
|
||||
@@ -14,14 +14,15 @@
|
||||
<field name="arch" type="xml">
|
||||
<list multi_edit="1">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="part_catalog_id" optional="show"/>
|
||||
<field name="name"/>
|
||||
<field name="tag" widget="badge"
|
||||
decoration-info="tag == 'standard'"
|
||||
decoration-warning="tag == 'masking'"
|
||||
decoration-danger="tag == 'rework'"
|
||||
decoration-success="tag in ('aerospace','nuclear')"/>
|
||||
<field name="coating_config_id" optional="show"/>
|
||||
<field name="partner_id" optional="show"/>
|
||||
<field name="coating_config_id" optional="hide"/>
|
||||
<field name="usage_count" string="Used"/>
|
||||
<field name="active" widget="boolean_toggle"/>
|
||||
</list>
|
||||
@@ -40,11 +41,14 @@
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="part_catalog_id"/>
|
||||
<field name="partner_id" readonly="part_catalog_id"/>
|
||||
<field name="tag"/>
|
||||
<field name="coating_config_id"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="partner_id"/>
|
||||
<field name="coating_config_id"
|
||||
help="Only used for generic (no-part) templates."
|
||||
invisible="part_catalog_id"/>
|
||||
<field name="sequence"/>
|
||||
<field name="usage_count" readonly="1"/>
|
||||
<field name="active" widget="boolean_toggle"/>
|
||||
@@ -66,15 +70,22 @@
|
||||
<search>
|
||||
<field name="name"/>
|
||||
<field name="description"/>
|
||||
<field name="part_catalog_id"/>
|
||||
<field name="coating_config_id"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="tag"/>
|
||||
<filter name="active" string="Active" domain="[('active','=',True)]"/>
|
||||
<filter name="with_part" string="Part-Specific"
|
||||
domain="[('part_catalog_id','!=',False)]"/>
|
||||
<filter name="no_part" string="Generic (No Part)"
|
||||
domain="[('part_catalog_id','=',False)]"/>
|
||||
<group>
|
||||
<filter name="group_part" string="Part"
|
||||
context="{'group_by': 'part_catalog_id'}"/>
|
||||
<filter name="group_customer" string="Customer"
|
||||
context="{'group_by': 'partner_id'}"/>
|
||||
<filter name="group_tag" string="Category"
|
||||
context="{'group_by': 'tag'}"/>
|
||||
<filter name="group_coating" string="Coating"
|
||||
context="{'group_by': 'coating_config_id'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
|
||||
Reference in New Issue
Block a user