feat(plating): split templates vs part-scoped processes + Process smart button
Two user-reported gaps: 1. The Process Recipes list was about to be flooded by part-scoped clones as soon as parts started carrying customised processes — thousands of clones would bury the handful of real shared templates (General Processing, Anodize, etc.). Fix: the main Process Recipes action now narrows to part_catalog_id = False so shared templates stay alone in that view. A sibling menu "Part Processes" (Plating → Operations → Part Processes) shows the inverse list — every part-cloned process, grouped by part — so admins can audit clones without cluttering the templates list. Search view gains two toggle filters (Shared Templates / Part-Scoped) and a "Group by Part" option. The node list gains an optional "Part" column. Split across modules: core owns the base search / tree / action (unchanged); configurator owns all the part_catalog_id-dependent pieces (filter extensions, list column, narrower domain, "Part Processes" action + menu). Keeps the dependency direction clean — configurator always depends on core, never the other way. 2. Added a "Process" smart button to the part form's button box. Shows either a green check (composed) or "None" (not yet composed) and opens the part-scoped Composer on click. Gives users one-tap access from any part form without hunting through the Process tab. fusion_plating → 19.0.8.0.0 fusion_plating_configurator → 19.0.13.1.0 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
'name': 'Fusion Plating',
|
'name': 'Fusion Plating',
|
||||||
'version': '19.0.7.4.0',
|
'version': '19.0.8.0.0',
|
||||||
'category': 'Manufacturing/Plating',
|
'category': 'Manufacturing/Plating',
|
||||||
'summary': 'Core plating / metal finishing ERP: facilities, processes, tanks, baths, jobs, operators.',
|
'summary': 'Core plating / metal finishing ERP: facilities, processes, tanks, baths, jobs, operators.',
|
||||||
'description': """
|
'description': """
|
||||||
|
|||||||
@@ -161,6 +161,7 @@
|
|||||||
domain="[('node_type', '=', 'sub_process')]"/>
|
domain="[('node_type', '=', 'sub_process')]"/>
|
||||||
<filter name="operations" string="Operations"
|
<filter name="operations" string="Operations"
|
||||||
domain="[('node_type', '=', 'operation')]"/>
|
domain="[('node_type', '=', 'operation')]"/>
|
||||||
|
<separator/>
|
||||||
<filter name="archived" string="Archived"
|
<filter name="archived" string="Archived"
|
||||||
domain="[('active', '=', False)]"/>
|
domain="[('active', '=', False)]"/>
|
||||||
<filter name="group_type" string="Type"
|
<filter name="group_type" string="Type"
|
||||||
@@ -169,11 +170,17 @@
|
|||||||
context="{'group_by': 'process_type_id'}"/>
|
context="{'group_by': 'process_type_id'}"/>
|
||||||
<filter name="group_wc" string="Work Centre"
|
<filter name="group_wc" string="Work Centre"
|
||||||
context="{'group_by': 'work_center_id'}"/>
|
context="{'group_by': 'work_center_id'}"/>
|
||||||
|
<!-- Part-scoped filters live in fusion_plating_configurator;
|
||||||
|
the part_catalog_id field is declared there (core
|
||||||
|
can't see it without a circular dep). -->
|
||||||
</search>
|
</search>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!-- ===== WINDOW ACTION — Recipe list ===== -->
|
<!-- ===== WINDOW ACTION — Recipe list ===== -->
|
||||||
|
<!-- Domain only narrows by node_type in core. The configurator
|
||||||
|
module adds the part_catalog_id = False narrowing via a
|
||||||
|
view/action inherit (see fusion_plating_configurator). -->
|
||||||
<record id="action_fp_process_recipe" model="ir.actions.act_window">
|
<record id="action_fp_process_recipe" model="ir.actions.act_window">
|
||||||
<field name="name">Process Recipes</field>
|
<field name="name">Process Recipes</field>
|
||||||
<field name="res_model">fusion.plating.process.node</field>
|
<field name="res_model">fusion.plating.process.node</field>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
'name': 'Fusion Plating — Configurator',
|
'name': 'Fusion Plating — Configurator',
|
||||||
'version': '19.0.13.0.0',
|
'version': '19.0.13.1.0',
|
||||||
'category': 'Manufacturing/Plating',
|
'category': 'Manufacturing/Plating',
|
||||||
'summary': 'Quotation configurator with part catalog, coating configs, and formula-based pricing engine.',
|
'summary': 'Quotation configurator with part catalog, coating configs, and formula-based pricing engine.',
|
||||||
'description': """
|
'description': """
|
||||||
@@ -42,6 +42,7 @@ Provides:
|
|||||||
'data/fp_treatment_data.xml',
|
'data/fp_treatment_data.xml',
|
||||||
'views/fp_treatment_views.xml',
|
'views/fp_treatment_views.xml',
|
||||||
'views/fp_part_catalog_views.xml',
|
'views/fp_part_catalog_views.xml',
|
||||||
|
'views/fp_process_node_part_scoped_views.xml',
|
||||||
'views/fp_coating_config_views.xml',
|
'views/fp_coating_config_views.xml',
|
||||||
'views/fp_pricing_rule_views.xml',
|
'views/fp_pricing_rule_views.xml',
|
||||||
'views/fp_customer_price_list_views.xml',
|
'views/fp_customer_price_list_views.xml',
|
||||||
|
|||||||
@@ -83,6 +83,26 @@
|
|||||||
context="{'search_default_part_catalog_id': id, 'default_part_catalog_id': id}">
|
context="{'search_default_part_catalog_id': id, 'default_part_catalog_id': id}">
|
||||||
<field name="description_template_count" widget="statinfo" string="Descriptions"/>
|
<field name="description_template_count" widget="statinfo" string="Descriptions"/>
|
||||||
</button>
|
</button>
|
||||||
|
<!-- Sub 3 follow-up: Process smart button. Click
|
||||||
|
opens the part-scoped Process Composer so
|
||||||
|
users have a one-tap path from any part
|
||||||
|
form to its process tree. -->
|
||||||
|
<button name="action_open_part_composer"
|
||||||
|
type="object"
|
||||||
|
class="oe_stat_button"
|
||||||
|
icon="fa-sitemap">
|
||||||
|
<div class="o_stat_info">
|
||||||
|
<span class="o_stat_value"
|
||||||
|
invisible="default_process_id">
|
||||||
|
None
|
||||||
|
</span>
|
||||||
|
<span class="o_stat_value text-success"
|
||||||
|
invisible="not default_process_id">
|
||||||
|
<i class="fa fa-check-circle"/>
|
||||||
|
</span>
|
||||||
|
<span class="o_stat_text">Process</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<widget name="web_ribbon" title="Archived" bg_color="text-bg-danger" invisible="active"/>
|
<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"/>
|
<widget name="web_ribbon" title="Superseded" bg_color="text-bg-warning" invisible="is_latest_revision"/>
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright 2026 Nexa Systems Inc.
|
||||||
|
License OPL-1 (Odoo Proprietary License v1.0)
|
||||||
|
Part of the Fusion Plating product family.
|
||||||
|
|
||||||
|
Separates shared recipe templates from part-scoped clones in the
|
||||||
|
backend so thousands of part clones don't bury the 5–10 real
|
||||||
|
templates in the main Recipes list.
|
||||||
|
|
||||||
|
* Narrow the existing Process Recipes action to templates only
|
||||||
|
(part_catalog_id = False).
|
||||||
|
* Add a sibling "Part Processes" menu + action for audit /
|
||||||
|
administration of every clone, grouped by part by default.
|
||||||
|
* Extend the search view with template / part-scoped toggles
|
||||||
|
so admins can cross between the two lists without switching
|
||||||
|
menus.
|
||||||
|
-->
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<!-- ========== Extend search view: add part_catalog_id filters ========== -->
|
||||||
|
<record id="view_fp_process_node_search_part_scoped"
|
||||||
|
model="ir.ui.view">
|
||||||
|
<field name="name">fusion.plating.process.node.search.part.scoped</field>
|
||||||
|
<field name="model">fusion.plating.process.node</field>
|
||||||
|
<field name="inherit_id"
|
||||||
|
ref="fusion_plating.view_fp_process_node_search"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//filter[@name='operations']" position="after">
|
||||||
|
<separator/>
|
||||||
|
<filter name="templates_only"
|
||||||
|
string="Shared Templates"
|
||||||
|
domain="[('part_catalog_id', '=', False)]"/>
|
||||||
|
<filter name="part_scoped"
|
||||||
|
string="Part-Scoped"
|
||||||
|
domain="[('part_catalog_id', '!=', False)]"/>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//filter[@name='group_wc']" position="after">
|
||||||
|
<filter name="group_part" string="Part"
|
||||||
|
context="{'group_by': 'part_catalog_id'}"/>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- ========== Extend list view: surface part column ========== -->
|
||||||
|
<record id="view_fp_process_node_tree_part_scoped"
|
||||||
|
model="ir.ui.view">
|
||||||
|
<field name="name">fusion.plating.process.node.tree.part.scoped</field>
|
||||||
|
<field name="model">fusion.plating.process.node</field>
|
||||||
|
<field name="inherit_id"
|
||||||
|
ref="fusion_plating.view_fp_process_node_tree"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//field[@name='name']" position="after">
|
||||||
|
<field name="part_catalog_id" string="Part" optional="show"/>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- ========== Narrow main Recipes action to templates only ========== -->
|
||||||
|
<record id="fusion_plating.action_fp_process_recipe"
|
||||||
|
model="ir.actions.act_window">
|
||||||
|
<field name="domain">[('node_type', '=', 'recipe'), ('part_catalog_id', '=', False)]</field>
|
||||||
|
<field name="context">{'default_node_type': 'recipe', 'search_default_recipes_only': 1, 'search_default_templates_only': 1}</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- ========== NEW action — Part Processes ========== -->
|
||||||
|
<record id="action_fp_process_recipe_part_scoped"
|
||||||
|
model="ir.actions.act_window">
|
||||||
|
<field name="name">Part Processes</field>
|
||||||
|
<field name="res_model">fusion.plating.process.node</field>
|
||||||
|
<field name="view_mode">list,form</field>
|
||||||
|
<field name="domain">[('node_type', '=', 'recipe'), ('part_catalog_id', '!=', False)]</field>
|
||||||
|
<field name="context">{'search_default_part_scoped': 1, 'search_default_group_part': 1}</field>
|
||||||
|
<field name="search_view_id"
|
||||||
|
ref="fusion_plating.view_fp_process_node_search"/>
|
||||||
|
<field name="help" type="html">
|
||||||
|
<p class="o_view_nocontent_smiling_face">
|
||||||
|
No part-customised processes yet
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
This view lists every process tree that has been
|
||||||
|
composed for a specific part via the part form's
|
||||||
|
<b>Compose</b> button. Each row is a clone of a shared
|
||||||
|
template with per-part tweaks. To browse the shared
|
||||||
|
templates themselves, use <b>Process Recipes</b>.
|
||||||
|
</p>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<menuitem id="menu_fp_process_part_scoped"
|
||||||
|
name="Part Processes"
|
||||||
|
parent="fusion_plating.menu_fp_operations"
|
||||||
|
action="action_fp_process_recipe_part_scoped"
|
||||||
|
sequence="6"/>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
Reference in New Issue
Block a user