Public release from ruodoo-project: 19.0 - 2026-05-10 21:19:01 UTC

This commit is contained in:
CI Publish Bot
2026-05-10 21:19:11 +00:00
commit cbf9e6e6d6
1213 changed files with 183945 additions and 0 deletions

View File

@ -0,0 +1,3 @@
from . import role
from . import user
from . import res_groups

View File

@ -0,0 +1,87 @@
from odoo import api, fields, models
class ResGroups(models.Model):
_inherit = "res.groups"
view_access = fields.Many2many(
groups="base.group_system",
)
# The inverse field of the field group_id on the res.users.role model
# This field should be used a One2one relation as a role can only be
# represented by one group. It's declared as a One2many field as the
# inverse field on the res.users.role it's declared as a Many2one
role_id = fields.One2many(
comodel_name="res.users.role",
inverse_name="group_id",
help="Relation for the groups that represents a role",
)
role_ids = fields.Many2many(
comodel_name="res.users.role",
relation="res_groups_implied_roles_rel",
string="User Roles",
compute="_compute_role_ids",
help="Roles in which the group is involved",
)
parent_ids = fields.Many2many(
"res.groups",
"res_groups_implied_rel",
"hid",
"gid",
string="Parents",
help="Inverse relation for the Inherits field. "
"The groups from which this group is inheriting",
)
trans_parent_ids = fields.Many2many(
comodel_name="res.groups",
string="Parent Groups",
compute="_compute_trans_parent_ids",
recursive=True,
)
role_count = fields.Integer("# User Roles", compute="_compute_role_count")
def _compute_role_count(self):
for group in self:
group.role_count = len(group.role_ids)
@api.depends("parent_ids.trans_parent_ids")
def _compute_trans_parent_ids(self):
for group in self:
group.trans_parent_ids = (
group.parent_ids | group.parent_ids.trans_parent_ids
)
def _compute_role_ids(self):
for group in self:
if group.trans_parent_ids:
group.role_ids = group.trans_parent_ids.role_id
else:
group.role_ids = group.role_id
def action_view_roles(self):
self.ensure_one()
action = self.env["ir.actions.act_window"]._for_xml_id(
"base_user_role.action_res_users_role_tree"
)
action["context"] = {}
if len(self.role_ids) > 1:
action["domain"] = [("id", "in", self.role_ids.ids)]
elif self.role_ids:
form_view = [
(self.env.ref("base_user_role.view_res_users_role_form").id, "form")
]
if "views" in action:
action["views"] = form_view + [
(state, view) for state, view in action["views"] if view != "form"
]
else:
action["views"] = form_view
action["res_id"] = self.role_ids.id
else:
action = {"type": "ir.actions.act_window_close"}
return action

View File

@ -0,0 +1,170 @@
# Copyright 2014 ABF OSIELL <http://osiell.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
import datetime
import logging
from odoo import SUPERUSER_ID, _, api, fields, models
_logger = logging.getLogger(__name__)
class ResUsersRole(models.Model):
_name = "res.users.role"
_inherits = {"res.groups": "group_id"}
_description = "User Role"
group_id = fields.Many2one(
comodel_name="res.groups",
required=True,
ondelete="cascade",
readonly=True,
string="Associated group",
)
line_ids = fields.One2many(
comodel_name="res.users.role.line", inverse_name="role_id", string="Role lines"
)
user_ids = fields.One2many(
comodel_name="res.users", string="Users list", compute="_compute_user_ids"
)
rule_ids = fields.Many2many(
comodel_name="ir.rule",
compute="_compute_rule_ids",
string="Record Rules",
required=False,
)
rules_count = fields.Integer(compute="_compute_rule_ids")
model_access_ids = fields.Many2many(
comodel_name="ir.model.access",
compute="_compute_model_access_ids",
string="Access Rights",
required=False,
)
model_access_count = fields.Integer(compute="_compute_model_access_ids")
@api.depends("line_ids.user_id")
def _compute_user_ids(self):
for role in self.sudo() if self._bypass_rules() else self:
role.user_ids = role.line_ids.mapped("user_id")
@api.depends("implied_ids", "implied_ids.model_access")
def _compute_model_access_ids(self):
for rec in self:
rec.model_access_ids = rec.implied_ids.model_access.ids
rec.model_access_count = len(rec.model_access_ids)
@api.depends("implied_ids", "implied_ids.rule_groups")
def _compute_rule_ids(self):
for rec in self:
rec.rule_ids = rec.implied_ids.rule_groups.ids
rec.rules_count = len(rec.rule_ids)
@api.model
def _bypass_rules(self):
# Run methods as super user to avoid problems by "Administrator/Access Right"
return self._name == "res.users.role" and self.env.user.has_group(
"base.group_erp_manager"
)
@api.model_create_multi
def create(self, vals_list):
model = (self.sudo() if self._bypass_rules() else self).browse()
new_records = super(ResUsersRole, model).create(vals_list)
new_records.update_users()
return new_records
def read(self, fields=None, load="_classic_read"):
recs = self.sudo() if self._bypass_rules() else self
return super(ResUsersRole, recs).read(fields, load)
def write(self, vals):
recs = self.sudo() if self._bypass_rules() else self
# Workaround to solve issue with broken code in odoo that clear the
# cache during the write: see odoo/addons/base/models/res_users.py#L226
groups_vals = {}
for field in recs.group_id._fields:
if field in vals:
groups_vals[field] = vals.pop(field)
if groups_vals:
recs.group_id.write(groups_vals)
res = super(ResUsersRole, recs).write(vals)
recs.update_users()
return res
def unlink(self):
users = self.mapped("user_ids")
res = super().unlink()
users.set_groups_from_roles(force=True)
return res
def copy(self, default=None):
self.ensure_one()
default = dict(default or {}, name=_("%s (copy)", self.name))
return super().copy(default)
def update_users(self):
"""Update all the users concerned by the roles identified by `ids`."""
users = self.mapped("user_ids")
users.set_groups_from_roles()
return True
@api.model
def cron_update_users(self):
logging.info("Update user roles")
self.search([]).update_users()
def show_rule_ids(self):
action = self.env["ir.actions.actions"]._for_xml_id("base.action_rule")
action["domain"] = [("id", "in", self.rule_ids.ids)]
return action
def show_model_access_ids(self):
action = self.env["ir.actions.actions"]._for_xml_id("base.ir_access_act")
action["domain"] = [("id", "in", self.model_access_ids.ids)]
return action
class ResUsersRoleLine(models.Model):
_name = "res.users.role.line"
_description = "Users associated to a role"
active = fields.Boolean(related="user_id.active")
role_id = fields.Many2one(
comodel_name="res.users.role", required=True, string="Role", ondelete="cascade"
)
user_id = fields.Many2one(
comodel_name="res.users",
required=True,
string="User",
domain=[("id", "!=", SUPERUSER_ID)],
ondelete="cascade",
)
date_from = fields.Date("From")
date_to = fields.Date("To")
is_enabled = fields.Boolean("Enabled", compute="_compute_is_enabled")
_sql_constraints = [
(
"user_role_uniq",
"unique (user_id,role_id)",
"User roles can be assigned to a user only once at a time",
)
]
@api.depends("date_from", "date_to")
def _compute_is_enabled(self):
today = datetime.date.today()
for role_line in self:
role_line.is_enabled = True
if role_line.date_from:
date_from = role_line.date_from
if date_from > today:
role_line.is_enabled = False
if role_line.date_to:
date_to = role_line.date_to
if today > date_to:
role_line.is_enabled = False
def unlink(self):
users = self.mapped("user_id")
res = super().unlink()
users.set_groups_from_roles(force=True)
return res

View File

@ -0,0 +1,107 @@
# Copyright 2014 ABF OSIELL <http://osiell.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
from odoo import api, fields, models
class ResUsers(models.Model):
_inherit = "res.users"
role_line_ids = fields.One2many(
comodel_name="res.users.role.line",
inverse_name="user_id",
string="Role lines",
default=lambda self: self._default_role_lines(),
groups="base.group_erp_manager",
)
show_alert = fields.Boolean(compute="_compute_show_alert")
@api.depends("role_line_ids")
def _compute_show_alert(self):
for user in self:
user.show_alert = user.role_line_ids.filtered(lambda rec: rec.is_enabled)
role_ids = fields.One2many(
comodel_name="res.users.role",
string="User Roles",
compute="_compute_role_ids",
compute_sudo=True,
groups="base.group_erp_manager",
)
@api.model
def _default_role_lines(self):
default_user = self.env.ref("base.default_user", raise_if_not_found=False)
default_values = []
if default_user:
for role_line in default_user.with_context(active_test=False).role_line_ids:
default_values.append(
{
"role_id": role_line.role_id.id,
"date_from": role_line.date_from,
"date_to": role_line.date_to,
"is_enabled": role_line.is_enabled,
}
)
return default_values
@api.depends("role_line_ids.role_id")
def _compute_role_ids(self):
for user in self:
user.role_ids = user.role_line_ids.mapped("role_id")
@api.model_create_multi
def create(self, vals_list):
new_records = super().create(vals_list)
new_records.set_groups_from_roles()
return new_records
def write(self, vals):
res = super().write(vals)
self.sudo().set_groups_from_roles()
return res
def _get_enabled_roles(self):
return self.role_line_ids.filtered(lambda rec: rec.is_enabled)
@api.model
def _get_self_writable_groups(self):
group = self.env.ref(
"mail.group_mail_notification_type_inbox", raise_if_not_found=False
)
return group or self.env["res.groups"]
def set_groups_from_roles(self, force=False):
"""Set (replace) the groups following the roles defined on users.
If no role is defined on the user, its groups are let untouched unless
the `force` parameter is `True`.
"""
role_groups = {}
# We obtain all the groups associated to each role first, so that
# it is faster to compare later with each user's groups.
for role in self.mapped("role_line_ids.role_id"):
role_groups[role] = list(
set(
role.group_id.ids
+ role.implied_ids.ids
+ role.all_implied_ids.ids
)
)
self_writable_group_ids = self._get_self_writable_groups().ids
for user in self:
if not user.role_line_ids and not force:
continue
user_group_ids = set(user.group_ids.ids).difference(self_writable_group_ids)
group_ids = set()
for role_line in user._get_enabled_roles():
role = role_line.role_id
group_ids.update(role_groups[role])
groups_to_add = group_ids - user_group_ids
groups_to_remove = user_group_ids - group_ids
to_add = [(4, gr) for gr in groups_to_add]
to_remove = [(3, gr) for gr in groups_to_remove]
groups = to_remove + to_add
if groups:
vals = {"group_ids": groups}
super(ResUsers, user).write(vals)
return True