changes
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
|
||||
{
|
||||
'name': 'Fusion Plating',
|
||||
'version': '19.0.18.8.0',
|
||||
'version': '19.0.18.11.0',
|
||||
'category': 'Manufacturing/Plating',
|
||||
'summary': 'Core plating / metal finishing ERP: facilities, processes, tanks, baths, jobs, operators.',
|
||||
'description': """
|
||||
|
||||
@@ -546,15 +546,23 @@ export class RecipeTreeEditor extends Component {
|
||||
// ---- Navigation ---------------------------------------------------------
|
||||
|
||||
onBackToList() {
|
||||
// If the editor was opened from the part-scoped Process Composer
|
||||
// (context carried part_id), return to that part's form instead
|
||||
// of the generic Recipes list.
|
||||
// Pop this editor off the action stack and restore the
|
||||
// previous controller — which is whatever opened the editor:
|
||||
// * Recipes list → recipe form → editor ⇒ back to recipe form
|
||||
// * Part form → composer → editor ⇒ back to composer
|
||||
// * Part form → editor (direct link) ⇒ back to part form
|
||||
//
|
||||
// clearBreadcrumbs: this is a semantic RETURN, not a forward
|
||||
// navigation. Without it, every round-trip (part → composer →
|
||||
// editor → back) leaves its intermediate pages on the breadcrumb
|
||||
// stack, so a second visit shows "…/Process Composer/Process
|
||||
// Editor/Process Composer/Process Editor/Part" nonsense.
|
||||
// restore() preserves the full breadcrumb trail.
|
||||
// clearBreadcrumbs: true (the old behaviour) would wipe parent
|
||||
// crumbs and isolate the user on a single-crumb page.
|
||||
try {
|
||||
this.action.restore();
|
||||
return;
|
||||
} catch (e) {
|
||||
// No prior controller — fall through to a sensible default.
|
||||
}
|
||||
// Fallback: when opened directly via URL with no prior crumb,
|
||||
// pick the most contextual landing page we have.
|
||||
if (this._partId) {
|
||||
this.action.doAction({
|
||||
type: "ir.actions.act_window",
|
||||
|
||||
@@ -196,6 +196,17 @@ export class FpSimpleRecipeEditor extends Component {
|
||||
* breadcrumb stack so a second visit shows nonsense.
|
||||
*/
|
||||
onBackToList() {
|
||||
// Pop this editor off the action stack and restore the
|
||||
// previous controller — preserves the full breadcrumb trail
|
||||
// (Recipes > LGPS1104 > Editor → back keeps "Recipes"
|
||||
// visible; Part > Composer > Editor → back returns to the
|
||||
// Composer with crumbs intact).
|
||||
try {
|
||||
this.action.restore();
|
||||
return;
|
||||
} catch (e) {
|
||||
// No prior controller — fall through to a sensible default.
|
||||
}
|
||||
if (this._partId) {
|
||||
this.action.doAction(
|
||||
{
|
||||
|
||||
@@ -51,7 +51,15 @@
|
||||
class="oe_stat_button" icon="fa-sitemap"
|
||||
invisible="node_type != 'recipe'">
|
||||
<field name="child_count" widget="statinfo"
|
||||
string="Steps"/>
|
||||
string="Tree Editor"/>
|
||||
</button>
|
||||
<button name="action_open_simple_editor" type="object"
|
||||
class="oe_stat_button" icon="fa-list-ol"
|
||||
invisible="node_type != 'recipe'">
|
||||
<div class="o_stat_info">
|
||||
<span class="o_stat_text">Simple</span>
|
||||
<span class="o_stat_text">Editor</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<widget name="web_ribbon" title="Archived"
|
||||
|
||||
@@ -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': """
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user