Files
Odoo-Modules/fusion_plating/fusion_plating/tests/test_role_groups.py
gsinghpal bdf676e05a test(plating-sec): verify 8-role hierarchy + implied_ids chains
Group-structure tests for Phase 1 permissions overhaul. Covers:
- All 7 new res.groups records present (8th role "No" is implicit)
- Owner transitively implies base.group_system + every old group
- Manager forms the diamond (implies both Shop Manager and Sales Manager)
- Sales and Shop branches remain orthogonal at the leaf (Tech != Sales Rep)
- uid 1/2 auto-assigned to Owner
- Sequence numbers unique (renders dropdown predictably)
- New groups imply old for backward-compat (30-day rollback safety)
- Cross-module backward-compat chain works (e.g., Owner -> CGP DO)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 01:03:48 -04:00

105 lines
5.2 KiB
Python

from odoo.tests.common import TransactionCase, tagged
@tagged('-at_install', 'post_install', 'fp_perms')
class TestRoleGroupsStructure(TransactionCase):
"""Verify the 8 new roles exist with correct implied_ids chains.
Part of Phase 1 permissions overhaul. See:
docs/superpowers/specs/2026-05-23-permissions-overhaul-design.md
"""
def test_all_seven_groups_exist(self):
"""The 7 new res.groups records must all be defined. (The 8th role 'No'
is implicit — absence of any plating group.)"""
xmlids = {
'group_fp_technician', 'group_fp_sales_rep',
'group_fp_shop_manager_v2', 'group_fp_sales_manager',
'group_fp_manager', 'group_fp_quality_manager', 'group_fp_owner',
}
for xmlid in xmlids:
grp = self.env.ref(f'fusion_plating.{xmlid}', raise_if_not_found=False)
self.assertTrue(grp, f'Group {xmlid} not found')
def test_owner_implies_quality_manager(self):
owner = self.env.ref('fusion_plating.group_fp_owner')
qm = self.env.ref('fusion_plating.group_fp_quality_manager')
self.assertIn(qm, owner.implied_ids)
def test_owner_implies_system(self):
owner = self.env.ref('fusion_plating.group_fp_owner')
system = self.env.ref('base.group_system')
self.assertIn(system, owner.trans_implied_ids,
'Owner must transitively imply base.group_system')
def test_manager_implies_both_branches(self):
"""Manager is the diamond apex — must imply both Shop Manager and Sales Manager."""
mgr = self.env.ref('fusion_plating.group_fp_manager')
sm = self.env.ref('fusion_plating.group_fp_shop_manager_v2')
sales_mgr = self.env.ref('fusion_plating.group_fp_sales_manager')
self.assertIn(sm, mgr.implied_ids, 'Manager must imply Shop Manager (diamond)')
self.assertIn(sales_mgr, mgr.implied_ids, 'Manager must imply Sales Manager (diamond)')
def test_technician_does_not_imply_sales_rep(self):
"""Sales and Shop branches must remain orthogonal at the leaf."""
tech = self.env.ref('fusion_plating.group_fp_technician')
sales_rep = self.env.ref('fusion_plating.group_fp_sales_rep')
self.assertNotIn(sales_rep, tech.trans_implied_ids,
'Technician must NOT see Sales Rep menus')
def test_sales_rep_does_not_imply_technician(self):
sales_rep = self.env.ref('fusion_plating.group_fp_sales_rep')
tech = self.env.ref('fusion_plating.group_fp_technician')
self.assertNotIn(tech, sales_rep.trans_implied_ids,
'Sales Rep must NOT see Workstation')
def test_owner_auto_assigned_to_uid_1_and_2(self):
owner = self.env.ref('fusion_plating.group_fp_owner')
user_ids = owner.user_ids.ids
self.assertIn(1, user_ids, 'Owner must include uid 1 (__system__)')
self.assertIn(2, user_ids, 'Owner must include uid 2 (admin)')
def test_sequence_numbers_are_unique(self):
seqs = [
self.env.ref(f'fusion_plating.{x}').sequence
for x in ('group_fp_technician', 'group_fp_sales_rep',
'group_fp_shop_manager_v2', 'group_fp_sales_manager',
'group_fp_manager', 'group_fp_quality_manager', 'group_fp_owner')
]
self.assertEqual(len(seqs), len(set(seqs)),
f'All sequence numbers must be unique, got {seqs}')
def test_new_groups_imply_old_for_backward_compat(self):
"""During the 30-day rollback window, new groups must trigger old ACLs."""
tech = self.env.ref('fusion_plating.group_fp_technician')
old_op = self.env.ref('fusion_plating.group_fusion_plating_operator')
self.assertIn(old_op, tech.trans_implied_ids)
mgr = self.env.ref('fusion_plating.group_fp_manager')
old_mgr = self.env.ref('fusion_plating.group_fusion_plating_manager')
self.assertIn(old_mgr, mgr.trans_implied_ids)
def test_owner_implies_all_old_groups_via_cross_module_chain(self):
"""Owner must transitively reach every old group (admin, manager, supervisor,
operator, estimator, receiving, accounting, cgp_officer, cgp_designated_official)
via the implication chain spread across fusion_plating + 4 downstream module
security files."""
owner = self.env.ref('fusion_plating.group_fp_owner')
expected_old = [
'fusion_plating.group_fusion_plating_admin',
'fusion_plating.group_fusion_plating_manager',
'fusion_plating.group_fusion_plating_supervisor',
'fusion_plating.group_fusion_plating_operator',
'fusion_plating_configurator.group_fp_estimator',
'fusion_plating_receiving.group_fp_receiving',
'fusion_plating_invoicing.group_fp_accounting',
'fusion_plating_cgp.group_fusion_plating_cgp_officer',
'fusion_plating_cgp.group_fusion_plating_cgp_designated_official',
]
for xmlid in expected_old:
old_grp = self.env.ref(xmlid, raise_if_not_found=False)
if not old_grp:
continue # Module not installed
self.assertIn(old_grp, owner.trans_implied_ids,
f'Owner must transitively imply {xmlid} for backward-compat')