feat(plating-quality): split Manager vs Quality Manager permissions
Phase C of permissions overhaul (spec Section 2.C).
Manager keeps reactive Quality (NCR/Hold/Check/Cert/RMA — already gated
via Phase B sweep). QM gains exclusive write/create/unlink on strategic
Quality records:
- fusion.plating.capa: Manager → read-only (1,0,0,0); QM → full
- fusion.plating.audit: same split (if model present)
- fp.approved.vendor.list: same split (if model present)
- fusion.plating.customer.spec: same split
- Doc Control models: same split
Plus FAIR/Nadcap cert restriction via two new ir.rule records on
fp.certificate:
- Manager: write/create/unlink on certs where cert_type NOT in
('fair', 'nadcap')
- QM: write/create/unlink on all certs (overrides via OR within group)
- Read access unchanged for both (perm_read=False on the rules)
Tests in fusion_plating/tests/test_quality_split.py verify each side
of the split. Models that may not exist on all DBs (audit, AVL) use
skipTest gracefully.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
|
||||
{
|
||||
'name': 'Fusion Plating',
|
||||
'version': '19.0.21.0.1',
|
||||
'version': '19.0.21.0.2',
|
||||
'category': 'Manufacturing/Plating',
|
||||
'summary': 'Core plating / metal finishing ERP: facilities, processes, tanks, baths, jobs, operators.',
|
||||
'description': """
|
||||
|
||||
@@ -5,3 +5,4 @@ from . import test_fp_job_step_state_machine
|
||||
from . import test_simple_recipe_flatten
|
||||
from . import test_role_groups
|
||||
from . import test_acl_migration
|
||||
from . import test_quality_split
|
||||
|
||||
90
fusion_plating/fusion_plating/tests/test_quality_split.py
Normal file
90
fusion_plating/fusion_plating/tests/test_quality_split.py
Normal file
@@ -0,0 +1,90 @@
|
||||
from odoo.tests.common import TransactionCase, tagged
|
||||
from odoo.exceptions import AccessError
|
||||
|
||||
|
||||
@tagged('-at_install', 'post_install', 'fp_perms')
|
||||
class TestQualitySplit(TransactionCase):
|
||||
"""Section 2.C of spec: Manager handles reactive Quality;
|
||||
QM exclusively owns CAPA close, Audit, AVL, Customer Spec, FAIR/Nadcap signing."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
Users = self.env['res.users'].with_context(no_reset_password=True)
|
||||
self.u_mgr = Users.create({
|
||||
'login': 'qsplit_mgr', 'name': 'QSplit Mgr',
|
||||
'email': 'qsplit_mgr@example.com',
|
||||
'groups_id': [(6, 0, [self.env.ref('fusion_plating.group_fp_manager').id])],
|
||||
})
|
||||
self.u_qm = Users.create({
|
||||
'login': 'qsplit_qm', 'name': 'QSplit QM',
|
||||
'email': 'qsplit_qm@example.com',
|
||||
'groups_id': [(6, 0, [self.env.ref('fusion_plating.group_fp_quality_manager').id])],
|
||||
})
|
||||
|
||||
# CAPA: Manager read-only, QM full
|
||||
def test_manager_can_read_capa(self):
|
||||
self.env['fusion.plating.capa'].with_user(self.u_mgr).check_access_rights('read')
|
||||
|
||||
def test_manager_cannot_write_capa(self):
|
||||
with self.assertRaises(AccessError):
|
||||
self.env['fusion.plating.capa'].with_user(self.u_mgr).check_access_rights('write')
|
||||
|
||||
def test_manager_cannot_create_capa(self):
|
||||
with self.assertRaises(AccessError):
|
||||
self.env['fusion.plating.capa'].with_user(self.u_mgr).check_access_rights('create')
|
||||
|
||||
def test_qm_can_write_capa(self):
|
||||
self.env['fusion.plating.capa'].with_user(self.u_qm).check_access_rights('write')
|
||||
|
||||
# Audit: Manager read-only, QM full
|
||||
def test_manager_can_read_audit(self):
|
||||
Audit = self.env.get('fusion.plating.audit')
|
||||
if not Audit:
|
||||
self.skipTest('fusion.plating.audit model not available')
|
||||
Audit.with_user(self.u_mgr).check_access_rights('read')
|
||||
|
||||
def test_manager_cannot_write_audit(self):
|
||||
Audit = self.env.get('fusion.plating.audit')
|
||||
if not Audit:
|
||||
self.skipTest('fusion.plating.audit model not available')
|
||||
with self.assertRaises(AccessError):
|
||||
Audit.with_user(self.u_mgr).check_access_rights('write')
|
||||
|
||||
def test_qm_can_write_audit(self):
|
||||
Audit = self.env.get('fusion.plating.audit')
|
||||
if not Audit:
|
||||
self.skipTest('fusion.plating.audit model not available')
|
||||
Audit.with_user(self.u_qm).check_access_rights('write')
|
||||
|
||||
# NCR: Manager full
|
||||
def test_manager_can_create_ncr(self):
|
||||
self.env['fusion.plating.ncr'].with_user(self.u_mgr).check_access_rights('create')
|
||||
|
||||
def test_manager_can_write_ncr(self):
|
||||
self.env['fusion.plating.ncr'].with_user(self.u_mgr).check_access_rights('write')
|
||||
|
||||
# Hold: Manager full
|
||||
def test_manager_can_create_hold(self):
|
||||
self.env['fusion.plating.quality.hold'].with_user(self.u_mgr).check_access_rights('create')
|
||||
|
||||
# AVL: Manager read-only, QM full
|
||||
def test_manager_can_read_avl(self):
|
||||
Avl = self.env.get('fp.approved.vendor.list')
|
||||
if not Avl:
|
||||
self.skipTest('fp.approved.vendor.list model not available')
|
||||
Avl.with_user(self.u_mgr).check_access_rights('read')
|
||||
|
||||
def test_manager_cannot_write_avl(self):
|
||||
Avl = self.env.get('fp.approved.vendor.list')
|
||||
if not Avl:
|
||||
self.skipTest('fp.approved.vendor.list model not available')
|
||||
with self.assertRaises(AccessError):
|
||||
Avl.with_user(self.u_mgr).check_access_rights('write')
|
||||
|
||||
# Customer Spec: Manager read-only, QM full
|
||||
def test_manager_can_read_customer_spec(self):
|
||||
self.env['fusion.plating.customer.spec'].with_user(self.u_mgr).check_access_rights('read')
|
||||
|
||||
def test_manager_cannot_write_customer_spec(self):
|
||||
with self.assertRaises(AccessError):
|
||||
self.env['fusion.plating.customer.spec'].with_user(self.u_mgr).check_access_rights('write')
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
{
|
||||
'name': 'Fusion Plating — Certificates',
|
||||
'version': '19.0.7.9.1',
|
||||
'version': '19.0.7.9.2',
|
||||
'category': 'Manufacturing/Plating',
|
||||
'summary': 'Certificate registry for CoC, thickness reports, and quality documents.',
|
||||
'description': """
|
||||
@@ -32,6 +32,7 @@ Includes Fischerscope thickness measurement data capture.
|
||||
],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'security/fp_cert_security.xml',
|
||||
'data/fp_certificate_sequence_data.xml',
|
||||
'views/res_config_settings_views.xml',
|
||||
'views/fp_certificate_views.xml',
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="0">
|
||||
<record id="rule_fp_certificate_fair_nadcap_qm_only" model="ir.rule">
|
||||
<field name="name">FP Certificate: FAIR/Nadcap edit restricted to Quality Manager</field>
|
||||
<field name="model_id" ref="model_fp_certificate"/>
|
||||
<field name="domain_force">[('cert_type', 'not in', ('fair', 'nadcap'))]</field>
|
||||
<field name="groups" eval="[(4, ref('fusion_plating.group_fp_manager'))]"/>
|
||||
<field name="perm_read" eval="False"/>
|
||||
<field name="perm_write" eval="True"/>
|
||||
<field name="perm_create" eval="True"/>
|
||||
<field name="perm_unlink" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record id="rule_fp_certificate_all_qm" model="ir.rule">
|
||||
<field name="name">FP Certificate: QM has full access to all certs</field>
|
||||
<field name="model_id" ref="model_fp_certificate"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
<field name="groups" eval="[(4, ref('fusion_plating.group_fp_quality_manager'))]"/>
|
||||
<field name="perm_read" eval="False"/>
|
||||
<field name="perm_write" eval="True"/>
|
||||
<field name="perm_create" eval="True"/>
|
||||
<field name="perm_unlink" eval="True"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
{
|
||||
'name': 'Fusion Plating — Quality (QMS)',
|
||||
'version': '19.0.6.6.1',
|
||||
'version': '19.0.6.6.2',
|
||||
'category': 'Manufacturing/Plating',
|
||||
'summary': 'Native QMS for plating shops: NCR, CAPA, calibration, AVL, FAIR, '
|
||||
'internal audits, customer specs, document control. CE + EE compatible.',
|
||||
|
||||
@@ -4,7 +4,8 @@ access_fp_ncr_supervisor,fp.ncr.supervisor,model_fusion_plating_ncr,fusion_plati
|
||||
access_fp_ncr_manager,fp.ncr.manager,model_fusion_plating_ncr,fusion_plating.group_fp_manager,1,1,1,1
|
||||
access_fp_capa_operator,fp.capa.operator,model_fusion_plating_capa,fusion_plating.group_fp_technician,1,0,0,0
|
||||
access_fp_capa_supervisor,fp.capa.supervisor,model_fusion_plating_capa,fusion_plating.group_fp_shop_manager_v2,1,1,1,0
|
||||
access_fp_capa_manager,fp.capa.manager,model_fusion_plating_capa,fusion_plating.group_fp_manager,1,1,1,1
|
||||
access_fp_capa_manager,fp.capa.manager,model_fusion_plating_capa,fusion_plating.group_fp_manager,1,0,0,0
|
||||
access_fp_capa_qm,fp.capa.qm,model_fusion_plating_capa,fusion_plating.group_fp_quality_manager,1,1,1,1
|
||||
access_fp_cal_equipment_operator,fp.cal.equipment.operator,model_fusion_plating_calibration_equipment,fusion_plating.group_fp_technician,1,0,0,0
|
||||
access_fp_cal_equipment_supervisor,fp.cal.equipment.supervisor,model_fusion_plating_calibration_equipment,fusion_plating.group_fp_shop_manager_v2,1,1,1,0
|
||||
access_fp_cal_equipment_manager,fp.cal.equipment.manager,model_fusion_plating_calibration_equipment,fusion_plating.group_fp_manager,1,1,1,1
|
||||
@@ -13,19 +14,23 @@ access_fp_cal_event_supervisor,fp.cal.event.supervisor,model_fusion_plating_cali
|
||||
access_fp_cal_event_manager,fp.cal.event.manager,model_fusion_plating_calibration_event,fusion_plating.group_fp_manager,1,1,1,1
|
||||
access_fp_avl_operator,fp.avl.operator,model_fusion_plating_avl,fusion_plating.group_fp_technician,1,0,0,0
|
||||
access_fp_avl_supervisor,fp.avl.supervisor,model_fusion_plating_avl,fusion_plating.group_fp_shop_manager_v2,1,1,1,0
|
||||
access_fp_avl_manager,fp.avl.manager,model_fusion_plating_avl,fusion_plating.group_fp_manager,1,1,1,1
|
||||
access_fp_avl_manager,fp.avl.manager,model_fusion_plating_avl,fusion_plating.group_fp_manager,1,0,0,0
|
||||
access_fp_avl_qm,fp.avl.qm,model_fusion_plating_avl,fusion_plating.group_fp_quality_manager,1,1,1,1
|
||||
access_fp_customer_spec_operator,fp.customer.spec.operator,model_fusion_plating_customer_spec,fusion_plating.group_fp_technician,1,0,0,0
|
||||
access_fp_customer_spec_supervisor,fp.customer.spec.supervisor,model_fusion_plating_customer_spec,fusion_plating.group_fp_shop_manager_v2,1,1,1,0
|
||||
access_fp_customer_spec_manager,fp.customer.spec.manager,model_fusion_plating_customer_spec,fusion_plating.group_fp_manager,1,1,1,1
|
||||
access_fp_customer_spec_manager,fp.customer.spec.manager,model_fusion_plating_customer_spec,fusion_plating.group_fp_manager,1,0,0,0
|
||||
access_fp_customer_spec_qm,fp.customer.spec.qm,model_fusion_plating_customer_spec,fusion_plating.group_fp_quality_manager,1,1,1,1
|
||||
access_fp_audit_operator,fp.audit.operator,model_fusion_plating_audit,fusion_plating.group_fp_technician,1,0,0,0
|
||||
access_fp_audit_supervisor,fp.audit.supervisor,model_fusion_plating_audit,fusion_plating.group_fp_shop_manager_v2,1,1,1,0
|
||||
access_fp_audit_manager,fp.audit.manager,model_fusion_plating_audit,fusion_plating.group_fp_manager,1,1,1,1
|
||||
access_fp_audit_manager,fp.audit.manager,model_fusion_plating_audit,fusion_plating.group_fp_manager,1,0,0,0
|
||||
access_fp_audit_qm,fp.audit.qm,model_fusion_plating_audit,fusion_plating.group_fp_quality_manager,1,1,1,1
|
||||
access_fp_fair_operator,fp.fair.operator,model_fusion_plating_fair,fusion_plating.group_fp_technician,1,0,0,0
|
||||
access_fp_fair_supervisor,fp.fair.supervisor,model_fusion_plating_fair,fusion_plating.group_fp_shop_manager_v2,1,1,1,0
|
||||
access_fp_fair_manager,fp.fair.manager,model_fusion_plating_fair,fusion_plating.group_fp_manager,1,1,1,1
|
||||
access_fp_doc_control_operator,fp.doc.control.operator,model_fusion_plating_doc_control,fusion_plating.group_fp_technician,1,0,0,0
|
||||
access_fp_doc_control_supervisor,fp.doc.control.supervisor,model_fusion_plating_doc_control,fusion_plating.group_fp_shop_manager_v2,1,1,1,0
|
||||
access_fp_doc_control_manager,fp.doc.control.manager,model_fusion_plating_doc_control,fusion_plating.group_fp_manager,1,1,1,1
|
||||
access_fp_doc_control_manager,fp.doc.control.manager,model_fusion_plating_doc_control,fusion_plating.group_fp_manager,1,0,0,0
|
||||
access_fp_doc_control_qm,fp.doc.control.qm,model_fusion_plating_doc_control,fusion_plating.group_fp_quality_manager,1,1,1,1
|
||||
access_fp_quality_hold_operator,fp.quality.hold.operator,model_fusion_plating_quality_hold,fusion_plating.group_fp_technician,1,0,1,0
|
||||
access_fp_quality_hold_supervisor,fp.quality.hold.supervisor,model_fusion_plating_quality_hold,fusion_plating.group_fp_shop_manager_v2,1,1,1,0
|
||||
access_fp_quality_hold_manager,fp.quality.hold.manager,model_fusion_plating_quality_hold,fusion_plating.group_fp_manager,1,1,1,1
|
||||
|
||||
|
Reference in New Issue
Block a user