This commit is contained in:
gsinghpal
2026-05-01 00:20:40 -04:00
parent bdcbd86db2
commit 1da27ed6bf
8 changed files with 117 additions and 12 deletions

View File

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

View File

@@ -9,7 +9,7 @@ to depend on the configurator. Any field that references a model defined
in configurator — like fp.pricing.rule, fp.part.catalog — must be
declared here.
"""
from odoo import fields, models
from odoo import api, fields, models, _
class FpProcessNode(models.Model):
@@ -73,3 +73,47 @@ class FpProcessNode(models.Model):
help='Friendly label shown in the variant picker '
'(e.g. "Standard ENP", "Selective Masking", "Rework").',
)
# ---- Linked Parts (cloned recipes) --------------------------------------
# On a shared template recipe, count + open all part-cloned recipe
# roots that were copied from this template (cloned_from_id == self).
# Only meaningful on shared templates (part_catalog_id IS NULL,
# node_type='recipe').
cloned_recipe_count = fields.Integer(
string='Linked Part Recipes',
compute='_compute_cloned_recipe_count',
)
def _compute_cloned_recipe_count(self):
Node = self.env['fusion.plating.process.node']
groups = Node._read_group(
domain=[
('cloned_from_id', 'in', self.ids),
('node_type', '=', 'recipe'),
('part_catalog_id', '!=', False),
],
groupby=['cloned_from_id'],
aggregates=['__count'],
)
counts = {src.id: count for src, count in groups}
for rec in self:
rec.cloned_recipe_count = counts.get(rec.id, 0)
def action_open_cloned_recipes(self):
"""Open the list of part-cloned recipe roots that came from this
template (i.e. cloned_from_id == self)."""
self.ensure_one()
return {
'type': 'ir.actions.act_window',
'name': _('Linked Parts — %s', self.name),
'res_model': 'fusion.plating.process.node',
'view_mode': 'list,form',
'domain': [
('cloned_from_id', '=', self.id),
('node_type', '=', 'recipe'),
('part_catalog_id', '!=', False),
],
'context': {
'search_default_group_part': 1,
},
}

View File

@@ -217,6 +217,18 @@ export class FpPartProcessComposer extends Component {
}
backToPart() {
// Pop this composer off the action stack and restore the
// previous controller (the part form the user came from).
// Preserves the full breadcrumb trail — clearBreadcrumbs: true
// would wipe parent crumbs (e.g. "Parts > 2144A6201-105").
// Falls back to the part form only when restore() throws (e.g.
// composer opened directly via URL with no prior crumb).
try {
this.action.restore();
return;
} catch (e) {
// No prior controller — fall through to the part form.
}
this.action.doAction({
type: "ir.actions.act_window",
res_model: "fp.part.catalog",

View File

@@ -42,6 +42,28 @@
</field>
</record>
<!-- ========== Extend form view: Linked Parts smart button ========== -->
<!-- Smart button visible only on shared template recipes (no
part_catalog_id). Opens the list of part-cloned recipe roots
that were copied from this template. -->
<record id="view_fp_process_node_form_linked_parts"
model="ir.ui.view">
<field name="name">fusion.plating.process.node.form.linked.parts</field>
<field name="model">fusion.plating.process.node</field>
<field name="inherit_id"
ref="fusion_plating.view_fp_process_node_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='button_box']" position="inside">
<button name="action_open_cloned_recipes" type="object"
class="oe_stat_button" icon="fa-link"
invisible="node_type != 'recipe' or part_catalog_id">
<field name="cloned_recipe_count" widget="statinfo"
string="Linked Parts"/>
</button>
</xpath>
</field>
</record>
<!-- ========== Extend list view: surface part column ========== -->
<record id="view_fp_process_node_tree_part_scoped"
model="ir.ui.view">