fusion_plating_bridge_mrp: per-job recipe overrides with config wizard (v19.0.2.0.0)
Links recipes to manufacturing orders via x_fc_recipe_id on mrp.production. New model fusion.plating.job.node.override stores per-job opt-in/out decisions for optional recipe steps. Config wizard (fp.recipe.config.wizard) shows all optional nodes as a checklist — opt-in steps default unchecked, opt-out steps default checked. Planner toggles and confirms. "Overrides" stat button on MO form opens wizard. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -11,4 +11,5 @@ from . import fp_portal_job
|
||||
from . import fp_quality_hold
|
||||
from . import fp_delivery
|
||||
from . import fp_batch
|
||||
from . import fp_job_node_override
|
||||
from . import account_move
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2026 Nexa Systems Inc.
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
# Part of the Fusion Plating product family.
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class FpJobNodeOverride(models.Model):
|
||||
"""Per-job override for optional recipe steps.
|
||||
|
||||
When a recipe is assigned to a manufacturing order, nodes with
|
||||
opt_in_out != 'disabled' can be toggled on or off for that specific
|
||||
job. Opt-in nodes default to excluded; opt-out nodes default to
|
||||
included. The planner changes these via the configuration wizard.
|
||||
"""
|
||||
_name = 'fusion.plating.job.node.override'
|
||||
_description = 'Fusion Plating — Job Node Override'
|
||||
_order = 'node_sequence, id'
|
||||
|
||||
production_id = fields.Many2one(
|
||||
'mrp.production',
|
||||
string='Manufacturing Order',
|
||||
required=True,
|
||||
ondelete='cascade',
|
||||
index=True,
|
||||
)
|
||||
node_id = fields.Many2one(
|
||||
'fusion.plating.process.node',
|
||||
string='Recipe Step',
|
||||
required=True,
|
||||
ondelete='cascade',
|
||||
)
|
||||
node_name = fields.Char(
|
||||
related='node_id.name',
|
||||
string='Step Name',
|
||||
readonly=True,
|
||||
)
|
||||
node_type = fields.Selection(
|
||||
related='node_id.node_type',
|
||||
string='Type',
|
||||
readonly=True,
|
||||
)
|
||||
node_sequence = fields.Integer(
|
||||
related='node_id.sequence',
|
||||
string='Sequence',
|
||||
readonly=True,
|
||||
store=True,
|
||||
)
|
||||
opt_in_out = fields.Selection(
|
||||
related='node_id.opt_in_out',
|
||||
string='Default',
|
||||
readonly=True,
|
||||
)
|
||||
included = fields.Boolean(
|
||||
string='Included',
|
||||
default=True,
|
||||
help='Whether this optional step is active for this job.',
|
||||
)
|
||||
|
||||
_sql_constraints = [
|
||||
('unique_production_node',
|
||||
'unique(production_id, node_id)',
|
||||
'Each recipe step can only have one override per job.'),
|
||||
]
|
||||
@@ -3,7 +3,8 @@
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
# Part of the Fusion Plating product family.
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class MrpProduction(models.Model):
|
||||
@@ -27,6 +28,44 @@ class MrpProduction(models.Model):
|
||||
string='Portal Job',
|
||||
help='The portal job linked to this manufacturing order.',
|
||||
)
|
||||
x_fc_recipe_id = fields.Many2one(
|
||||
'fusion.plating.process.node',
|
||||
string='Recipe',
|
||||
domain=[('node_type', '=', 'recipe')],
|
||||
help='Process recipe template for this manufacturing order.',
|
||||
tracking=True,
|
||||
)
|
||||
x_fc_override_ids = fields.One2many(
|
||||
'fusion.plating.job.node.override',
|
||||
'production_id',
|
||||
string='Recipe Overrides',
|
||||
)
|
||||
x_fc_override_count = fields.Integer(
|
||||
string='Overrides',
|
||||
compute='_compute_override_count',
|
||||
)
|
||||
|
||||
@api.depends('x_fc_override_ids')
|
||||
def _compute_override_count(self):
|
||||
for rec in self:
|
||||
rec.x_fc_override_count = len(rec.x_fc_override_ids)
|
||||
|
||||
def action_configure_recipe_steps(self):
|
||||
"""Open the wizard to configure opt-in/out steps for this job."""
|
||||
self.ensure_one()
|
||||
if not self.x_fc_recipe_id:
|
||||
raise UserError(_('Please select a recipe first.'))
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': f'Configure Steps — {self.x_fc_recipe_id.name}',
|
||||
'res_model': 'fp.recipe.config.wizard',
|
||||
'view_mode': 'form',
|
||||
'target': 'new',
|
||||
'context': {
|
||||
'default_production_id': self.id,
|
||||
'default_recipe_id': self.x_fc_recipe_id.id,
|
||||
},
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# GAP 2: SO confirm → MO confirm → auto-create Portal Job
|
||||
|
||||
Reference in New Issue
Block a user