diff --git a/operating_unit/__manifest__.py b/operating_unit/__manifest__.py index 6de0b0eace..b92aab9da6 100644 --- a/operating_unit/__manifest__.py +++ b/operating_unit/__manifest__.py @@ -6,7 +6,7 @@ "name": "Operating Unit", "summary": "An operating unit (OU) is an organizational entity part of a " "company", - "version": "16.0.1.0.2", + "version": "17.0.1.0.0", "author": "ForgeFlow, " "Serpent Consulting Services Pvt. Ltd., " "Odoo Community Association (OCA)", diff --git a/operating_unit/data/operating_unit_data.xml b/operating_unit/data/operating_unit_data.xml index 27b9bb0d9b..e101b6b9d9 100644 --- a/operating_unit/data/operating_unit_data.xml +++ b/operating_unit/data/operating_unit_data.xml @@ -8,10 +8,16 @@ - + - + diff --git a/operating_unit/models/__init__.py b/operating_unit/models/__init__.py index b2dcf9371c..191c9807f0 100644 --- a/operating_unit/models/__init__.py +++ b/operating_unit/models/__init__.py @@ -1,2 +1,3 @@ +from . import ir_rule from . import operating_unit from . import res_users diff --git a/operating_unit/models/ir_rule.py b/operating_unit/models/ir_rule.py new file mode 100644 index 0000000000..d68da2d643 --- /dev/null +++ b/operating_unit/models/ir_rule.py @@ -0,0 +1,20 @@ +# Copyright 2024 NSI-SA +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + + +from odoo import api, models + + +class IrRule(models.Model): + _inherit = "ir.rule" + + @api.model + def _eval_context(self): + res = super()._eval_context() + res.update( + { + "operating_unit_ids": self.env.user.operating_units().ids, + "operating_unit_id": self.env.user.default_operating_unit_id.id, + } + ) + return res diff --git a/operating_unit/models/operating_unit.py b/operating_unit/models/operating_unit.py index 098a4a39c9..ca29bd7906 100644 --- a/operating_unit/models/operating_unit.py +++ b/operating_unit/models/operating_unit.py @@ -41,22 +41,18 @@ class OperatingUnit(models.Model): ), ] - def name_get(self): - res = [] + @api.depends("name", "code") + def _compute_display_name(self): for ou in self: - name = ou.name - if ou.code: - name = f"[{ou.code}] {name}" - res.append((ou.id, name)) - return res + ou.display_name = f"[{ou.code}] {ou.name}" @api.model_create_multi def create(self, vals_list): res = super().create(vals_list) res.write({"user_ids": [fields.Command.link(self.env.user.id)]}) - self.clear_caches() + self.env.registry.clear_cache() return res def write(self, vals): - self.clear_caches() + self.env.registry.clear_cache() return super().write(vals) diff --git a/operating_unit/models/res_users.py b/operating_unit/models/res_users.py index cf05d19724..66d253d924 100644 --- a/operating_unit/models/res_users.py +++ b/operating_unit/models/res_users.py @@ -8,33 +8,6 @@ class ResUsers(models.Model): _inherit = "res.users" - @api.model - def operating_unit_default_get(self, uid2=False): - if not uid2: - uid2 = self.env.user.id - user = self.env["res.users"].browse(uid2) - # check if the company of the default OU is active - if user.default_operating_unit_id.sudo().company_id in self.env.companies: - return user.default_operating_unit_id - else: - # find an OU of the main active company - for ou in user.assigned_operating_unit_ids: - if ou.sudo().company_id in self.env.company: - return ou - # find an OU of any active company - for ou in user.assigned_operating_unit_ids: - if ou.sudo().company_id in self.env.companies: - return ou - return False - - @api.model - def _default_operating_unit(self): - return self.operating_unit_default_get() - - @api.model - def _default_operating_units(self): - return self._default_operating_unit() - operating_unit_ids = fields.One2many( comodel_name="operating.unit", compute="_compute_operating_unit_ids", @@ -49,7 +22,7 @@ def _default_operating_units(self): column1="user_id", column2="operating_unit_id", string="Operating Units", - default=lambda self: self._default_operating_units(), + default=lambda self: self._default_operating_unit(), ) default_operating_unit_id = fields.Many2one( @@ -59,36 +32,32 @@ def _default_operating_units(self): domain="[('company_id', '=', current_company_id)]", ) - @api.onchange("operating_unit_ids") - def _onchange_operating_unit_ids(self): - for record in self: - if ( - record.default_operating_unit_id - and record.default_operating_unit_id - not in record.operating_unit_ids._origin - ): - record.default_operating_unit_id = False + @api.model + def _get_default_operating_unit(self, uid2=False): + if not uid2: + uid2 = self.env.user.id + user = self.env["res.users"].browse(uid2) + # check if the company of the default OU is active + if user.default_operating_unit_id.sudo().company_id in self.env.companies: + return user.default_operating_unit_id + else: + # find an OU of the main active company + for ou in user.assigned_operating_unit_ids: + if ou.sudo().company_id in self.env.company: + return ou + # find an OU of any active company + for ou in user.assigned_operating_unit_ids: + if ou.sudo().company_id in self.env.companies: + return ou + return False - @api.depends("groups_id", "assigned_operating_unit_ids") - def _compute_operating_unit_ids(self): - for user in self: - if user._origin.has_group("operating_unit.group_manager_operating_unit"): - dom = [] - if self.env.context.get("allowed_company_ids"): - dom = [ - "|", - ("company_id", "=", False), - ("company_id", "in", self.env.context["allowed_company_ids"]), - ] - else: - dom = [] - user.operating_unit_ids = self.env["operating.unit"].sudo().search(dom) - else: - user.operating_unit_ids = user.assigned_operating_unit_ids + @api.model + def _default_operating_unit(self): + return self._get_default_operating_unit() @api.model def default_get(self, fields): - vals = super(ResUsers, self).default_get(fields) + vals = super().default_get(fields) if ( self.env["ir.config_parameter"] .sudo() @@ -102,7 +71,37 @@ def default_get(self, fields): vals["operating_unit_ids"] = [(6, 0, default_user.operating_unit_ids.ids)] return vals + @api.depends("groups_id", "assigned_operating_unit_ids") + def _compute_operating_unit_ids(self): + for user in self: + if user._origin.has_group("operating_unit.group_manager_operating_unit"): + if self.env.context.get("allowed_company_ids"): + dom = [ + "|", + ("company_id", "=", False), + ("company_id", "in", self.env.context["allowed_company_ids"]), + ] + else: + dom = [] + + user.operating_unit_ids = self.env["operating.unit"].sudo().search(dom) + else: + user.operating_unit_ids = user.assigned_operating_unit_ids + def _inverse_operating_unit_ids(self): for user in self: user.assigned_operating_unit_ids = user.operating_unit_ids - self.clear_caches() + self.env.registry.clear_cache() + + @api.onchange("operating_unit_ids") + def _onchange_operating_unit_ids(self): + for record in self: + if ( + record.default_operating_unit_id + and record.default_operating_unit_id + not in record.operating_unit_ids._origin + ): + record.default_operating_unit_id = False + + def operating_units(self): + return self.env.user.operating_unit_ids diff --git a/operating_unit/security/operating_unit_security.xml b/operating_unit/security/operating_unit_security.xml index c7f2572791..4f9dcd9871 100644 --- a/operating_unit/security/operating_unit_security.xml +++ b/operating_unit/security/operating_unit_security.xml @@ -27,7 +27,7 @@ - [('id','in',user.operating_unit_ids.ids)] + [('id','in',operating_unit_ids)] Allowed operating units diff --git a/operating_unit/tests/__init__.py b/operating_unit/tests/__init__.py index 8096d86683..768fdaaba1 100644 --- a/operating_unit/tests/__init__.py +++ b/operating_unit/tests/__init__.py @@ -1 +1,2 @@ +from . import common from . import test_operating_unit diff --git a/operating_unit/tests/common.py b/operating_unit/tests/common.py new file mode 100644 index 0000000000..ed3d6f9fde --- /dev/null +++ b/operating_unit/tests/common.py @@ -0,0 +1,67 @@ +# © 2017-TODAY ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo.models import Command +from odoo.tests import common + + +class OperatingUnitCommon(common.TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.res_users_model = cls.env["res.users"].with_context( + tracking_disable=True, no_reset_password=True + ) + # Groups + cls.grp_ou_mngr = cls.env.ref("operating_unit.group_manager_operating_unit") + cls.grp_ou_multi = cls.env.ref("operating_unit.group_multi_operating_unit") + # Company + cls.company = cls.env.ref("base.main_company") + cls.company_2 = cls.env["res.company"].create({"name": "Second company"}) + # Main Operating Unit + cls.ou1 = cls.env.ref("operating_unit.main_operating_unit") + # B2C Operating Unit + cls.b2c = cls.env.ref("operating_unit.b2c_operating_unit") + # B2B Operating Unit + cls.b2b = cls.env.ref("operating_unit.b2b_operating_unit") + # Create User 1 with Main OU + cls.user1 = cls._create_user("user_1", cls.grp_ou_mngr, cls.company, cls.ou1) + # Create User 2 with B2C OU + cls.user2 = cls._create_user("user_2", cls.grp_ou_multi, cls.company, cls.b2c) + # Partner + cls.partner1 = cls.env.ref("base.res_partner_1") + + @classmethod + def _create_user(cls, login, group, company, operating_units, context=None): + """Create a user.""" + user = cls.res_users_model.create( + { + "name": "Test User", + "login": login, + "password": "demo", + "email": "test@yourcompany.com", + "company_id": company.id, + "company_ids": [(4, company.id)], + "operating_unit_ids": [(4, ou.id) for ou in operating_units], + "groups_id": [Command.link(group.id)], + } + ) + return user + + def _create_operating_unit(self, uid, name, code, company_id=None): + """Create Operating Unit""" + if company_id is None: + company_id = self.company + ou = ( + self.env["operating.unit"] + .with_user(uid) + .create( + { + "name": name, + "code": code, + "partner_id": company_id.partner_id.id, + "company_id": company_id.id, + } + ) + ) + return ou diff --git a/operating_unit/tests/test_operating_unit.py b/operating_unit/tests/test_operating_unit.py index 29dcf8ade1..95d9c12577 100644 --- a/operating_unit/tests/test_operating_unit.py +++ b/operating_unit/tests/test_operating_unit.py @@ -2,71 +2,14 @@ # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) from odoo.exceptions import AccessError -from odoo.tests import common +from odoo.tests import tagged from odoo.tests.common import Form +from .common import OperatingUnitCommon -class TestOperatingUnit(common.TransactionCase): - @classmethod - def setUpClass(cls): - super().setUpClass() - cls.res_users_model = cls.env["res.users"].with_context( - tracking_disable=True, no_reset_password=True - ) - - # Groups - cls.grp_ou_mngr = cls.env.ref("operating_unit.group_manager_operating_unit") - cls.grp_ou_multi = cls.env.ref("operating_unit.group_multi_operating_unit") - # Company - cls.company = cls.env.ref("base.main_company") - cls.company_2 = cls.env["res.company"].create({"name": "Second company"}) - # Main Operating Unit - cls.ou1 = cls.env.ref("operating_unit.main_operating_unit") - # B2C Operating Unit - cls.b2c = cls.env.ref("operating_unit.b2c_operating_unit") - # B2B Operating Unit - cls.b2b = cls.env.ref("operating_unit.b2b_operating_unit") - # Create User 1 with Main OU - cls.user1 = cls._create_user("user_1", cls.grp_ou_mngr, cls.company, cls.ou1) - # Create User 2 with B2C OU - cls.user2 = cls._create_user("user_2", cls.grp_ou_multi, cls.company, cls.b2c) - - @classmethod - def _create_user(cls, login, group, company, operating_units, context=None): - """Create a user.""" - user = cls.res_users_model.create( - { - "name": "Test User", - "login": login, - "password": "demo", - "email": "test@yourcompany.com", - "company_id": company.id, - "company_ids": [(4, company.id)], - "operating_unit_ids": [(4, ou.id) for ou in operating_units], - "default_operating_unit_id": False, - "sel_groups_13_14": group.id, - } - ) - return user - - def _create_operating_unit(self, uid, name, code, company_id=None): - """Create Operating Unit""" - if company_id is None: - company_id = self.company - ou = ( - self.env["operating.unit"] - .with_user(uid) - .create( - { - "name": name, - "code": code, - "partner_id": company_id.partner_id.id, - "company_id": company_id.id, - } - ) - ) - return ou +@tagged("post_install", "-at_install") +class TestOperatingUnit(OperatingUnitCommon): def test_01_operating_unit(self): # User 1 tries to create and modify an OU # Create @@ -156,17 +99,17 @@ def test_find_operating_unit_by_name_or_code(self): def test_03_operating_unit(self): """ - The method operating_unit_default_get should not return + The method _get_default_operating_unit should not return operating units belonging to a company that is not active """ self.assertEqual( - self.res_users_model.operating_unit_default_get(uid2=self.user1.id), + self.res_users_model._get_default_operating_unit(uid2=self.user1.id), self.ou1, ) self.assertEqual( self.res_users_model.with_company( self.company_2 - ).operating_unit_default_get(uid2=self.user1.id), + )._get_default_operating_unit(uid2=self.user1.id), False, ) @@ -178,7 +121,7 @@ def test_03_operating_unit(self): self.assertEqual( self.res_users_model.with_company( self.company_2 - ).operating_unit_default_get(uid2=self.user1.id), + )._get_default_operating_unit(uid2=self.user1.id), ou_company_2, )