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:
gsinghpal
2026-04-23 08:45:24 -04:00
parent acb406950f
commit 625f6560f1
5 changed files with 126 additions and 2 deletions

View File

@@ -5,7 +5,7 @@
{
'name': 'Fusion Plating',
'version': '19.0.7.4.0',
'version': '19.0.8.0.0',
'category': 'Manufacturing/Plating',
'summary': 'Core plating / metal finishing ERP: facilities, processes, tanks, baths, jobs, operators.',
'description': """

View File

@@ -161,6 +161,7 @@
domain="[('node_type', '=', 'sub_process')]"/>
<filter name="operations" string="Operations"
domain="[('node_type', '=', 'operation')]"/>
<separator/>
<filter name="archived" string="Archived"
domain="[('active', '=', False)]"/>
<filter name="group_type" string="Type"
@@ -169,11 +170,17 @@
context="{'group_by': 'process_type_id'}"/>
<filter name="group_wc" string="Work Centre"
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>
</field>
</record>
<!-- ===== 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">
<field name="name">Process Recipes</field>
<field name="res_model">fusion.plating.process.node</field>

View File

@@ -5,7 +5,7 @@
{
'name': 'Fusion Plating — Configurator',
'version': '19.0.13.0.0',
'version': '19.0.13.1.0',
'category': 'Manufacturing/Plating',
'summary': 'Quotation configurator with part catalog, coating configs, and formula-based pricing engine.',
'description': """
@@ -42,6 +42,7 @@ Provides:
'data/fp_treatment_data.xml',
'views/fp_treatment_views.xml',
'views/fp_part_catalog_views.xml',
'views/fp_process_node_part_scoped_views.xml',
'views/fp_coating_config_views.xml',
'views/fp_pricing_rule_views.xml',
'views/fp_customer_price_list_views.xml',

View File

@@ -83,6 +83,26 @@
context="{'search_default_part_catalog_id': id, 'default_part_catalog_id': id}">
<field name="description_template_count" widget="statinfo" string="Descriptions"/>
</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>
<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"/>

View File

@@ -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 510 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>