From 143412765fb334f900b07221ac226bfcb9df3fc6 Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Tue, 19 Oct 2021 09:05:55 +0000 Subject: [PATCH] [FIX] base: user group selection fields This is a followup on b6c688caa2bad1706443a7f950a268723b70e508, which has introduced a new bug. Consider two groups A and B in a given category, where B implies A and also A.id > B.id. For the sake of simplicity, assume that A.id=2 and B.id=1. Following the commit above, the name of the group selection field will be 'sel_groups_1_2'. Consider a user in group B. Because B implies A, this means that the user now belongs to both A and B. A call to read() on that user returns field 'sel_groups_1_2' with value 2, which on the form view appears as the user belonging to A only. The error is in read(), which assumes that the group ids in the field name correspond to the implication order of the groups, which is no longer the case since b6c688caa2bad1706443a7f950a268723b70e508. closes odoo/odoo#78662 X-original-commit: e73c406671a51e9c1c4872a9e85eebe5656ea38e Signed-off-by: Raphael Collet (rco) --- odoo/addons/base/models/res_users.py | 7 +++- odoo/addons/base/tests/test_res_users.py | 42 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/odoo/addons/base/models/res_users.py b/odoo/addons/base/models/res_users.py index b57556f7f7a..cbfc6616563 100644 --- a/odoo/addons/base/models/res_users.py +++ b/odoo/addons/base/models/res_users.py @@ -1471,7 +1471,12 @@ class UsersView(models.Model): if is_boolean_group(f): values[f] = get_boolean_group(f) in gids elif is_selection_groups(f): - selected = [gid for gid in get_selection_groups(f) if gid in gids] + # determine selection groups, in order + sel_groups = self.env['res.groups'].sudo().browse(get_selection_groups(f)) + sel_order = {g: len(g.trans_implied_ids & sel_groups) for g in sel_groups} + sel_groups = sel_groups.sorted(key=sel_order.get) + # determine which ones are in gids + selected = [gid for gid in sel_groups.ids if gid in gids] # if 'Internal User' is in the group, this is the "User Type" group # and we need to show 'Internal User' selected, not Public/Portal. if self.env.ref('base.group_user').id in selected: diff --git a/odoo/addons/base/tests/test_res_users.py b/odoo/addons/base/tests/test_res_users.py index 34f21356abe..fa93dca0407 100644 --- a/odoo/addons/base/tests/test_res_users.py +++ b/odoo/addons/base/tests/test_res_users.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from odoo.addons.base.models.res_users import is_selection_groups, get_selection_groups from odoo.tests.common import TransactionCase, Form, tagged @@ -129,3 +130,44 @@ class TestUsers2(TransactionCase): user = f.save() self.assertIn(self.env.ref('base.group_user'), user.groups_id) + + def test_selection_groups(self): + # create 3 groups that should be in a selection + app = self.env['ir.module.category'].create({'name': 'Foo'}) + group1, group2, group0 = self.env['res.groups'].create([ + {'name': name, 'category_id': app.id} + for name in ('User', 'Manager', 'Visitor') + ]) + # THIS PART IS NECESSARY TO REPRODUCE AN ISSUE: group1.id < group2.id < group0.id + self.assertLess(group1.id, group2.id) + self.assertLess(group2.id, group0.id) + # implication order is group0 < group1 < group2 + group2.implied_ids = group1 + group1.implied_ids = group0 + groups = group0 + group1 + group2 + + # determine the name of the field corresponding to groups + fname = next( + name + for name in self.env['res.users'].fields_get() + if is_selection_groups(name) and group0.id in get_selection_groups(name) + ) + self.assertCountEqual(get_selection_groups(fname), groups.ids) + + # create a user + user = self.env['res.users'].create({'name': 'foo', 'login': 'foo'}) + + # put user in group0, and check field value + user.write({fname: group0.id}) + self.assertEqual(user.groups_id & groups, group0) + self.assertEqual(user.read([fname])[0][fname], group0.id) + + # put user in group1, and check field value + user.write({fname: group1.id}) + self.assertEqual(user.groups_id & groups, group0 + group1) + self.assertEqual(user.read([fname])[0][fname], group1.id) + + # put user in group2, and check field value + user.write({fname: group2.id}) + self.assertEqual(user.groups_id & groups, groups) + self.assertEqual(user.read([fname])[0][fname], group2.id)