From 37f917824abe72d4a44618751440b600aa617a0a Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Fri, 24 Apr 2026 21:12:32 -0400 Subject: [PATCH] feat(jobs): add fp.work.centre native model Replaces mrp.workcenter for plating. Domain-specific kinds (wet_line/bake/mask/rack/inspect/other) drive release-ready validation on steps. ACLs follow existing supervisor/manager hierarchy. Note: spec listed default_oven_id Many2one to fusion.plating.oven but that model does not exist in core (the bake-oven model fusion.plating.bake.oven lives in fusion_plating_shopfloor, which core cannot depend on). Field omitted; the bridge that adds fp.job/fp.job.step can re-introduce it via _inherit later. Part of: native job model migration (spec 2026-04-25) Co-Authored-By: Claude Opus 4.7 (1M context) --- fusion_plating/fusion_plating/__manifest__.py | 2 +- .../fusion_plating/models/__init__.py | 1 + .../fusion_plating/models/fp_work_centre.py | 58 +++++++++++++++++++ .../security/ir.model.access.csv | 3 + .../fusion_plating/tests/__init__.py | 2 + .../tests/test_fp_work_centre.py | 29 ++++++++++ 6 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 fusion_plating/fusion_plating/models/fp_work_centre.py create mode 100644 fusion_plating/fusion_plating/tests/__init__.py create mode 100644 fusion_plating/fusion_plating/tests/test_fp_work_centre.py diff --git a/fusion_plating/fusion_plating/__manifest__.py b/fusion_plating/fusion_plating/__manifest__.py index f1b5344f..485ddd3e 100644 --- a/fusion_plating/fusion_plating/__manifest__.py +++ b/fusion_plating/fusion_plating/__manifest__.py @@ -5,7 +5,7 @@ { 'name': 'Fusion Plating', - 'version': '19.0.8.0.0', + 'version': '19.0.8.1.0', 'category': 'Manufacturing/Plating', 'summary': 'Core plating / metal finishing ERP: facilities, processes, tanks, baths, jobs, operators.', 'description': """ diff --git a/fusion_plating/fusion_plating/models/__init__.py b/fusion_plating/fusion_plating/models/__init__.py index a8df88f7..6c4a2388 100644 --- a/fusion_plating/fusion_plating/models/__init__.py +++ b/fusion_plating/fusion_plating/models/__init__.py @@ -7,6 +7,7 @@ from . import fp_process_category from . import fp_process_type from . import fp_facility from . import fp_work_center +from . import fp_work_centre from . import fp_tank from . import fp_bath from . import fp_bath_log diff --git a/fusion_plating/fusion_plating/models/fp_work_centre.py b/fusion_plating/fusion_plating/models/fp_work_centre.py new file mode 100644 index 00000000..8f61270c --- /dev/null +++ b/fusion_plating/fusion_plating/models/fp_work_centre.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- +# Copyright 2026 Nexa Systems Inc. +# License OPL-1 (Odoo Proprietary License v1.0) +# +# fp.work.centre — native plating work-centre model. +# +# Replaces mrp.workcenter for the plating flow. Plating work centres +# are domain-specific (a tank line, a bake oven, a rack station — not +# assembly cells). Each centre has a 'kind' that drives release-ready +# validation on fp.job.step (e.g. wet_line -> bath+tank required). + +from odoo import fields, models + + +class FpWorkCentre(models.Model): + _name = 'fp.work.centre' + _description = 'Plating Work Centre' + _order = 'sequence, code, name' + + name = fields.Char(required=True) + code = fields.Char(required=True, help='Short code used on stickers and reports.') + sequence = fields.Integer(default=10) + facility_id = fields.Many2one( + 'fusion.plating.facility', + string='Facility', + ) + kind = fields.Selection( + [ + ('wet_line', 'Wet Line'), + ('bake', 'Bake Oven'), + ('mask', 'Masking'), + ('rack', 'Racking'), + ('inspect', 'Inspection'), + ('other', 'Other'), + ], + required=True, + default='other', + ) + cost_per_hour = fields.Monetary( + currency_field='currency_id', + help='Used for fp.job.step cost rollups.', + ) + currency_id = fields.Many2one( + 'res.currency', + default=lambda self: self.env.company.currency_id, + ) + default_bath_id = fields.Many2one('fusion.plating.bath') + default_tank_id = fields.Many2one('fusion.plating.tank') + # NOTE: `default_oven_id` from the spec/plan is omitted here — the + # `fusion.plating.bake.oven` model lives in fusion_plating_shopfloor, + # which the core module cannot depend on. The bridge module that + # introduces fp.job/fp.job.step (Task 1.x) can re-introduce this + # field via _inherit if/when the bake-oven coupling is needed. + active = fields.Boolean(default=True) + + _sql_constraints = [ + ('unique_code', 'UNIQUE(code)', 'Work centre code must be unique.'), + ] diff --git a/fusion_plating/fusion_plating/security/ir.model.access.csv b/fusion_plating/fusion_plating/security/ir.model.access.csv index 715972b2..d98349b1 100644 --- a/fusion_plating/fusion_plating/security/ir.model.access.csv +++ b/fusion_plating/fusion_plating/security/ir.model.access.csv @@ -44,3 +44,6 @@ access_fp_replenishment_suggestion_manager,fp.replenishment.suggestion.manager,m access_fp_operator_cert_operator,fp.operator.cert.operator,model_fp_operator_certification,group_fusion_plating_operator,1,0,0,0 access_fp_operator_cert_supervisor,fp.operator.cert.supervisor,model_fp_operator_certification,group_fusion_plating_supervisor,1,1,1,0 access_fp_operator_cert_manager,fp.operator.cert.manager,model_fp_operator_certification,group_fusion_plating_manager,1,1,1,1 +access_fp_work_centre_user,fp.work.centre.user,model_fp_work_centre,base.group_user,1,0,0,0 +access_fp_work_centre_supervisor,fp.work.centre.supervisor,model_fp_work_centre,fusion_plating.group_fusion_plating_supervisor,1,1,1,0 +access_fp_work_centre_manager,fp.work.centre.manager,model_fp_work_centre,fusion_plating.group_fusion_plating_manager,1,1,1,1 diff --git a/fusion_plating/fusion_plating/tests/__init__.py b/fusion_plating/fusion_plating/tests/__init__.py new file mode 100644 index 00000000..061a2c72 --- /dev/null +++ b/fusion_plating/fusion_plating/tests/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import test_fp_work_centre diff --git a/fusion_plating/fusion_plating/tests/test_fp_work_centre.py b/fusion_plating/fusion_plating/tests/test_fp_work_centre.py new file mode 100644 index 00000000..c13f557c --- /dev/null +++ b/fusion_plating/fusion_plating/tests/test_fp_work_centre.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +from odoo.tests.common import TransactionCase + + +class TestFpWorkCentre(TransactionCase): + def test_create_work_centre_minimal(self): + wc = self.env['fp.work.centre'].create({ + 'name': 'Bath Line 1', + 'code': 'BL1', + 'kind': 'wet_line', + }) + self.assertEqual(wc.name, 'Bath Line 1') + self.assertEqual(wc.kind, 'wet_line') + self.assertTrue(wc.active) + + def test_facility_required_for_active_centre(self): + wc = self.env['fp.work.centre'].create({ + 'name': 'Test', + 'code': 'T', + 'kind': 'other', + }) + self.assertFalse(wc.facility_id) + + def test_kind_selection_values(self): + kinds = dict( + self.env['fp.work.centre']._fields['kind'].selection + ) + for k in ('wet_line', 'bake', 'mask', 'rack', 'inspect', 'other'): + self.assertIn(k, kinds)