From adc6b3641644e643c9d981f2debe21fec48db6c2 Mon Sep 17 00:00:00 2001 From: Chandresh Thakkar OSI Date: Tue, 4 May 2021 02:06:01 +0530 Subject: [PATCH 01/45] [ADD] base_user_role_company: add per company user roles --- base_user_role_company/__init__.py | 4 ++ base_user_role_company/__manifest__.py | 19 ++++++ base_user_role_company/models/__init__.py | 5 ++ base_user_role_company/models/ir_http.py | 23 +++++++ base_user_role_company/models/role.py | 65 +++++++++++++++++++ base_user_role_company/readme/CONFIGURE.rst | 6 ++ .../readme/CONTRIBUTORS.rst | 4 ++ base_user_role_company/readme/DESCRIPTION.rst | 9 +++ base_user_role_company/readme/USAGE.rst | 17 +++++ base_user_role_company/tests/__init__.py | 1 + .../tests/test_role_per_company.py | 62 ++++++++++++++++++ base_user_role_company/views/role.xml | 14 ++++ 12 files changed, 229 insertions(+) create mode 100644 base_user_role_company/__init__.py create mode 100644 base_user_role_company/__manifest__.py create mode 100644 base_user_role_company/models/__init__.py create mode 100644 base_user_role_company/models/ir_http.py create mode 100644 base_user_role_company/models/role.py create mode 100644 base_user_role_company/readme/CONFIGURE.rst create mode 100644 base_user_role_company/readme/CONTRIBUTORS.rst create mode 100644 base_user_role_company/readme/DESCRIPTION.rst create mode 100644 base_user_role_company/readme/USAGE.rst create mode 100644 base_user_role_company/tests/__init__.py create mode 100644 base_user_role_company/tests/test_role_per_company.py create mode 100644 base_user_role_company/views/role.xml diff --git a/base_user_role_company/__init__.py b/base_user_role_company/__init__.py new file mode 100644 index 000000000..bb83730e9 --- /dev/null +++ b/base_user_role_company/__init__.py @@ -0,0 +1,4 @@ +# Copyright (C) 2021 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import models diff --git a/base_user_role_company/__manifest__.py b/base_user_role_company/__manifest__.py new file mode 100644 index 000000000..5b1af0981 --- /dev/null +++ b/base_user_role_company/__manifest__.py @@ -0,0 +1,19 @@ +# Copyright (C) 2021 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "User roles by company", + "version": "14.0.1.0.0", + "category": "Tools", + "author": "Open Source Integrators, Odoo Community Association (OCA)", + "license": "AGPL-3", + "website": "https://github.com/OCA/server-backend", + "depends": ["base_user_role"], + "data": [ + "views/role.xml", + ], + "installable": True, + "auto_install": True, + "maintainer": "dreispt", + "development_status": "Beta", +} diff --git a/base_user_role_company/models/__init__.py b/base_user_role_company/models/__init__.py new file mode 100644 index 000000000..d38a0acf7 --- /dev/null +++ b/base_user_role_company/models/__init__.py @@ -0,0 +1,5 @@ +# Copyright (C) 2021 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import role +from . import ir_http diff --git a/base_user_role_company/models/ir_http.py b/base_user_role_company/models/ir_http.py new file mode 100644 index 000000000..7eaca704a --- /dev/null +++ b/base_user_role_company/models/ir_http.py @@ -0,0 +1,23 @@ +# Copyright (C) 2021 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import models +from odoo.http import request + + +class IrHttp(models.AbstractModel): + _inherit = "ir.http" + + def session_info(self): + """ + Based on the selected companies (cids), + calculate the roles to enable. + A role should be enabled only when it applies to all selected companies. + """ + result = super(IrHttp, self).session_info() + if self.env.user.role_line_ids: + cids_str = request.httprequest.cookies.get("cids", str(self.env.company.id)) + cids = [int(cid) for cid in cids_str.split(",")] + self.env.user._set_session_active_roles(cids) + self.env.user.set_groups_from_roles() + return result diff --git a/base_user_role_company/models/role.py b/base_user_role_company/models/role.py new file mode 100644 index 000000000..c6702494c --- /dev/null +++ b/base_user_role_company/models/role.py @@ -0,0 +1,65 @@ +# Copyright (C) 2021 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class ResUsersRoleLine(models.Model): + _inherit = "res.users.role.line" + + company_id = fields.Many2one( + "res.company", + "Company", + help="If set, this role only applies when this is the main company selected." + " Otherwise it applies to all companies.", + ) + active_role = fields.Boolean(string="Active Role", default=True) + + @api.constrains("user_id", "company_id") + def _check_company(self): + for record in self: + if ( + record.company_id + and record.company_id != record.user_id.company_id + and record.company_id not in record.user_id.company_ids + ): + raise ValidationError( + _('User "{}" does not have access to the company "{}"').format( + record.user_id.name, record.company_id.name + ) + ) + + _sql_constraints = [ + ( + "user_role_uniq", + "unique (user_id,role_id,company_id)", + "Roles can be assigned to a user only once at a time", + ) + ] + + +class ResUsers(models.Model): + _inherit = "res.users" + + def _get_enabled_roles(self): + res = super()._get_enabled_roles() + return res.filtered("active_role") + + @api.model + def _set_session_active_roles(self, cids): + """ + Based on the selected companies (cids), + calculate the roles to enable. + A role should be enabled only when it applies to all selected companies. + """ + for role_line in self.env.user.role_line_ids: + if not role_line.company_id: + role_line.active_role = True + elif role_line.company_id.id in cids: + is_on_companies = self.env.user.role_line_ids.filtered( + lambda x: x.role_id == role_line.role_id and x.company_id.id in cids + ) + role_line.active_role = len(is_on_companies) == len(cids) + else: + role_line.active_role = False diff --git a/base_user_role_company/readme/CONFIGURE.rst b/base_user_role_company/readme/CONFIGURE.rst new file mode 100644 index 000000000..c50bf9fec --- /dev/null +++ b/base_user_role_company/readme/CONFIGURE.rst @@ -0,0 +1,6 @@ +Roles are set on the User form. + +The "Company" additional column allows to set a Role as only valid for specific companies. + +There is also a "Active Role" techincal field, only visible in developer mode. +It shows what roles are active, after applying the company selection rules. diff --git a/base_user_role_company/readme/CONTRIBUTORS.rst b/base_user_role_company/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..c259741d2 --- /dev/null +++ b/base_user_role_company/readme/CONTRIBUTORS.rst @@ -0,0 +1,4 @@ +`Open Source Integrators `_ + + * Daniel Reis + * Chandresh Thakkar diff --git a/base_user_role_company/readme/DESCRIPTION.rst b/base_user_role_company/readme/DESCRIPTION.rst new file mode 100644 index 000000000..68507f1e4 --- /dev/null +++ b/base_user_role_company/readme/DESCRIPTION.rst @@ -0,0 +1,9 @@ +Enable User Roles depending on the Companies selected. + +A company specific Role will only be enabled +if it is set for **all** the currently selected companies. + +For example, if a user is "Sales Manager" only for Company A, +it will see that role enabled only if Company A is selected. +If the user selects Company A and Company B, +then the "Sales Manager" role won't be enabled. diff --git a/base_user_role_company/readme/USAGE.rst b/base_user_role_company/readme/USAGE.rst new file mode 100644 index 000000000..88dce6bc7 --- /dev/null +++ b/base_user_role_company/readme/USAGE.rst @@ -0,0 +1,17 @@ +Select the active companies from the web client widget, near the top right corner. +When doing so, the User's security Groups are recomputed, based on the Roles. + +When the user changes the company selection, only the groups available to all active companies will be activated. + +For example: + +* A "SALES PERSON" and a "SALES MANAGER" roles are created. + +* A user is assigned to the roles: + * "SALES PERSON", with no specific company assigned (meaning all) + * "SALES MANAGER" only to "My Company (Chicago)" + +* When selecting active companies from the UI widget: + * If only "My Company (San Francisco)" is active, "SALES PERSON" will be active. + * If only "My Company (Chicago)" is active, "SALES PERSON" and "SALES MANAGER" will be active. + * If both "My Company (San Francisco)" and "My Company (Chicago)" is active, "SALES PERSON" will be active. diff --git a/base_user_role_company/tests/__init__.py b/base_user_role_company/tests/__init__.py new file mode 100644 index 000000000..cd7f7833f --- /dev/null +++ b/base_user_role_company/tests/__init__.py @@ -0,0 +1 @@ +from . import test_role_per_company diff --git a/base_user_role_company/tests/test_role_per_company.py b/base_user_role_company/tests/test_role_per_company.py new file mode 100644 index 000000000..14cb869bf --- /dev/null +++ b/base_user_role_company/tests/test_role_per_company.py @@ -0,0 +1,62 @@ +# Copyright 2021 Open Source Integrators +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo.tests.common import TransactionCase + + +class TestUserRoleCompany(TransactionCase): + def setUp(self): + super().setUp() + # COMPANIES + self.Company = self.env["res.company"] + self.company1 = self.env.ref("base.main_company") + self.company2 = self.Company.create({"name": "company2"}) + # ROLES + self.Role = self.env["res.users.role"] + self.roleA = self.Role.create({"name": "ROLE All Companies"}) + self.roleB = self.Role.create({"name": "ROLE Company 1"}) + self.roleC = self.Role.create({"name": "ROLE Company 1 and 2"}) + # USER + # ==Role=== ==Company== C1 C2 C1+C2 + # Role A Yes Yes Yes + # Role B Company1 Yes + # Role C Company1 Yes Yes + # Role C Company2 Yes Yes + self.User = self.env["res.users"] + user_vals = { + "name": "ROLES TEST USER", + "login": "test_user", + "company_ids": [(6, 0, [self.company1.id, self.company2.id])], + "role_line_ids": [ + (0, 0, {"role_id": self.roleA.id}), + (0, 0, {"role_id": self.roleB.id, "company_id": self.company1.id}), + (0, 0, {"role_id": self.roleC.id, "company_id": self.company1.id}), + (0, 0, {"role_id": self.roleC.id, "company_id": self.company2.id}), + ], + } + self.test_user = self.User.create(user_vals) + self.User = self.User.with_user(self.test_user) + + def test_110_company_1(self): + "Company 1 selected: Tech and Settings roles are activated" + self.User._set_session_active_roles([self.company1.id]) + active_roles = self.test_user.role_line_ids.filtered("active_role").mapped( + "role_id" + ) + self.assertEqual(active_roles, self.roleA | self.roleB | self.roleC) + + def test_120_company_2(self): + "Company 2 selected: only Tech role enabled" + self.User._set_session_active_roles([self.company2.id]) + active_roles = self.test_user.role_line_ids.filtered("active_role").mapped( + "role_id" + ) + self.assertEqual(active_roles, self.roleA | self.roleC) + + def test_130_company_1_2(self): + "Settings Role enabled for Company 1 and 2" + self.User._set_session_active_roles([self.company1.id, self.company2.id]) + active_roles = self.test_user.role_line_ids.filtered("active_role").mapped( + "role_id" + ) + self.assertEqual(active_roles, self.roleA | self.roleC) diff --git a/base_user_role_company/views/role.xml b/base_user_role_company/views/role.xml new file mode 100644 index 000000000..bfcb01e8f --- /dev/null +++ b/base_user_role_company/views/role.xml @@ -0,0 +1,14 @@ + + + + res.users.form.inherit.company + res.users + + + + + + + + + From 5849eccdcf3258a4ba898621bd74707e517778e9 Mon Sep 17 00:00:00 2001 From: oca-travis Date: Wed, 19 May 2021 18:13:39 +0000 Subject: [PATCH 02/45] [UPD] Update base_user_role_company.pot --- .../i18n/base_user_role_company.pot | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 base_user_role_company/i18n/base_user_role_company.pot diff --git a/base_user_role_company/i18n/base_user_role_company.pot b/base_user_role_company/i18n/base_user_role_company.pot new file mode 100644 index 000000000..776c3cb0a --- /dev/null +++ b/base_user_role_company/i18n/base_user_role_company.pot @@ -0,0 +1,78 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * base_user_role_company +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: base_user_role_company +#: model:ir.model.fields,field_description:base_user_role_company.field_res_users_role_line__active_role +msgid "Active Role" +msgstr "" + +#. module: base_user_role_company +#: model:ir.model.fields,field_description:base_user_role_company.field_res_users_role_line__company_id +msgid "Company" +msgstr "" + +#. module: base_user_role_company +#: model:ir.model.fields,field_description:base_user_role_company.field_ir_http__display_name +#: model:ir.model.fields,field_description:base_user_role_company.field_res_users__display_name +#: model:ir.model.fields,field_description:base_user_role_company.field_res_users_role_line__display_name +msgid "Display Name" +msgstr "" + +#. module: base_user_role_company +#: model:ir.model,name:base_user_role_company.model_ir_http +msgid "HTTP Routing" +msgstr "" + +#. module: base_user_role_company +#: model:ir.model.fields,field_description:base_user_role_company.field_ir_http__id +#: model:ir.model.fields,field_description:base_user_role_company.field_res_users__id +#: model:ir.model.fields,field_description:base_user_role_company.field_res_users_role_line__id +msgid "ID" +msgstr "" + +#. module: base_user_role_company +#: model:ir.model.fields,help:base_user_role_company.field_res_users_role_line__company_id +msgid "" +"If set, this role only applies when this is the main company selected. " +"Otherwise it applies to all companies." +msgstr "" + +#. module: base_user_role_company +#: model:ir.model.fields,field_description:base_user_role_company.field_ir_http____last_update +#: model:ir.model.fields,field_description:base_user_role_company.field_res_users____last_update +#: model:ir.model.fields,field_description:base_user_role_company.field_res_users_role_line____last_update +msgid "Last Modified on" +msgstr "" + +#. module: base_user_role_company +#: model:ir.model.constraint,message:base_user_role_company.constraint_res_users_role_line_user_role_uniq +msgid "Roles can be assigned to a user only once at a time" +msgstr "" + +#. module: base_user_role_company +#: code:addons/base_user_role_company/models/role.py:0 +#, python-format +msgid "User \"{}\" does not have access to the company \"{}\"" +msgstr "" + +#. module: base_user_role_company +#: model:ir.model,name:base_user_role_company.model_res_users +msgid "Users" +msgstr "" + +#. module: base_user_role_company +#: model:ir.model,name:base_user_role_company.model_res_users_role_line +msgid "Users associated to a role" +msgstr "" From 3f39499b0fe82d755dfb9685f0c2f71f322ee01b Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Wed, 19 May 2021 18:27:49 +0000 Subject: [PATCH 03/45] [UPD] README.rst --- base_user_role_company/README.rst | 115 +++++ .../static/description/index.html | 467 ++++++++++++++++++ 2 files changed, 582 insertions(+) create mode 100644 base_user_role_company/README.rst create mode 100644 base_user_role_company/static/description/index.html diff --git a/base_user_role_company/README.rst b/base_user_role_company/README.rst new file mode 100644 index 000000000..5b7d12252 --- /dev/null +++ b/base_user_role_company/README.rst @@ -0,0 +1,115 @@ +===================== +User roles by company +===================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--backend-lightgray.png?logo=github + :target: https://github.com/OCA/server-backend/tree/14.0/base_user_role_company + :alt: OCA/server-backend +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/server-backend-14-0/server-backend-14-0-base_user_role_company + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/253/14.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Enable User Roles depending on the Companies selected. + +A company specific Role will only be enabled +if it is set for **all** the currently selected companies. + +For example, if a user is "Sales Manager" only for Company A, +it will see that role enabled only if Company A is selected. +If the user selects Company A and Company B, +then the "Sales Manager" role won't be enabled. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +Roles are set on the User form. + +The "Company" additional column allows to set a Role as only valid for specific companies. + +There is also a "Active Role" techincal field, only visible in developer mode. +It shows what roles are active, after applying the company selection rules. + +Usage +===== + +Select the active companies from the web client widget, near the top right corner. +When doing so, the User's security Groups are recomputed, based on the Roles. + +When the user changes the company selection, only the groups available to all active companies will be activated. + +For example: + +* A "SALES PERSON" and a "SALES MANAGER" roles are created. + +* A user is assigned to the roles: + * "SALES PERSON", with no specific company assigned (meaning all) + * "SALES MANAGER" only to "My Company (Chicago)" + +* When selecting active companies from the UI widget: + * If only "My Company (San Francisco)" is active, "SALES PERSON" will be active. + * If only "My Company (Chicago)" is active, "SALES PERSON" and "SALES MANAGER" will be active. + * If both "My Company (San Francisco)" and "My Company (Chicago)" is active, "SALES PERSON" will be active. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Open Source Integrators + +Contributors +~~~~~~~~~~~~ + +`Open Source Integrators `_ + + * Daniel Reis + * Chandresh Thakkar + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/server-backend `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/base_user_role_company/static/description/index.html b/base_user_role_company/static/description/index.html new file mode 100644 index 000000000..9eb4a6fcc --- /dev/null +++ b/base_user_role_company/static/description/index.html @@ -0,0 +1,467 @@ + + + + + + +User roles by company + + + +
+

User roles by company

+ + +

Beta License: AGPL-3 OCA/server-backend Translate me on Weblate Try me on Runbot

+

Enable User Roles depending on the Companies selected.

+

A company specific Role will only be enabled +if it is set for all the currently selected companies.

+

For example, if a user is “Sales Manager” only for Company A, +it will see that role enabled only if Company A is selected. +If the user selects Company A and Company B, +then the “Sales Manager” role won’t be enabled.

+

Table of contents

+ +
+

Configuration

+

Roles are set on the User form.

+

The “Company” additional column allows to set a Role as only valid for specific companies.

+

There is also a “Active Role” techincal field, only visible in developer mode. +It shows what roles are active, after applying the company selection rules.

+
+
+

Usage

+

Select the active companies from the web client widget, near the top right corner. +When doing so, the User’s security Groups are recomputed, based on the Roles.

+

When the user changes the company selection, only the groups available to all active companies will be activated.

+

For example:

+
    +
  • A “SALES PERSON” and a “SALES MANAGER” roles are created.
  • +
  • +
    A user is assigned to the roles:
    +
      +
    • “SALES PERSON”, with no specific company assigned (meaning all)
    • +
    • “SALES MANAGER” only to “My Company (Chicago)”
    • +
    +
    +
    +
  • +
  • +
    When selecting active companies from the UI widget:
    +
      +
    • If only “My Company (San Francisco)” is active, “SALES PERSON” will be active.
    • +
    • If only “My Company (Chicago)” is active, “SALES PERSON” and “SALES MANAGER” will be active.
    • +
    • If both “My Company (San Francisco)” and “My Company (Chicago)” is active, “SALES PERSON” will be active.
    • +
    +
    +
    +
  • +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Open Source Integrators
  • +
+
+ +
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/server-backend project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + From 43dca59c29802310ed0c3323d27617c08303942d Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Wed, 19 May 2021 18:27:49 +0000 Subject: [PATCH 04/45] [ADD] icon.png --- .../static/description/icon.png | Bin 0 -> 9455 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 base_user_role_company/static/description/icon.png diff --git a/base_user_role_company/static/description/icon.png b/base_user_role_company/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 From 5f84a9b85ab9fe3a99fb1041f8ec9556753ad8de Mon Sep 17 00:00:00 2001 From: Andrii Skrypka Date: Wed, 3 Nov 2021 10:04:09 +0200 Subject: [PATCH 05/45] [FIX] base_user_role_company: wrong xpath --- base_user_role_company/views/role.xml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/base_user_role_company/views/role.xml b/base_user_role_company/views/role.xml index bfcb01e8f..89bd80ad7 100644 --- a/base_user_role_company/views/role.xml +++ b/base_user_role_company/views/role.xml @@ -5,10 +5,13 @@ res.users - + - + From 31d424bf413266c4e31ed510e6c225f1938c370e Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Thu, 4 Nov 2021 18:50:53 +0000 Subject: [PATCH 06/45] base_user_role_company 14.0.1.1.0 --- base_user_role_company/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base_user_role_company/__manifest__.py b/base_user_role_company/__manifest__.py index 5b1af0981..8e306b5c8 100644 --- a/base_user_role_company/__manifest__.py +++ b/base_user_role_company/__manifest__.py @@ -3,7 +3,7 @@ { "name": "User roles by company", - "version": "14.0.1.0.0", + "version": "14.0.1.1.0", "category": "Tools", "author": "Open Source Integrators, Odoo Community Association (OCA)", "license": "AGPL-3", From fa5145dbac421f0332a5907fa015128e8ac0e9c6 Mon Sep 17 00:00:00 2001 From: Riccardo Bellanova Date: Tue, 15 Feb 2022 12:15:48 +0000 Subject: [PATCH 07/45] Added translation using Weblate (Italian) --- base_user_role_company/i18n/it.po | 79 +++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 base_user_role_company/i18n/it.po diff --git a/base_user_role_company/i18n/it.po b/base_user_role_company/i18n/it.po new file mode 100644 index 000000000..b48538f39 --- /dev/null +++ b/base_user_role_company/i18n/it.po @@ -0,0 +1,79 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * base_user_role_company +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#. module: base_user_role_company +#: model:ir.model.fields,field_description:base_user_role_company.field_res_users_role_line__active_role +msgid "Active Role" +msgstr "" + +#. module: base_user_role_company +#: model:ir.model.fields,field_description:base_user_role_company.field_res_users_role_line__company_id +msgid "Company" +msgstr "" + +#. module: base_user_role_company +#: model:ir.model.fields,field_description:base_user_role_company.field_ir_http__display_name +#: model:ir.model.fields,field_description:base_user_role_company.field_res_users__display_name +#: model:ir.model.fields,field_description:base_user_role_company.field_res_users_role_line__display_name +msgid "Display Name" +msgstr "" + +#. module: base_user_role_company +#: model:ir.model,name:base_user_role_company.model_ir_http +msgid "HTTP Routing" +msgstr "" + +#. module: base_user_role_company +#: model:ir.model.fields,field_description:base_user_role_company.field_ir_http__id +#: model:ir.model.fields,field_description:base_user_role_company.field_res_users__id +#: model:ir.model.fields,field_description:base_user_role_company.field_res_users_role_line__id +msgid "ID" +msgstr "" + +#. module: base_user_role_company +#: model:ir.model.fields,help:base_user_role_company.field_res_users_role_line__company_id +msgid "" +"If set, this role only applies when this is the main company selected. " +"Otherwise it applies to all companies." +msgstr "" + +#. module: base_user_role_company +#: model:ir.model.fields,field_description:base_user_role_company.field_ir_http____last_update +#: model:ir.model.fields,field_description:base_user_role_company.field_res_users____last_update +#: model:ir.model.fields,field_description:base_user_role_company.field_res_users_role_line____last_update +msgid "Last Modified on" +msgstr "" + +#. module: base_user_role_company +#: model:ir.model.constraint,message:base_user_role_company.constraint_res_users_role_line_user_role_uniq +msgid "Roles can be assigned to a user only once at a time" +msgstr "" + +#. module: base_user_role_company +#: code:addons/base_user_role_company/models/role.py:0 +#, python-format +msgid "User \"{}\" does not have access to the company \"{}\"" +msgstr "" + +#. module: base_user_role_company +#: model:ir.model,name:base_user_role_company.model_res_users +msgid "Users" +msgstr "" + +#. module: base_user_role_company +#: model:ir.model,name:base_user_role_company.model_res_users_role_line +msgid "Users associated to a role" +msgstr "" From 4b1dcf99f382a1aa1d5d8957bc1886a31e756c89 Mon Sep 17 00:00:00 2001 From: Daniel Reis Date: Tue, 15 Feb 2022 12:34:49 +0000 Subject: [PATCH 08/45] [FIX] base_user_role_company: roles not properly applied on login --- base_user_role_company/models/__init__.py | 1 + base_user_role_company/models/ir_http.py | 4 +-- base_user_role_company/models/role.py | 29 ++---------------- base_user_role_company/models/user.py | 36 +++++++++++++++++++++++ base_user_role_company/views/role.xml | 2 +- 5 files changed, 42 insertions(+), 30 deletions(-) create mode 100644 base_user_role_company/models/user.py diff --git a/base_user_role_company/models/__init__.py b/base_user_role_company/models/__init__.py index d38a0acf7..32004dfac 100644 --- a/base_user_role_company/models/__init__.py +++ b/base_user_role_company/models/__init__.py @@ -2,4 +2,5 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from . import role +from . import user from . import ir_http diff --git a/base_user_role_company/models/ir_http.py b/base_user_role_company/models/ir_http.py index 7eaca704a..65a6b3b91 100644 --- a/base_user_role_company/models/ir_http.py +++ b/base_user_role_company/models/ir_http.py @@ -18,6 +18,6 @@ def session_info(self): if self.env.user.role_line_ids: cids_str = request.httprequest.cookies.get("cids", str(self.env.company.id)) cids = [int(cid) for cid in cids_str.split(",")] - self.env.user._set_session_active_roles(cids) - self.env.user.set_groups_from_roles() + # The first element of cids is the currently selected company + self.env.user.set_groups_from_roles(company_id=cids[0]) return result diff --git a/base_user_role_company/models/role.py b/base_user_role_company/models/role.py index c6702494c..0fdd234d8 100644 --- a/base_user_role_company/models/role.py +++ b/base_user_role_company/models/role.py @@ -8,13 +8,14 @@ class ResUsersRoleLine(models.Model): _inherit = "res.users.role.line" + allowed_company_ids = fields.Many2many(related="user_id.company_ids") company_id = fields.Many2one( "res.company", "Company", + domain="[('id', 'in', allowed_company_ids)]", help="If set, this role only applies when this is the main company selected." " Otherwise it applies to all companies.", ) - active_role = fields.Boolean(string="Active Role", default=True) @api.constrains("user_id", "company_id") def _check_company(self): @@ -37,29 +38,3 @@ def _check_company(self): "Roles can be assigned to a user only once at a time", ) ] - - -class ResUsers(models.Model): - _inherit = "res.users" - - def _get_enabled_roles(self): - res = super()._get_enabled_roles() - return res.filtered("active_role") - - @api.model - def _set_session_active_roles(self, cids): - """ - Based on the selected companies (cids), - calculate the roles to enable. - A role should be enabled only when it applies to all selected companies. - """ - for role_line in self.env.user.role_line_ids: - if not role_line.company_id: - role_line.active_role = True - elif role_line.company_id.id in cids: - is_on_companies = self.env.user.role_line_ids.filtered( - lambda x: x.role_id == role_line.role_id and x.company_id.id in cids - ) - role_line.active_role = len(is_on_companies) == len(cids) - else: - role_line.active_role = False diff --git a/base_user_role_company/models/user.py b/base_user_role_company/models/user.py new file mode 100644 index 000000000..edc9ee0d2 --- /dev/null +++ b/base_user_role_company/models/user.py @@ -0,0 +1,36 @@ +# Copyright (C) 2021 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, models + + +class ResUsers(models.Model): + _inherit = "res.users" + + @classmethod + def authenticate(cls, db, login, password, user_agent_env): + uid = super().authenticate(db, login, password, user_agent_env) + # On login, ensure the proper roles are applied + # The last Role applied may not be the correct one, + # sonce the new session current company can be different + with cls.pool.cursor() as cr: + env = api.Environment(cr, uid, {}) + if env.user.role_line_ids: + env.user.set_groups_from_roles() + return uid + + def _get_enabled_roles(self): + res = super()._get_enabled_roles() + # Enable only the Roles corresponing to the currently selected company + if self.env.user.role_line_ids: + curr_company = self.env.company + res = res.filtered( + lambda x: not x.company_id or x.company_id == curr_company + ) + return res + + def set_groups_from_roles(self, force=False, company_id=False): + # When using the Company Switcher widget, the self.env.company is not yet set + if company_id: + self = self.with_company(company_id) + return super().set_groups_from_roles(force=force) diff --git a/base_user_role_company/views/role.xml b/base_user_role_company/views/role.xml index 89bd80ad7..9cb06b7e9 100644 --- a/base_user_role_company/views/role.xml +++ b/base_user_role_company/views/role.xml @@ -9,8 +9,8 @@ expr="//field[@name='role_line_ids']//field[@name='role_id']" position="after" > + - From 77a34f8d0d4a10341b7e98885f350a9314d339e2 Mon Sep 17 00:00:00 2001 From: Riccardo Bellanova Date: Tue, 15 Feb 2022 13:51:05 +0000 Subject: [PATCH 09/45] Translated using Weblate (Italian) Currently translated at 100.0% (11 of 11 strings) Translation: server-backend-14.0/server-backend-14.0-base_user_role_company Translate-URL: https://translation.odoo-community.org/projects/server-backend-14-0/server-backend-14-0-base_user_role_company/it/ --- base_user_role_company/i18n/it.po | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/base_user_role_company/i18n/it.po b/base_user_role_company/i18n/it.po index b48538f39..f28ab71a1 100644 --- a/base_user_role_company/i18n/it.po +++ b/base_user_role_company/i18n/it.po @@ -6,42 +6,44 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 14.0\n" "Report-Msgid-Bugs-To: \n" -"Last-Translator: Automatically generated\n" +"PO-Revision-Date: 2022-02-15 16:16+0000\n" +"Last-Translator: Riccardo Bellanova \n" "Language-Team: none\n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" "Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.3.2\n" #. module: base_user_role_company #: model:ir.model.fields,field_description:base_user_role_company.field_res_users_role_line__active_role msgid "Active Role" -msgstr "" +msgstr "Ruolo attivo" #. module: base_user_role_company #: model:ir.model.fields,field_description:base_user_role_company.field_res_users_role_line__company_id msgid "Company" -msgstr "" +msgstr "Azienda" #. module: base_user_role_company #: model:ir.model.fields,field_description:base_user_role_company.field_ir_http__display_name #: model:ir.model.fields,field_description:base_user_role_company.field_res_users__display_name #: model:ir.model.fields,field_description:base_user_role_company.field_res_users_role_line__display_name msgid "Display Name" -msgstr "" +msgstr "Nome visualizzato" #. module: base_user_role_company #: model:ir.model,name:base_user_role_company.model_ir_http msgid "HTTP Routing" -msgstr "" +msgstr "Rotta HTTP" #. module: base_user_role_company #: model:ir.model.fields,field_description:base_user_role_company.field_ir_http__id #: model:ir.model.fields,field_description:base_user_role_company.field_res_users__id #: model:ir.model.fields,field_description:base_user_role_company.field_res_users_role_line__id msgid "ID" -msgstr "" +msgstr "ID" #. module: base_user_role_company #: model:ir.model.fields,help:base_user_role_company.field_res_users_role_line__company_id @@ -49,31 +51,33 @@ msgid "" "If set, this role only applies when this is the main company selected. " "Otherwise it applies to all companies." msgstr "" +"Se impostato, questo ruolo si applica solo quando questa è l'azienda " +"principale selezionata. Altrimenti vale per tutte le aziende." #. module: base_user_role_company #: model:ir.model.fields,field_description:base_user_role_company.field_ir_http____last_update #: model:ir.model.fields,field_description:base_user_role_company.field_res_users____last_update #: model:ir.model.fields,field_description:base_user_role_company.field_res_users_role_line____last_update msgid "Last Modified on" -msgstr "" +msgstr "Ultima modifica il" #. module: base_user_role_company #: model:ir.model.constraint,message:base_user_role_company.constraint_res_users_role_line_user_role_uniq msgid "Roles can be assigned to a user only once at a time" -msgstr "" +msgstr "I ruoli possono essere assegnati all'utente solo uno alla volta" #. module: base_user_role_company #: code:addons/base_user_role_company/models/role.py:0 #, python-format msgid "User \"{}\" does not have access to the company \"{}\"" -msgstr "" +msgstr "L'utente \"{}\" non ha l'accesso all'azienda \"{}\"" #. module: base_user_role_company #: model:ir.model,name:base_user_role_company.model_res_users msgid "Users" -msgstr "" +msgstr "Utenti" #. module: base_user_role_company #: model:ir.model,name:base_user_role_company.model_res_users_role_line msgid "Users associated to a role" -msgstr "" +msgstr "Utenti associati al ruolo" From f3f8bd2460678a8454e4d6126b94b0788ace7a7c Mon Sep 17 00:00:00 2001 From: Daniel Reis Date: Wed, 2 Mar 2022 12:42:30 +0000 Subject: [PATCH 10/45] [FIX] base_user_role_company: wrong menus on re-login Issue found on logout / relogin. The user groups were applied correctly, but the main menu showed apps the user did not have access to. This was related to the menu caching mechanisn, that was disabled here. --- base_user_role_company/__init__.py | 1 + base_user_role_company/controllers/__init__.py | 1 + base_user_role_company/controllers/main.py | 16 ++++++++++++++++ 3 files changed, 18 insertions(+) create mode 100644 base_user_role_company/controllers/__init__.py create mode 100644 base_user_role_company/controllers/main.py diff --git a/base_user_role_company/__init__.py b/base_user_role_company/__init__.py index bb83730e9..efc2a3f33 100644 --- a/base_user_role_company/__init__.py +++ b/base_user_role_company/__init__.py @@ -1,4 +1,5 @@ # Copyright (C) 2021 Open Source Integrators # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from . import controllers from . import models diff --git a/base_user_role_company/controllers/__init__.py b/base_user_role_company/controllers/__init__.py new file mode 100644 index 000000000..12a7e529b --- /dev/null +++ b/base_user_role_company/controllers/__init__.py @@ -0,0 +1 @@ +from . import main diff --git a/base_user_role_company/controllers/main.py b/base_user_role_company/controllers/main.py new file mode 100644 index 000000000..7df62870e --- /dev/null +++ b/base_user_role_company/controllers/main.py @@ -0,0 +1,16 @@ +# Copyright (C) 2022 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import http + +from odoo.addons.web.controllers.main import Home + + +class HomeExtended(Home): + @http.route() + def web_load_menus(self, unique): + response = super().web_load_menus(unique) + # On logout & re-login we could see wrong menus being rendered + # To avoid this, menu http cache must be disabled + response.headers.remove("Cache-Control") + return response From 668e5ec6fabc217fa1e0100100904cf435f6f928 Mon Sep 17 00:00:00 2001 From: Daniel Reis Date: Thu, 3 Mar 2022 11:40:58 +0000 Subject: [PATCH 11/45] [FIX] base_user_role_company: fix tests --- base_user_role_company/models/user.py | 5 +-- .../tests/test_role_per_company.py | 41 ++++++++++--------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/base_user_role_company/models/user.py b/base_user_role_company/models/user.py index edc9ee0d2..1a2f6296b 100644 --- a/base_user_role_company/models/user.py +++ b/base_user_role_company/models/user.py @@ -22,10 +22,9 @@ def authenticate(cls, db, login, password, user_agent_env): def _get_enabled_roles(self): res = super()._get_enabled_roles() # Enable only the Roles corresponing to the currently selected company - if self.env.user.role_line_ids: - curr_company = self.env.company + if self.role_line_ids: res = res.filtered( - lambda x: not x.company_id or x.company_id == curr_company + lambda x: not x.company_id or x.company_id == self.env.company ) return res diff --git a/base_user_role_company/tests/test_role_per_company.py b/base_user_role_company/tests/test_role_per_company.py index 14cb869bf..9b1ac1fcc 100644 --- a/base_user_role_company/tests/test_role_per_company.py +++ b/base_user_role_company/tests/test_role_per_company.py @@ -11,11 +11,18 @@ def setUp(self): self.Company = self.env["res.company"] self.company1 = self.env.ref("base.main_company") self.company2 = self.Company.create({"name": "company2"}) + # GROUPS for roles + self.groupA = self.env.ref("base.group_user") + self.groupB = self.env.ref("base.group_system") + self.groupC = self.env.ref("base.group_partner_manager") # ROLES self.Role = self.env["res.users.role"] self.roleA = self.Role.create({"name": "ROLE All Companies"}) + self.roleA.implied_ids |= self.groupA self.roleB = self.Role.create({"name": "ROLE Company 1"}) + self.roleB.implied_ids |= self.groupB self.roleC = self.Role.create({"name": "ROLE Company 1 and 2"}) + self.roleC.implied_ids |= self.groupC # USER # ==Role=== ==Company== C1 C2 C1+C2 # Role A Yes Yes Yes @@ -35,28 +42,22 @@ def setUp(self): ], } self.test_user = self.User.create(user_vals) - self.User = self.User.with_user(self.test_user) def test_110_company_1(self): - "Company 1 selected: Tech and Settings roles are activated" - self.User._set_session_active_roles([self.company1.id]) - active_roles = self.test_user.role_line_ids.filtered("active_role").mapped( - "role_id" - ) - self.assertEqual(active_roles, self.roleA | self.roleB | self.roleC) + "Company 1 selected: Roles A, B and C are enabled" + self.test_user.set_groups_from_roles(company_id=self.company1.id) + expected = self.groupA | self.groupB | self.groupC + found = self.test_user.groups_id.filtered(lambda x: x in expected) + self.assertEqual(expected, found) def test_120_company_2(self): - "Company 2 selected: only Tech role enabled" - self.User._set_session_active_roles([self.company2.id]) - active_roles = self.test_user.role_line_ids.filtered("active_role").mapped( - "role_id" - ) - self.assertEqual(active_roles, self.roleA | self.roleC) + "Company 2 selected: Roles A and C are enabled" + self.test_user.set_groups_from_roles(company_id=self.company2.id) + enabled = self.test_user.groups_id + expected = self.groupA | self.groupC + found = enabled.filtered(lambda x: x in expected) + self.assertEqual(expected, found) - def test_130_company_1_2(self): - "Settings Role enabled for Company 1 and 2" - self.User._set_session_active_roles([self.company1.id, self.company2.id]) - active_roles = self.test_user.role_line_ids.filtered("active_role").mapped( - "role_id" - ) - self.assertEqual(active_roles, self.roleA | self.roleC) + not_expected = self.groupB + found = enabled.filtered(lambda x: x in not_expected) + self.assertFalse(found) From 3b37c52ca70bda07b963c44ba6b2e47e250f0040 Mon Sep 17 00:00:00 2001 From: oca-travis Date: Thu, 3 Mar 2022 15:29:25 +0000 Subject: [PATCH 12/45] [UPD] Update base_user_role_company.pot --- base_user_role_company/i18n/base_user_role_company.pot | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base_user_role_company/i18n/base_user_role_company.pot b/base_user_role_company/i18n/base_user_role_company.pot index 776c3cb0a..3b1fe1508 100644 --- a/base_user_role_company/i18n/base_user_role_company.pot +++ b/base_user_role_company/i18n/base_user_role_company.pot @@ -14,8 +14,8 @@ msgstr "" "Plural-Forms: \n" #. module: base_user_role_company -#: model:ir.model.fields,field_description:base_user_role_company.field_res_users_role_line__active_role -msgid "Active Role" +#: model:ir.model.fields,field_description:base_user_role_company.field_res_users_role_line__allowed_company_ids +msgid "Companies" msgstr "" #. module: base_user_role_company From 4ad41ce0a2ed76ebf76804bd84c83f2f48863176 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Thu, 3 Mar 2022 15:33:16 +0000 Subject: [PATCH 13/45] base_user_role_company 14.0.2.0.0 --- base_user_role_company/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base_user_role_company/__manifest__.py b/base_user_role_company/__manifest__.py index 8e306b5c8..b5716f984 100644 --- a/base_user_role_company/__manifest__.py +++ b/base_user_role_company/__manifest__.py @@ -3,7 +3,7 @@ { "name": "User roles by company", - "version": "14.0.1.1.0", + "version": "14.0.2.0.0", "category": "Tools", "author": "Open Source Integrators, Odoo Community Association (OCA)", "license": "AGPL-3", From 6d90736364ca056e49ca366c76969cbd26d4c474 Mon Sep 17 00:00:00 2001 From: OCA Transbot Date: Thu, 3 Mar 2022 15:33:27 +0000 Subject: [PATCH 14/45] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: server-backend-14.0/server-backend-14.0-base_user_role_company Translate-URL: https://translation.odoo-community.org/projects/server-backend-14-0/server-backend-14-0-base_user_role_company/ --- base_user_role_company/i18n/it.po | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/base_user_role_company/i18n/it.po b/base_user_role_company/i18n/it.po index f28ab71a1..c587735df 100644 --- a/base_user_role_company/i18n/it.po +++ b/base_user_role_company/i18n/it.po @@ -17,9 +17,9 @@ msgstr "" "X-Generator: Weblate 4.3.2\n" #. module: base_user_role_company -#: model:ir.model.fields,field_description:base_user_role_company.field_res_users_role_line__active_role -msgid "Active Role" -msgstr "Ruolo attivo" +#: model:ir.model.fields,field_description:base_user_role_company.field_res_users_role_line__allowed_company_ids +msgid "Companies" +msgstr "" #. module: base_user_role_company #: model:ir.model.fields,field_description:base_user_role_company.field_res_users_role_line__company_id @@ -81,3 +81,6 @@ msgstr "Utenti" #: model:ir.model,name:base_user_role_company.model_res_users_role_line msgid "Users associated to a role" msgstr "Utenti associati al ruolo" + +#~ msgid "Active Role" +#~ msgstr "Ruolo attivo" From 57e012c8386496311ac6e9cf9bcf097ce7792c47 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Thu, 3 Mar 2022 15:45:46 +0000 Subject: [PATCH 15/45] base_user_role_company 14.0.2.0.1 --- base_user_role_company/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base_user_role_company/__manifest__.py b/base_user_role_company/__manifest__.py index b5716f984..d39f645a7 100644 --- a/base_user_role_company/__manifest__.py +++ b/base_user_role_company/__manifest__.py @@ -3,7 +3,7 @@ { "name": "User roles by company", - "version": "14.0.2.0.0", + "version": "14.0.2.0.1", "category": "Tools", "author": "Open Source Integrators, Odoo Community Association (OCA)", "license": "AGPL-3", From d9950f57567f8cb9cf06a929e6178ddf3380adc9 Mon Sep 17 00:00:00 2001 From: Francesco Foresti Date: Tue, 7 Mar 2023 17:07:28 +0000 Subject: [PATCH 16/45] Translated using Weblate (Italian) Currently translated at 90.9% (10 of 11 strings) Translation: server-backend-14.0/server-backend-14.0-base_user_role_company Translate-URL: https://translation.odoo-community.org/projects/server-backend-14-0/server-backend-14-0-base_user_role_company/it/ --- base_user_role_company/i18n/it.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/base_user_role_company/i18n/it.po b/base_user_role_company/i18n/it.po index c587735df..90e9e0b20 100644 --- a/base_user_role_company/i18n/it.po +++ b/base_user_role_company/i18n/it.po @@ -6,15 +6,15 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 14.0\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2022-02-15 16:16+0000\n" -"Last-Translator: Riccardo Bellanova \n" +"PO-Revision-Date: 2023-03-07 19:24+0000\n" +"Last-Translator: Francesco Foresti \n" "Language-Team: none\n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.3.2\n" +"X-Generator: Weblate 4.14.1\n" #. module: base_user_role_company #: model:ir.model.fields,field_description:base_user_role_company.field_res_users_role_line__allowed_company_ids @@ -36,7 +36,7 @@ msgstr "Nome visualizzato" #. module: base_user_role_company #: model:ir.model,name:base_user_role_company.model_ir_http msgid "HTTP Routing" -msgstr "Rotta HTTP" +msgstr "Instradamento HTTP" #. module: base_user_role_company #: model:ir.model.fields,field_description:base_user_role_company.field_ir_http__id From 68838038aee49e7e5af45ce0cee63e703485e131 Mon Sep 17 00:00:00 2001 From: Urvisha-OSI Date: Wed, 5 Apr 2023 12:43:55 +0530 Subject: [PATCH 17/45] [IMP] base_user_role_company: pre-commit stuff --- base_user_role_company/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base_user_role_company/__manifest__.py b/base_user_role_company/__manifest__.py index d39f645a7..4b225993f 100644 --- a/base_user_role_company/__manifest__.py +++ b/base_user_role_company/__manifest__.py @@ -3,7 +3,7 @@ { "name": "User roles by company", - "version": "14.0.2.0.1", + "version": "16.0.1.0.0", "category": "Tools", "author": "Open Source Integrators, Odoo Community Association (OCA)", "license": "AGPL-3", From ebc9834afb025b6f6b584ca0cf9193dab873d824 Mon Sep 17 00:00:00 2001 From: Urvisha-OSI Date: Wed, 5 Apr 2023 13:30:38 +0530 Subject: [PATCH 18/45] [MIG] base_user_role_company: Migration to 16.0 --- base_user_role_company/README.rst | 15 ++++++++------- base_user_role_company/controllers/main.py | 2 +- base_user_role_company/readme/CONTRIBUTORS.rst | 1 + .../static/description/index.html | 9 +++++---- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/base_user_role_company/README.rst b/base_user_role_company/README.rst index 5b7d12252..a75e13635 100644 --- a/base_user_role_company/README.rst +++ b/base_user_role_company/README.rst @@ -14,14 +14,14 @@ User roles by company :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--backend-lightgray.png?logo=github - :target: https://github.com/OCA/server-backend/tree/14.0/base_user_role_company + :target: https://github.com/OCA/server-backend/tree/16.0/base_user_role_company :alt: OCA/server-backend .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/server-backend-14-0/server-backend-14-0-base_user_role_company + :target: https://translation.odoo-community.org/projects/server-backend-16-0/server-backend-16-0-base_user_role_company :alt: Translate me on Weblate -.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/253/14.0 - :alt: Try me on Runbot +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/webui/builds.html?repo=OCA/server-backend&target_branch=16.0 + :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| @@ -77,7 +77,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -96,6 +96,7 @@ Contributors * Daniel Reis * Chandresh Thakkar + * Urvisha Desai Maintainers ~~~~~~~~~~~ @@ -110,6 +111,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. -This module is part of the `OCA/server-backend `_ project on GitHub. +This module is part of the `OCA/server-backend `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/base_user_role_company/controllers/main.py b/base_user_role_company/controllers/main.py index 7df62870e..7e75d6954 100644 --- a/base_user_role_company/controllers/main.py +++ b/base_user_role_company/controllers/main.py @@ -3,7 +3,7 @@ from odoo import http -from odoo.addons.web.controllers.main import Home +from odoo.addons.web.controllers.home import Home class HomeExtended(Home): diff --git a/base_user_role_company/readme/CONTRIBUTORS.rst b/base_user_role_company/readme/CONTRIBUTORS.rst index c259741d2..3b275b35c 100644 --- a/base_user_role_company/readme/CONTRIBUTORS.rst +++ b/base_user_role_company/readme/CONTRIBUTORS.rst @@ -2,3 +2,4 @@ * Daniel Reis * Chandresh Thakkar + * Urvisha Desai diff --git a/base_user_role_company/static/description/index.html b/base_user_role_company/static/description/index.html index 9eb4a6fcc..4eef8c25c 100644 --- a/base_user_role_company/static/description/index.html +++ b/base_user_role_company/static/description/index.html @@ -3,7 +3,7 @@ - + User roles by company -
-

User roles by company

+
+ + +Odoo Community Association + +
+

User roles by company

-

Beta License: AGPL-3 OCA/server-backend Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/server-backend Translate me on Weblate Try me on Runboat

Enable User Roles depending on the Companies selected.

A company specific Role will only be enabled if it is set for all the currently selected companies.

@@ -391,7 +396,7 @@

User roles by company

-

Configuration

+

Configuration

Roles are set on the User form.

The “Company” additional column allows to set a Role as only valid for specific companies.

@@ -400,7 +405,7 @@

Configuration

selection rules.

-

Usage

+

Usage

Select the active companies from the web client widget, near the top right corner. When doing so, the User’s security Groups are recomputed, based on the Roles.

@@ -415,10 +420,10 @@

Usage

  • When selecting active companies from the UI widget:
      -
    • If only “My Company (San Francisco)” is active, “SALES PERSON” will -be active.
    • -
    • If only “My Company (Chicago)” is active, “SALES PERSON” and “SALES -MANAGER” will be active.
    • +
    • If only “My Company (San Francisco)” is active, “SALES PERSON” +will be active.
    • +
    • If only “My Company (Chicago)” is active, “SALES PERSON” and +“SALES MANAGER” will be active.
    • If both “My Company (San Francisco)” and “My Company (Chicago)” is active, “SALES PERSON” will be active.
    @@ -426,23 +431,23 @@

    Usage

  • -

    Bug Tracker

    +

    Bug Tracker

    Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -feedback.

    +feedback.

    Do not contact contributors directly about support or help with technical issues.

    -

    Credits

    +

    Credits

    -

    Authors

    +

    Authors

    • Open Source Integrators
    -

    Maintainers

    +

    Maintainers

    This module is maintained by the OCA.

    Odoo Community Association @@ -473,10 +478,11 @@

    Maintainers

    OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

    -

    This module is part of the OCA/server-backend project on GitHub.

    +

    This module is part of the OCA/server-backend project on GitHub.

    You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

    +
    From 0250393ea05d8934708c04cf697f1e5e23a926cf Mon Sep 17 00:00:00 2001 From: Milan Topuzov Date: Thu, 9 Oct 2025 14:00:09 +0200 Subject: [PATCH 45/45] [MIG] base_user_role_company: migrate to 19.0 - Replace groups_id with group_ids in views/actions - Bump version to 19.0.1.0.0; adjust manifests/assets - Use env attributes and Domain expressions - Adopt new Constraint/Index APIs where applicable Functional changes --- base_user_role_company/controllers/main.py | 7 +++--- base_user_role_company/models/ir_http.py | 4 ++-- base_user_role_company/models/role.py | 18 +++++++-------- base_user_role_company/models/user.py | 23 +++++++++---------- base_user_role_company/tests/__init__.py | 1 + .../tests/test_load_menus.py | 14 +++++++++++ .../tests/test_role_per_company.py | 21 ++++++++++++++--- .../tests/test_use_only_enabled_roles.py | 4 ++-- 8 files changed, 61 insertions(+), 31 deletions(-) create mode 100644 base_user_role_company/tests/test_load_menus.py diff --git a/base_user_role_company/controllers/main.py b/base_user_role_company/controllers/main.py index 7e75d6954..b81f07643 100644 --- a/base_user_role_company/controllers/main.py +++ b/base_user_role_company/controllers/main.py @@ -8,9 +8,10 @@ class HomeExtended(Home): @http.route() - def web_load_menus(self, unique): - response = super().web_load_menus(unique) + def web_load_menus(self, *args, **kwargs): + response = super().web_load_menus(*args, **kwargs) # On logout & re-login we could see wrong menus being rendered # To avoid this, menu http cache must be disabled - response.headers.remove("Cache-Control") + # Using .pop() as Werkzeug Headers no longer supports __delitem__ (del) + response.headers.pop("Cache-Control", None) return response diff --git a/base_user_role_company/models/ir_http.py b/base_user_role_company/models/ir_http.py index a635453fa..43c097290 100644 --- a/base_user_role_company/models/ir_http.py +++ b/base_user_role_company/models/ir_http.py @@ -8,13 +8,13 @@ class IrHttp(models.AbstractModel): _inherit = "ir.http" - def session_info(self): + def session_info(self, *args, **kwargs): """ Based on the selected companies (cids), calculate the roles to enable. A role should be enabled only when it applies to all selected companies. """ - result = super().session_info() + result = super().session_info(*args, **kwargs) if self.env.user.role_line_ids: cids_str = request.httprequest.cookies.get("cids", str(self.env.company.id)) cids = [int(cid) for cid in cids_str.split("-")] diff --git a/base_user_role_company/models/role.py b/base_user_role_company/models/role.py index 3cadca8a0..40b6ca895 100644 --- a/base_user_role_company/models/role.py +++ b/base_user_role_company/models/role.py @@ -28,15 +28,15 @@ def _check_company(self): raise ValidationError( self.env._( 'User "%(user)s" does not have access to the company ' - '"%(company)s"' + '"%(company)s"', + user=record.user_id.name, + company=record.company_id.name, ) - % {"user": record.user_id.name, "company": record.company_id.name} ) - _sql_constraints = [ - ( - "user_role_uniq", - "unique (user_id,role_id,company_id)", - "Roles can be assigned to a user only once at a time", - ) - ] + # Override parent unique constraint to allow the same role multiple times + # for a user, provided company_id differs. + _user_role_uniq = models.Constraint( + "UNIQUE (user_id, role_id, company_id)", + "Roles can be assigned to a user only once at a time", + ) diff --git a/base_user_role_company/models/user.py b/base_user_role_company/models/user.py index 368b2ba26..9b80ce522 100644 --- a/base_user_role_company/models/user.py +++ b/base_user_role_company/models/user.py @@ -7,20 +7,18 @@ class ResUsers(models.Model): _inherit = "res.users" - @classmethod - def authenticate(cls, db, credential, user_agent_env): - auth_info = super().authenticate(db, credential, user_agent_env) - # On login, ensure the proper roles are applied - # The last Role applied may not be the correct one, - # sonce the new session current company can be different - with cls.pool.cursor() as cr: - env = api.Environment(cr, auth_info["uid"], {}) + def authenticate(self, *args, **kwargs): + auth_info = super().authenticate(*args, **kwargs) + # Ensure proper roles are applied for the logged-in user + uid = auth_info.get("uid") if isinstance(auth_info, dict) else None + if uid: + env = api.Environment(self.env.cr, uid, {}) if env.user.role_line_ids: env.user.set_groups_from_roles() return auth_info - def _get_enabled_roles(self): - res = super()._get_enabled_roles() + def _get_enabled_roles(self, *args, **kwargs): + res = super()._get_enabled_roles(*args, **kwargs) if self.role_line_ids: active_roles = self.env["res.users.role.line"] if self.env.context.get("active_company_ids"): @@ -32,8 +30,9 @@ def _get_enabled_roles(self): active_roles |= role_line elif role_line.company_id.id in company_ids: role_line_companies = self.role_line_ids.filtered( - lambda x, rl=role_line: x.role_id == rl.role_id - and x.company_id.id in company_ids + lambda x, rl=role_line: ( + x.role_id == rl.role_id and x.company_id.id in company_ids + ) ) if len(role_line_companies) == len(company_ids): active_roles |= role_line diff --git a/base_user_role_company/tests/__init__.py b/base_user_role_company/tests/__init__.py index 7ddf192b2..c92695ddb 100644 --- a/base_user_role_company/tests/__init__.py +++ b/base_user_role_company/tests/__init__.py @@ -1,2 +1,3 @@ from . import test_role_per_company from . import test_use_only_enabled_roles +from . import test_load_menus diff --git a/base_user_role_company/tests/test_load_menus.py b/base_user_role_company/tests/test_load_menus.py new file mode 100644 index 000000000..65232035c --- /dev/null +++ b/base_user_role_company/tests/test_load_menus.py @@ -0,0 +1,14 @@ +# Copyright 2026 Open Source Integrators +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo.tests.common import HttpCase + + +class LoadMenusTests(HttpCase): + def setUp(self): + super().setUp() + self.authenticate("admin", "admin") + + def test_load_menus(self): + "Expect no errors on HomeExtended.web_load_menus controller" + self.url_open("/web/webclient/load_menus") diff --git a/base_user_role_company/tests/test_role_per_company.py b/base_user_role_company/tests/test_role_per_company.py index 98b0c50bb..ee7c26e09 100644 --- a/base_user_role_company/tests/test_role_per_company.py +++ b/base_user_role_company/tests/test_role_per_company.py @@ -1,6 +1,7 @@ # Copyright 2021 Open Source Integrators # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). +from odoo.exceptions import ValidationError from odoo.tests.common import TransactionCase @@ -11,6 +12,7 @@ def setUp(self): self.Company = self.env["res.company"] self.company1 = self.env.ref("base.main_company") self.company2 = self.Company.create({"name": "company2"}) + self.company3 = self.Company.create({"name": "company3"}) # GROUPS for roles self.groupA = self.env.ref("base.group_user") self.groupB = self.env.ref("base.group_system") @@ -49,7 +51,7 @@ def test_110_company_1(self): active_company_ids=self.company1.ids ).set_groups_from_roles() expected = self.groupA | self.groupB | self.groupC - found = self.test_user.groups_id.filtered(lambda x: x in expected) + found = self.test_user.group_ids.filtered(lambda x: x in expected) self.assertEqual(expected, found) def test_120_company_2(self): @@ -57,7 +59,7 @@ def test_120_company_2(self): self.test_user.with_context( active_company_ids=self.company2.ids ).set_groups_from_roles() - enabled = self.test_user.groups_id + enabled = self.test_user.group_ids expected = self.groupA | self.groupC found = enabled.filtered(lambda x: x in expected) self.assertEqual(expected, found) @@ -71,7 +73,7 @@ def test_130_all_company(self): self.test_user.with_context( active_company_ids=[self.company1.id, self.company2.id] ).set_groups_from_roles() - enabled = self.test_user.groups_id + enabled = self.test_user.group_ids expected = self.groupA | self.groupC found = enabled.filtered(lambda x: x in expected) self.assertEqual(expected, found) @@ -79,3 +81,16 @@ def test_130_all_company(self): not_expected = self.groupB found = enabled.filtered(lambda x: x in not_expected) self.assertFalse(found) + + def test_140_company_3(self): + "Company 3 selected: ValidationError" + user_vals = { + "name": "ROLES TEST USER 2", + "login": "test_user_2", + "company_ids": [(6, 0, [self.company1.id, self.company2.id])], + "role_line_ids": [ + (0, 0, {"role_id": self.roleA.id, "company_id": self.company3.id}), + ], + } + with self.assertRaises(ValidationError): + self.User.create(user_vals) diff --git a/base_user_role_company/tests/test_use_only_enabled_roles.py b/base_user_role_company/tests/test_use_only_enabled_roles.py index 4b95e455a..98b62f9f2 100644 --- a/base_user_role_company/tests/test_use_only_enabled_roles.py +++ b/base_user_role_company/tests/test_use_only_enabled_roles.py @@ -46,7 +46,7 @@ def test_110_enabled_role_is_used(self): active_company_ids=self.company1.ids ).set_groups_from_roles() expected = self.groupA | self.groupB - found = self.test_user.groups_id.filtered(lambda x: x in expected) + found = self.test_user.group_ids.filtered(lambda x: x in expected) self.assertEqual(expected, found) def test_120_disabled_role_is_not_used(self): @@ -58,5 +58,5 @@ def test_120_disabled_role_is_not_used(self): active_company_ids=self.company1.ids ).set_groups_from_roles() expected = self.groupA - found = self.test_user.groups_id.filtered(lambda x: x in expected) + found = self.test_user.group_ids.filtered(lambda x: x in expected) self.assertEqual(expected, found)