From 59285440a5e0f796c5db944a50b80e3b8cf8172f Mon Sep 17 00:00:00 2001 From: karuna Date: Fri, 10 Jul 2026 16:34:39 +0530 Subject: [PATCH] Implemented Roles Management and Weekly Timesheet enhancements --- .../__manifest__.py | 2 +- .../models/__init__.py | 2 +- .../models/res_users.py | 29 +- .../models/user_role.py | 58 ++-- .../views/res_users_views.xml | 7 +- .../weekly_timesheets/__manifest__.py | 4 +- .../models/weekly_period_timesheets.py | 247 ++++++++++++++++-- .../security/weekly_timesheet_rules.xml | 61 +++++ .../views/week_timesheet.xml | 20 +- .../views/weekly_period_timesheets.xml | 43 ++- 10 files changed, 385 insertions(+), 88 deletions(-) create mode 100644 addons_extensions/weekly_timesheets/security/weekly_timesheet_rules.xml diff --git a/addons_extensions/role_based_group_management/__manifest__.py b/addons_extensions/role_based_group_management/__manifest__.py index a447ce883..465bfede1 100644 --- a/addons_extensions/role_based_group_management/__manifest__.py +++ b/addons_extensions/role_based_group_management/__manifest__.py @@ -1,7 +1,7 @@ { "name": "Role-Based Group Management", "summary": "Manage reusable security-group roles for users", - "version": "18.0.1.4.0", + "version": "18.0.1.6.0", "category": "Administration/Access Rights", "license": "LGPL-3", "author": "Custom", diff --git a/addons_extensions/role_based_group_management/models/__init__.py b/addons_extensions/role_based_group_management/models/__init__.py index cccafcc0b..beaab4982 100644 --- a/addons_extensions/role_based_group_management/models/__init__.py +++ b/addons_extensions/role_based_group_management/models/__init__.py @@ -1,2 +1,2 @@ -from . import res_users from . import user_role +from . import res_users diff --git a/addons_extensions/role_based_group_management/models/res_users.py b/addons_extensions/role_based_group_management/models/res_users.py index cf2c3926e..47b7fe46d 100644 --- a/addons_extensions/role_based_group_management/models/res_users.py +++ b/addons_extensions/role_based_group_management/models/res_users.py @@ -7,11 +7,21 @@ class ResUsers(models.Model): role_id = fields.Many2one( comodel_name="res.users.role", - string="Role", + string="Legacy Role", groups="base.group_system", ondelete="set null", copy=False, - help="Reusable role whose groups can be synchronized to this user.", + help="Legacy single role field kept only to migrate old records.", + ) + role_ids = fields.Many2many( + comodel_name="res.users.role", + relation="res_users_role_user_rel", + column1="user_id", + column2="role_id", + string="Assigned Roles", + groups="base.group_system", + copy=False, + help="Reusable roles whose groups can be synchronized to this user.", ) role_managed_group_ids = fields.Many2many( comodel_name="res.groups", @@ -28,11 +38,13 @@ class ResUsers(models.Model): @api.model_create_multi def create(self, vals_list): users = super().create(vals_list) - users.filtered("role_id")._sync_groups_from_role() + users.filtered( + lambda user: user.role_ids or user.role_id + )._sync_groups_from_role() return users def write(self, values): - role_changed = "role_id" in values + role_changed = "role_ids" in values or "role_id" in values result = super().write(values) if role_changed: self._sync_groups_from_role() @@ -61,14 +73,15 @@ class ResUsers(models.Model): protected_groups = self._get_protected_role_group_ids() for user in self: - role_groups = user.role_id.group_ids + roles = user.role_ids | user.role_id + role_groups = roles.mapped("group_ids") desired_groups = role_groups | role_groups.trans_implied_ids desired_groups -= protected_groups current_groups = user.groups_id previously_managed = user.role_managed_group_ids - if user.role_id: + if roles: groups_to_remove = current_groups - desired_groups - protected_groups direct_groups_to_add = role_groups - current_groups - protected_groups managed_groups = desired_groups @@ -94,8 +107,8 @@ class ResUsers(models.Model): self.ensure_one() if not self.env.user.has_group("base.group_system"): raise AccessError(_("Only Settings administrators can synchronize roles.")) - if not self.role_id: - raise UserError(_("Select a role before fetching groups.")) + if not (self.role_ids or self.role_id): + raise UserError(_("Select at least one role before fetching groups.")) self._sync_groups_from_role() return { "type": "ir.actions.client", diff --git a/addons_extensions/role_based_group_management/models/user_role.py b/addons_extensions/role_based_group_management/models/user_role.py index bc8f96293..3ddbdf683 100644 --- a/addons_extensions/role_based_group_management/models/user_role.py +++ b/addons_extensions/role_based_group_management/models/user_role.py @@ -17,17 +17,12 @@ class ResUsersRole(models.Model): domain=lambda self: self._get_allowed_group_domain(), help="Security groups granted by this role. User-type groups are intentionally excluded.", ) - user_ids = fields.One2many( - comodel_name="res.users", - inverse_name="role_id", - string="Users", - readonly=True, - ) assigned_user_ids = fields.Many2many( comodel_name="res.users", + relation="res_users_role_user_rel", + column1="role_id", + column2="user_id", string="Assigned Users", - compute="_compute_assigned_user_ids", - inverse="_inverse_assigned_user_ids", domain=[("share", "=", False)], help="Select internal users to assign this role. Their groups are synchronized automatically.", ) @@ -49,33 +44,15 @@ class ResUsersRole(models.Model): else [] ) - @api.depends("user_ids") + @api.depends("assigned_user_ids") def _compute_user_count(self): - counts = self.env["res.users"]._read_group( - [("role_id", "in", self.ids)], ["role_id"], ["__count"] - ) - count_by_role = {role.id: count for role, count in counts} for role in self: - role.user_count = count_by_role.get(role.id, 0) - - def _compute_assigned_user_ids(self): - users = self.env["res.users"].with_context(active_test=False).search( - [("role_id", "in", self.ids)] - ) - for role in self: - role.assigned_user_ids = users.filtered( - lambda user: user.role_id == role + role.user_count = self.env["res.users"].with_context( + active_test=False + ).search_count( + ["|", ("role_ids", "in", [role.id]), ("role_id", "=", role.id)] ) - def _inverse_assigned_user_ids(self): - """Apply additions/removals made through the role's user selector.""" - Users = self.env["res.users"].with_context(active_test=False) - for role in self.filtered("id"): - current_users = Users.search([("role_id", "=", role.id)]) - selected_users = role.assigned_user_ids - (current_users - selected_users).write({"role_id": False}) - (selected_users - current_users).write({"role_id": role.id}) - @api.constrains("group_ids") def _check_group_ids_do_not_include_user_types(self): user_type_category = self.env.ref( @@ -97,19 +74,24 @@ class ResUsersRole(models.Model): ) def write(self, values): - groups_changed = "group_ids" in values - result = super().write(values) - if groups_changed: - users = self.env["res.users"].with_context(active_test=False).search( - [("role_id", "in", self.ids)] + sync_needed = "group_ids" in values or "assigned_user_ids" in values + users_before = self.env["res.users"] + if sync_needed: + users_before = self.env["res.users"].with_context(active_test=False).search( + ["|", ("role_ids", "in", self.ids), ("role_id", "in", self.ids)] ) - users._sync_groups_from_role() + result = super().write(values) + if sync_needed: + users_after = self.env["res.users"].with_context(active_test=False).search( + ["|", ("role_ids", "in", self.ids), ("role_id", "in", self.ids)] + ) + (users_before | users_after)._sync_groups_from_role() return result def action_update_users(self): self.ensure_one() users = self.env["res.users"].with_context(active_test=False).search( - [("role_id", "=", self.id)] + ["|", ("role_ids", "in", [self.id]), ("role_id", "=", self.id)] ) users._sync_groups_from_role() return { diff --git a/addons_extensions/role_based_group_management/views/res_users_views.xml b/addons_extensions/role_based_group_management/views/res_users_views.xml index 53be917c0..4a7d71fab 100644 --- a/addons_extensions/role_based_group_management/views/res_users_views.xml +++ b/addons_extensions/role_based_group_management/views/res_users_views.xml @@ -10,14 +10,15 @@ appears at the top of Access Rights, just above User Type. --> -