[IMP] base: Add compute/inverse methods to manage user groups

Purpose
=======

Allow to define users groups on a res.user with computed fields based on the 'groups_id' field.

Specification
=============

Add compute/inverse methods to manage specific groups on a res.users.

These methods should be used on fields defined like one the following cases:

1. A boolean field with the compute/inverse method and an attribute group_xml_id.
Example:
    has_group_discount_per_so_line = fields.Boolean(
        "Discount on lines",
        compute='_compute_groups_id', inverse='_inverse_groups_id',
        group_xml_id='sale.group_discount_per_so_line')

2. A selection field with the compute/inverse method, the selection got from '_get_group_selection'
   and an attribute 'category_xml_id'
Example:
    group_sales_team_user = fields.Selection(
        selection=lambda self: self._get_group_selection('base.module_category_sales_management'),
        string="Sales", compute='_compute_groups_id', inverse='_inverse_groups_id',
        category_xml_id='base.module_category_sales_management')

The fields will be set according to the groups defined in the 'groups_id' field, and the 'groups_id'
field will be modified according to the modifications made on theses fields when saving the users's
form.
This commit is contained in:
len-odoo
2018-04-26 15:13:38 +02:00
committed by Yannick Tivisse
parent e67b61811b
commit ab179bb2d7
+106
View File
@@ -624,6 +624,112 @@ class Users(models.Model):
def get_company_currency_id(self):
return self.env.user.company_id.currency_id.id
def _add_missing_default_values(self, vals):
# Remove the default values of 'group_' and 'has_group' fields at the user creation if
# 'groups_id' is provided in vals and if the fields value is not explicitely given.
res = super(Users, self)._add_missing_default_values(vals)
return {
key: value for (key, value) in res.items()
if 'groups_id' not in vals or key in vals or (not is_boolean_group(key) or not is_selection_groups(key))
}
def _get_group_selection(self, category_xml_id):
"""Returns the ordered selection for the given ir.module.category xmlid"""
category = self.env.ref(category_xml_id, raise_if_not_found=False)
selections = []
if category:
groups = self.env['res.groups'].search([('category_id', '=', category.id)])
order = {group: len(group.trans_implied_ids & groups) for group in groups}
groups = groups.sorted(key=order.get)
selections = [(group.id, group.name) for group in groups]
return selections
@api.depends('groups_id')
def _compute_groups_id(self):
"""Set the value for the group field (Selection of Boolean)
according to the user's groups, defined by the field 'groups_id'.
These methods should be used on fields defined like one the
following cases:
1. A boolean field with the compute/inverse method and an attribute
group_xml_id.
Example:
has_group_discount_per_so_line = fields.Boolean(
"Discount on lines",
compute='_compute_groups_id', inverse='_inverse_groups_id',
group_xml_id='sale.group_discount_per_so_line')
2. A selection field with the compute/inverse method, the selection
got from '_get_group_selection' and an attribute
'category_xml_id'
Example:
group_sales_team_user = fields.Selection(
selection=lambda self: self._get_group_selection('base.module_category_sales_management'),
string="Sales", compute='_compute_groups_id', inverse='_inverse_groups_id',
category_xml_id='base.module_category_sales_management')
The fields will be set according to the groups defined in the 'groups_id'
field, and the 'groups_id' field will be modified according to the
modifications made on theses fields when saving the users's form.
"""
computed_group_fields = [field for field in self._field_computed.keys() if field.compute == '_compute_groups_id']
all_groups = self.env['res.groups'].search([])
category_data = {}
# Retrieve groups order for selection fields
for field in computed_group_fields:
if getattr(field, 'category_xml_id', None):
category = self.env.ref(getattr(field, 'category_xml_id'))
category_groups = all_groups.filtered(lambda group: group.category_id == category)
order = {group: len(group.trans_implied_ids & category_groups) for group in category_groups}
category_data[field] = category_groups.sorted(key=order.get, reverse=True)
# Set group fields values according to groups_id
for user in self:
for field in computed_group_fields:
# Checkbox group
if getattr(field, 'group_xml_id', None):
group = self.env.ref(getattr(field, 'group_xml_id'))
user[field.name] = group in user.groups_id
# Selection group
elif getattr(field, 'category_xml_id', None):
# Take the highest level group the user belongs to
user_groups = [group for group in category_data[field] if group in user.groups_id]
user[field.name] = user_groups[0].id if user_groups else False
else:
_logger.warning(_("No 'group_xml_id' or 'category_xml_id' is set on the computed field %s linked to the method _compute_groups_id") % (field.name))
def _inverse_groups_id(self):
"""Update 'groups_id' according the group fields values in cache."""
computed_group_fields = [field for field in self._field_computed.keys() if field.compute == '_compute_groups_id']
all_groups = self.env['res.groups'].search([])
for user in self:
# we need to read all values in cache before any prefetch
field_values = {field: user[field.name] for field in computed_group_fields if field.name in user._cache}
groups_id_vals = []
for field, value in field_values.items():
# Checkbox group
if getattr(field, 'group_xml_id', None):
selected_group = self.env.ref(getattr(field, 'group_xml_id'))
if value:
groups_id_vals.append((4, selected_group.id))
else:
groups_id_vals.append((3, selected_group.id))
for group in selected_group.trans_implied_ids:
groups_id_vals.append((4, group.id))
# Selection group
elif getattr(field, 'category_xml_id', None):
category = self.env.ref(getattr(field, 'category_xml_id'))
category_groups = [group for group in all_groups if group.category_id == category]
selected_group = [group for group in all_groups if group.id == value]
selected_group = selected_group and selected_group[0] or self.env['res.groups']
for group in category_groups:
if group in (selected_group.trans_implied_ids | selected_group):
groups_id_vals.append((4, group.id))
else:
groups_id_vals.append((3, group.id))
else:
_logger.warning(_("No 'group_xml_id' or 'category_xml_id' is set on the computed field %s linked to the method _compute_groups_id") % (field.name))
if groups_id_vals:
user.write({'groups_id': groups_id_vals})
#
# Implied groups
#