feat(phase1): top-level menu consolidation + landing-page resolver

Phase 1 collapses the Plating app's 17 top-level menus down to 6
domains (Sales, Operations, Receiving & Shipping, Quality,
Compliance, Configuration) so users no longer scroll a 17-item
sidebar to find one thing.

Re-parented (no XML id changes — bookmarks still work):
- fusion_plating_compliance.menu_fp_compliance_root
    → menu_fp_compliance_hub  (renamed 'General')
- fusion_plating_safety.menu_fp_safety_root
    → menu_fp_compliance_hub  (renamed 'Safety / WHMIS')
- fusion_plating_aerospace.menu_fp_aerospace
    → menu_fp_compliance_hub  (renamed 'Aerospace (AS9100 / Nadcap)')
- fusion_plating_nuclear.menu_fp_nuclear
    → menu_fp_compliance_hub  (renamed 'Nuclear (CSA N299 / CNSC)')
- fusion_plating_cgp.menu_fp_cgp
    → menu_fp_compliance_hub  (renamed 'Controlled Goods (CGP)')
- fusion_plating_certificates.menu_fp_certificates
    → menu_fp_quality (Certs are a Quality output, not a separate
      top-level concern)
- fusion_plating_bridge_maintenance.menu_fp_maintenance
    → menu_fp_operations
- fusion_plating.menu_fp_job_step_move (Move Log)
    → menu_fp_operations
- fusion_plating.menu_fp_job_step_timelog (Labor History)
    → menu_fp_operations

The new menu_fp_compliance_hub is supervisor-gated; underlying
verticals retain their own group locks (CGP officer, etc.).

Settings menu remains manager-gated through inheritance from
menu_fp_config (already in place).

NEW — Plating landing-page resolver:
- ir.actions.act_window.x_fc_pickable_landing  (Boolean tag for
  curated picklist; flagged on Sale Orders, Quotations, Process
  Recipes for Phase 1; more in Phase 2)
- res.company.x_fc_default_landing_action_id (admin sets fallback)
- res.users.x_fc_plating_landing_action_id (per-user override)
- ir.actions.server action_fp_resolve_plating_landing — picks
  user → company → Sale Orders fallback at click time
- menu_fp_root rewired to call the resolver
- User profile + Settings tabs surface the dropdowns

Configurator's earlier menu_fp_root override (action_fp_sale_orders
direct) removed — core's resolver now owns the routing.

Versions bumped: fusion_plating 19.0.11.0.0, configurator
19.0.17.16.0, plus 7 dependent modules patched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-04-27 22:33:37 -04:00
parent 3098fcfaf9
commit 0ad382e1a6
27 changed files with 273 additions and 41 deletions

View File

@@ -5,7 +5,7 @@
{
'name': 'Fusion Plating',
'version': '19.0.10.4.0',
'version': '19.0.11.0.0',
'category': 'Manufacturing/Plating',
'summary': 'Core plating / metal finishing ERP: facilities, processes, tanks, baths, jobs, operators.',
'description': """
@@ -81,6 +81,7 @@ Copyright (c) 2026 Nexa Systems Inc. All rights reserved.
'data': [
'security/fp_security.xml',
'security/ir.model.access.csv',
'data/fp_landing_data.xml',
'data/fp_sequence_data.xml',
'data/fp_job_sequences.xml',
'data/fp_process_category_data.xml',
@@ -99,6 +100,7 @@ Copyright (c) 2026 Nexa Systems Inc. All rights reserved.
'views/fp_bath_replenishment_views.xml',
'views/fp_operator_certification_views.xml',
'views/res_config_settings_views.xml',
'views/fp_landing_views.xml',
'views/fp_menu.xml',
'views/fp_work_centre_views.xml',
'views/fp_job_views.xml',

View File

@@ -0,0 +1,49 @@
<?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.
Phase 1 — Plating landing-page resolver.
The Plating app's root menu (menu_fp_root) calls this server action
on click. It resolves which window action to open in this priority
order:
1. user.x_fc_plating_landing_action_id (per-user override)
2. company.x_fc_default_landing_action_id (company default)
3. action_fp_sale_orders (hardcoded fallback)
Falls back to Sale Orders so that pre-Sub-12d users who haven't
set a preference still land on the Sale-Orders default we shipped
earlier in the session.
-->
<odoo noupdate="0">
<record id="action_fp_resolve_plating_landing" model="ir.actions.server">
<field name="name">Plating — Open Landing Page</field>
<field name="model_id" ref="base.model_res_users"/>
<field name="state">code</field>
<field name="code"><![CDATA[
# Resolve in priority order: user pref → company default → Sale Orders fallback.
user = env.user
target = False
if 'x_fc_plating_landing_action_id' in user._fields and user.x_fc_plating_landing_action_id:
target = user.x_fc_plating_landing_action_id.sudo()
elif 'x_fc_default_landing_action_id' in env.company._fields and env.company.x_fc_default_landing_action_id:
target = env.company.x_fc_default_landing_action_id.sudo()
if not target:
target = env.ref('fusion_plating_configurator.action_fp_sale_orders', raise_if_not_found=False)
if target:
action = target.sudo().read()[0]
# Strip ids that confuse the act_window dispatcher.
action.pop('id', None)
else:
# Last-ditch — open the Plating app's process recipes if even
# the Sale Orders action is missing (e.g. configurator not installed).
action = env.ref('fusion_plating.action_fp_process_recipe').sudo().read()[0]
action.pop('id', None)
]]></field>
</record>
</odoo>

View File

@@ -41,3 +41,6 @@ from . import fp_step_template_transition_input
# Sub 12b — Rack-aware moves + persistent labor reconciliation
from . import fp_rack_tag
from . import fp_job_step_move
# Phase 1 — Plating landing-page resolver
from . import fp_landing

View File

@@ -0,0 +1,61 @@
# -*- coding: utf-8 -*-
# Copyright 2026 Nexa Systems Inc.
# License OPL-1 (Odoo Proprietary License v1.0)
# Part of the Fusion Plating product family.
"""Phase 1 — Plating landing-page resolver fields.
Three pieces:
1. `ir.actions.act_window.x_fc_pickable_landing` — Boolean tag. Mark a
curated set of plating actions (Sale Orders, Plant Overview,
Quotations, Quality Dashboard, Manager Dashboard, Tablet Station,
Labor History) so the landing-page dropdown only offers sensible
options, not all 200 act_window records in the DB.
2. `res.company.x_fc_default_landing_action_id` — admin sets the
fallback for users who don't pick a preference.
3. `res.users.x_fc_plating_landing_action_id` — each user's own
override.
The resolver server action (data/fp_landing_data.xml) reads these.
"""
from odoo import fields, models
class IrActionsActWindow(models.Model):
_inherit = 'ir.actions.act_window'
x_fc_pickable_landing = fields.Boolean(
string='Pickable as Plating Landing',
default=False,
help='When True, this action appears in the Plating landing-'
'page dropdown on res.users and res.company. Tag a small '
'curated list (Sale Orders, Plant Overview, etc.) to keep '
'the picker manageable.',
)
class ResCompany(models.Model):
_inherit = 'res.company'
x_fc_default_landing_action_id = fields.Many2one(
'ir.actions.act_window',
string='Default Plating Landing Page',
domain=[('x_fc_pickable_landing', '=', True)],
help='Page that opens when a user clicks the Plating app, '
'unless the user has chosen their own override on their '
'preferences. Falls back to Sale Orders when blank.',
)
class ResUsers(models.Model):
_inherit = 'res.users'
x_fc_plating_landing_action_id = fields.Many2one(
'ir.actions.act_window',
string='My Plating Landing Page',
domain=[('x_fc_pickable_landing', '=', True)],
help='Personal override for the page that opens when you click '
'the Plating app. When blank, follows the company default.',
)

View File

@@ -62,3 +62,11 @@ class ResConfigSettings(models.TransientModel):
readonly=False,
string='Default Recipe Editor',
)
# ----- Phase 1 — Plating landing page default -----------------------
x_fc_default_landing_action_id = fields.Many2one(
'ir.actions.act_window',
related='company_id.x_fc_default_landing_action_id',
readonly=False,
string='Default Plating Landing Page',
)

View File

@@ -115,10 +115,11 @@
<field name="search_view_id" ref="view_fp_job_step_move_search"/>
</record>
<!-- Phase 1 — re-parented under Operations. -->
<menuitem id="menu_fp_job_step_move"
name="Move Log"
parent="menu_fp_root"
parent="menu_fp_operations"
action="action_fp_job_step_move"
sequence="62"/>
sequence="90"/>
</odoo>

View File

@@ -133,10 +133,11 @@
<field name="context">{'search_default_my_timers': 1}</field>
</record>
<!-- Phase 1 — re-parented under Operations. -->
<menuitem id="menu_fp_labor_history"
name="Labor History"
parent="menu_fp_root"
parent="menu_fp_operations"
action="action_fp_labor_history"
sequence="64"/>
sequence="95"/>
</odoo>

View File

@@ -0,0 +1,82 @@
<?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.
Phase 1 — Plating landing-page resolver UI.
Two surfaces:
1. Settings → Fusion Plating → Recipe Editor block (extended into
a Landing Page block for the company-level default).
2. User profile / preferences form — adds a Fusion Plating tab
with the per-user override dropdown.
-->
<odoo>
<!-- ====== User profile (Preferences > Fusion Plating tab) ====== -->
<record id="view_users_form_fp_landing" model="ir.ui.view">
<field name="name">res.users.form.fp.landing</field>
<field name="model">res.users</field>
<field name="inherit_id" ref="base.view_users_form"/>
<field name="arch" type="xml">
<xpath expr="//notebook" position="inside">
<page string="Fusion Plating" name="fp_landing">
<p class="text-muted">
Choose which page opens when you click the Plating
app. When blank, you see the company default
(Sale Orders unless an admin has changed it).
</p>
<group>
<field name="x_fc_plating_landing_action_id"
options="{'no_create': True, 'no_open': True}"/>
</group>
</page>
</xpath>
</field>
</record>
<!-- Same field surfaced on the simplified preferences form (the one
users open from the avatar menu — uses a different XML id). -->
<record id="view_users_form_simple_fp_landing" model="ir.ui.view">
<field name="name">res.users.form.simple.fp.landing</field>
<field name="model">res.users</field>
<field name="inherit_id" ref="base.view_users_form_simple_modif"/>
<field name="arch" type="xml">
<xpath expr="//notebook" position="inside">
<page string="Fusion Plating" name="fp_landing_simple">
<p class="text-muted">
Page that opens when you click the Plating app.
</p>
<group>
<field name="x_fc_plating_landing_action_id"
options="{'no_create': True, 'no_open': True}"/>
</group>
</page>
</xpath>
</field>
</record>
<!-- ====== Settings → Fusion Plating → Landing Page block ====== -->
<record id="res_config_settings_view_form_fp_landing" model="ir.ui.view">
<field name="name">res.config.settings.form.fp.landing</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="fusion_plating.res_config_settings_view_form_fp_core"/>
<field name="arch" type="xml">
<xpath expr="//block[@name='fp_recipe_editor_settings']"
position="after">
<block title="Plating Landing Page"
name="fp_landing_settings"
help="Page that opens when a user clicks the Plating app.">
<setting id="fp_default_landing_action"
string="Default Landing Page"
help="Users without a personal preference see this page. Each user can override it under their Profile > Preferences > Fusion Plating tab.">
<field name="x_fc_default_landing_action_id"
options="{'no_create': True, 'no_open': True}"/>
</setting>
</block>
</xpath>
</field>
</record>
</odoo>

View File

@@ -6,13 +6,26 @@
-->
<odoo>
<!-- ===== ROOT APP MENU ===== -->
<!-- ===== ROOT APP MENU =====
Landing action wired via the resolver server action below.
Per-user override > company default > Sale Orders fallback. -->
<menuitem id="menu_fp_root"
name="Plating"
sequence="46"
web_icon="fusion_plating,static/description/icon.png"
action="action_fp_resolve_plating_landing"
groups="group_fusion_plating_operator"/>
<!-- ===== Compliance hub (Phase 1) =====
Bundles General Compliance + Safety + Aerospace + Nuclear + CGP
under one top-level. Each vertical's existing root menu is
re-parented here in its own module. -->
<menuitem id="menu_fp_compliance_hub"
name="Compliance"
parent="menu_fp_root"
sequence="50"
groups="group_fusion_plating_supervisor"/>
<!-- ===== OPERATIONS ===== -->
<menuitem id="menu_fp_operations"
name="Operations"

View File

@@ -227,6 +227,7 @@
<field name="domain">[('node_type', '=', 'recipe')]</field>
<field name="context">{'default_node_type': 'recipe', 'search_default_recipes_only': 1}</field>
<field name="search_view_id" ref="view_fp_process_node_search"/>
<field name="x_fc_pickable_landing" eval="True"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create your first process recipe

View File

@@ -5,7 +5,7 @@
{
'name': 'Fusion Plating — Aerospace (AS9100 + Nadcap)',
'version': '19.0.1.0.0',
'version': '19.0.1.1.0',
'category': 'Manufacturing/Plating',
'summary': 'Aerospace industry pack: AS9100 Rev D clause library, Nadcap AC7108 '
'audits, counterfeit parts prevention, config management, risk register, '

View File

@@ -6,11 +6,11 @@
-->
<odoo>
<!-- ===== AEROSPACE (parent submenu under the Plating app) ===== -->
<!-- Phase 1 — re-parented under Plating → Compliance hub. -->
<menuitem id="menu_fp_aerospace"
name="Aerospace"
parent="fusion_plating.menu_fp_root"
sequence="60"
name="Aerospace (AS9100 / Nadcap)"
parent="fusion_plating.menu_fp_compliance_hub"
sequence="30"
groups="fusion_plating.group_fusion_plating_operator"/>
<menuitem id="menu_fp_aerospace_as9100"

View File

@@ -4,7 +4,7 @@
{
'name': 'Fusion Plating — Maintenance Bridge',
'version': '19.0.1.0.0',
'version': '19.0.1.1.0',
'category': 'Manufacturing/Plating',
'summary': 'Bridge standard Odoo Maintenance with Fusion Plating equipment, '
'plans, checklists, and sensor integration.',

View File

@@ -1,11 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- ===== Maintenance parent menu under Plating root ===== -->
<!-- Phase 1 — re-parented under Plating → Operations. Maintenance
is an Operations concern, not a separate top-level. -->
<menuitem id="menu_fp_maintenance"
name="Maintenance"
parent="fusion_plating.menu_fp_root"
sequence="22"
parent="fusion_plating.menu_fp_operations"
sequence="80"
groups="fusion_plating.group_fusion_plating_operator"/>
<menuitem id="menu_fp_maintenance_active"

View File

@@ -5,7 +5,7 @@
{
'name': 'Fusion Plating — Certificates',
'version': '19.0.5.3.0',
'version': '19.0.5.4.0',
'category': 'Manufacturing/Plating',
'summary': 'Certificate registry for CoC, thickness reports, and quality documents.',
'description': """

View File

@@ -16,11 +16,12 @@
<field name="domain">[('certificate_type', '=', 'thickness_report')]</field>
</record>
<!-- Menu under Fusion Plating root -->
<!-- Phase 1 — re-parented under Plating → Quality. Certificates are
a quality output, not a separate top-level concern. -->
<menuitem id="menu_fp_certificates"
name="Certificates"
parent="fusion_plating.menu_fp_root"
sequence="25"
parent="fusion_plating_quality.menu_fp_quality"
sequence="80"
groups="fusion_plating.group_fusion_plating_supervisor"/>
<menuitem id="menu_fp_certificates_all"

View File

@@ -5,7 +5,7 @@
{
'name': 'Fusion Plating — Controlled Goods Program',
'version': '19.0.1.0.0',
'version': '19.0.1.1.0',
'category': 'Manufacturing/Plating',
'summary': 'Canadian Controlled Goods Program (CGP) compliance for plating '
'shops handling defence work: registration, authorized individuals, '

View File

@@ -6,11 +6,11 @@
-->
<odoo>
<!-- ===== CGP (parent submenu under the Plating app) ===== -->
<!-- Phase 1 — re-parented under Plating → Compliance hub. -->
<menuitem id="menu_fp_cgp"
name="CGP"
parent="fusion_plating.menu_fp_root"
sequence="70"
name="Controlled Goods (CGP)"
parent="fusion_plating.menu_fp_compliance_hub"
sequence="50"
groups="group_fusion_plating_cgp_officer"/>
<menuitem id="menu_fp_cgp_registration"

View File

@@ -3,7 +3,7 @@
# License OPL-1 (Odoo Proprietary License v1.0)
{
'name': 'Fusion Plating - Compliance (Framework)',
'version': '19.0.1.1.0',
'version': '19.0.1.2.0',
'category': 'Manufacturing/Plating',
'summary': 'Jurisdiction-agnostic compliance framework: permits, discharge monitoring, waste manifests, pollutant inventory, compliance calendar, spill register.',
'description': 'Generic compliance framework. Region packs load jurisdiction-specific data.',

View File

@@ -1,6 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<menuitem id="menu_fp_compliance_root" name="Compliance" parent="fusion_plating.menu_fp_root" sequence="40"/>
<!-- Phase 1 — re-parented under fusion_plating.menu_fp_compliance_hub
and renamed to 'General' since the hub is now the top-level Compliance. -->
<menuitem id="menu_fp_compliance_root" name="General"
parent="fusion_plating.menu_fp_compliance_hub" sequence="10"/>
<menuitem id="menu_fp_compliance_permit" name="Permits" parent="menu_fp_compliance_root" action="action_fp_permit" sequence="10"/>
<menuitem id="menu_fp_compliance_discharge_sample" name="Discharge Samples" parent="menu_fp_compliance_root" action="action_fp_discharge_sample" sequence="20"/>

View File

@@ -5,7 +5,7 @@
{
'name': 'Fusion Plating — Configurator',
'version': '19.0.17.15.0',
'version': '19.0.17.16.0',
'category': 'Manufacturing/Plating',
'summary': 'Quotation configurator with part catalog, coating configs, and formula-based pricing engine.',
'description': """

View File

@@ -15,10 +15,14 @@
<field name="context">{'default_customer_rank': 1}</field>
</record>
<!-- Default landing screen for the Plating app = Sale Orders -->
<menuitem id="fusion_plating.menu_fp_root"
name="Plating"
action="action_fp_sale_orders"/>
<!--
The Plating app's landing screen is now resolved by a server
action defined in fusion_plating core (Phase 1):
user.x_fc_plating_landing_action_id →
company.x_fc_default_landing_action_id →
action_fp_sale_orders fallback
See fusion_plating/data/fp_landing_data.xml.
-->
<!-- ===== SALES submenu under Fusion Plating root ===== -->
<menuitem id="menu_fp_sales"

View File

@@ -467,6 +467,7 @@
(0, 0, {'view_mode': 'list', 'view_id': ref('view_sale_order_list_fp_quotes')})]"/>
<field name="search_view_id" ref="view_sale_order_search_fp_quotes"/>
<field name="context">{'default_x_fc_delivery_method': 'shipping_partner'}</field>
<field name="x_fc_pickable_landing" eval="True"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create a new quotation
@@ -482,6 +483,7 @@
<field name="domain">[('state', 'in', ('sale', 'done'))]</field>
<field name="view_ids" eval="[(5, 0, 0),
(0, 0, {'view_mode': 'list', 'view_id': ref('view_sale_order_list_fp')})]"/>
<field name="x_fc_pickable_landing" eval="True"/>
</record>
</odoo>

View File

@@ -5,7 +5,7 @@
{
'name': 'Fusion Plating — Nuclear (CSA N299, NQA-1)',
'version': '19.0.1.0.0',
'version': '19.0.1.1.0',
'category': 'Manufacturing/Plating',
'summary': 'Nuclear industry pack: CSA N299 Levels 1-4, NQA-1 awareness, '
'CNSC licence tracking, 10 CFR Part 21 reporting, ITPs, '

View File

@@ -6,11 +6,11 @@
-->
<odoo>
<!-- ===== NUCLEAR (top-level submenu under the Plating app) ===== -->
<!-- Phase 1 — re-parented under Plating → Compliance hub. -->
<menuitem id="menu_fp_nuclear"
name="Nuclear"
parent="fusion_plating.menu_fp_root"
sequence="65"
name="Nuclear (CSA N299 / CNSC)"
parent="fusion_plating.menu_fp_compliance_hub"
sequence="40"
groups="fusion_plating.group_fusion_plating_operator"/>
<menuitem id="menu_fp_nuclear_program"

View File

@@ -5,7 +5,7 @@
{
'name': 'Fusion Plating — Safety (EHS)',
'version': '19.0.1.0.0',
'version': '19.0.1.1.0',
'category': 'Manufacturing/Plating',
'summary': 'Occupational health and safety for plating shops: SDS library, '
'WHMIS/TDG training, exposure monitoring, JHSC, incidents, PPE, '

View File

@@ -6,11 +6,11 @@
-->
<odoo>
<!-- ===== SAFETY (top-level under Plating) ===== -->
<!-- Phase 1 — re-parented under Plating → Compliance hub. -->
<menuitem id="menu_fp_safety_root"
name="Safety"
parent="fusion_plating.menu_fp_root"
sequence="45"
name="Safety / WHMIS"
parent="fusion_plating.menu_fp_compliance_hub"
sequence="20"
groups="fusion_plating.group_fusion_plating_operator"/>
<menuitem id="menu_fp_safety_sds"