feat(fusion_accounting_core): add computed coexistence group + recompute hooks
group_fusion_show_when_enterprise_absent has membership = all internal users iff no Enterprise accounting module is installed. Membership is recomputed on module install/uninstall via overrides on ir.module.module. Used by Phase 1 fusion_bank_rec menus to auto-hide when Enterprise is active and auto-appear after Enterprise uninstall. Made-with: Cursor
This commit is contained in:
@@ -1 +1,6 @@
|
|||||||
from . import models
|
from . import models
|
||||||
|
|
||||||
|
|
||||||
|
def post_init_hook(env):
|
||||||
|
"""Initialize coexistence group membership based on current Enterprise install state."""
|
||||||
|
env['res.users']._fusion_recompute_coexistence_group()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
'name': 'Fusion Accounting Core',
|
'name': 'Fusion Accounting Core',
|
||||||
'version': '19.0.1.0.1',
|
'version': '19.0.1.0.2',
|
||||||
'category': 'Accounting/Accounting',
|
'category': 'Accounting/Accounting',
|
||||||
'sequence': 24,
|
'sequence': 24,
|
||||||
'summary': 'Shared base for the Fusion Accounting sub-module suite (security, shared schema, runtime helpers).',
|
'summary': 'Shared base for the Fusion Accounting sub-module suite (security, shared schema, runtime helpers).',
|
||||||
@@ -30,4 +30,5 @@ Built by Nexa Systems Inc.
|
|||||||
'installable': True,
|
'installable': True,
|
||||||
'application': False,
|
'application': False,
|
||||||
'license': 'OPL-1',
|
'license': 'OPL-1',
|
||||||
|
'post_init_hook': 'post_init_hook',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from . import ir_module_module
|
from . import ir_module_module
|
||||||
|
from . import res_users
|
||||||
from . import account_move
|
from . import account_move
|
||||||
from . import account_reconcile_model
|
from . import account_reconcile_model
|
||||||
from . import account_bank_statement_line
|
from . import account_bank_statement_line
|
||||||
|
|||||||
@@ -30,3 +30,26 @@ class IrModuleModule(models.Model):
|
|||||||
('name', '=', module_name),
|
('name', '=', module_name),
|
||||||
('state', '=', 'installed'),
|
('state', '=', 'installed'),
|
||||||
]))
|
]))
|
||||||
|
|
||||||
|
def button_immediate_install(self):
|
||||||
|
"""Recompute the coexistence group after install state changes."""
|
||||||
|
result = super().button_immediate_install()
|
||||||
|
self.env['res.users']._fusion_recompute_coexistence_group()
|
||||||
|
return result
|
||||||
|
|
||||||
|
def button_immediate_uninstall(self):
|
||||||
|
"""Recompute the coexistence group after uninstall state changes.
|
||||||
|
|
||||||
|
The MRO chains into fusion_accounting_migration's override (which runs
|
||||||
|
the safety guard before calling super); we recompute only after the
|
||||||
|
whole chain completes.
|
||||||
|
"""
|
||||||
|
result = super().button_immediate_uninstall()
|
||||||
|
self.env['res.users']._fusion_recompute_coexistence_group()
|
||||||
|
return result
|
||||||
|
|
||||||
|
def module_uninstall(self):
|
||||||
|
"""Recompute the coexistence group after the lower-level uninstall."""
|
||||||
|
result = super().module_uninstall()
|
||||||
|
self.env['res.users']._fusion_recompute_coexistence_group()
|
||||||
|
return result
|
||||||
|
|||||||
27
fusion_accounting_core/models/res_users.py
Normal file
27
fusion_accounting_core/models/res_users.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
"""Coexistence group membership recomputation."""
|
||||||
|
|
||||||
|
from odoo import api, models
|
||||||
|
|
||||||
|
|
||||||
|
class ResUsers(models.Model):
|
||||||
|
_inherit = "res.users"
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def _fusion_recompute_coexistence_group(self):
|
||||||
|
"""Set group membership = all internal users iff Enterprise absent.
|
||||||
|
|
||||||
|
Called from ir.module.module.button_immediate_install / uninstall
|
||||||
|
overrides. Idempotent; safe to call multiple times.
|
||||||
|
"""
|
||||||
|
group = self.env.ref(
|
||||||
|
'fusion_accounting_core.group_fusion_show_when_enterprise_absent',
|
||||||
|
raise_if_not_found=False,
|
||||||
|
)
|
||||||
|
if not group:
|
||||||
|
return
|
||||||
|
enterprise_installed = self.env['ir.module.module']._fusion_is_enterprise_accounting_installed()
|
||||||
|
if enterprise_installed:
|
||||||
|
group.sudo().write({'user_ids': [(5, 0, 0)]})
|
||||||
|
else:
|
||||||
|
all_internal = self.sudo().search([('share', '=', False)])
|
||||||
|
group.sudo().write({'user_ids': [(6, 0, all_internal.ids)]})
|
||||||
@@ -43,4 +43,10 @@
|
|||||||
<record id="account.group_account_manager" model="res.groups">
|
<record id="account.group_account_manager" model="res.groups">
|
||||||
<field name="implied_ids" eval="[(4, ref('group_fusion_accounting_admin'))]"/>
|
<field name="implied_ids" eval="[(4, ref('group_fusion_accounting_admin'))]"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<!-- Phase 1: dynamic coexistence group -->
|
||||||
|
<record id="group_fusion_show_when_enterprise_absent" model="res.groups">
|
||||||
|
<field name="name">Fusion: Show menus when Enterprise absent</field>
|
||||||
|
<field name="comment">Computed group. Membership: all internal users when no Enterprise accounting module is installed. Used to hide fusion sub-module menus that would conflict with Enterprise UIs.</field>
|
||||||
|
</record>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
from . import test_enterprise_detection
|
from . import test_enterprise_detection
|
||||||
from . import test_shared_field_ownership
|
from . import test_shared_field_ownership
|
||||||
from . import test_shared_field_bank_statement
|
from . import test_shared_field_bank_statement
|
||||||
|
from . import test_coexistence_group
|
||||||
|
|||||||
46
fusion_accounting_core/tests/test_coexistence_group.py
Normal file
46
fusion_accounting_core/tests/test_coexistence_group.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
from odoo.tests.common import TransactionCase, tagged
|
||||||
|
|
||||||
|
|
||||||
|
@tagged('post_install', '-at_install')
|
||||||
|
class TestCoexistenceGroup(TransactionCase):
|
||||||
|
"""The 'show when Enterprise absent' group must exist and have computed membership."""
|
||||||
|
|
||||||
|
def test_group_exists(self):
|
||||||
|
group = self.env.ref(
|
||||||
|
'fusion_accounting_core.group_fusion_show_when_enterprise_absent',
|
||||||
|
raise_if_not_found=False,
|
||||||
|
)
|
||||||
|
self.assertTrue(group, "Coexistence group must exist")
|
||||||
|
|
||||||
|
def test_membership_matches_enterprise_state(self):
|
||||||
|
"""A user is in the group iff Enterprise accounting is NOT installed.
|
||||||
|
|
||||||
|
We can't toggle Enterprise mid-test, so just assert the current state
|
||||||
|
matches: if Enterprise is installed, group should have 0 members; if
|
||||||
|
not, the group should include all internal users.
|
||||||
|
"""
|
||||||
|
group = self.env.ref(
|
||||||
|
'fusion_accounting_core.group_fusion_show_when_enterprise_absent'
|
||||||
|
)
|
||||||
|
enterprise_installed = self.env['ir.module.module']._fusion_is_enterprise_accounting_installed()
|
||||||
|
all_internal = self.env['res.users'].sudo().search([('share', '=', False)])
|
||||||
|
if enterprise_installed:
|
||||||
|
self.assertEqual(
|
||||||
|
len(group.user_ids), 0,
|
||||||
|
"Enterprise installed -> coexistence group should be empty",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.assertEqual(
|
||||||
|
set(group.user_ids.ids), set(all_internal.ids),
|
||||||
|
"Enterprise absent -> coexistence group should contain all internal users",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_recompute_method_exists(self):
|
||||||
|
"""The recompute helper must be callable on res.users."""
|
||||||
|
self.assertTrue(
|
||||||
|
callable(getattr(
|
||||||
|
self.env['res.users'],
|
||||||
|
'_fusion_recompute_coexistence_group',
|
||||||
|
None,
|
||||||
|
))
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user