From f050ef335ee5232c9c60f4b50f88797a6f65acfd Mon Sep 17 00:00:00 2001 From: "Dylan Kiss (dyki)" Date: Mon, 25 Sep 2023 11:39:48 +0200 Subject: [PATCH] [FIX] base,core: relax `{child,parent}_of` with related fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the context of branches, you need to be able to select taxes of an ancestor company on an invoice/bill, even when you don't have access to the ancestor company. In order to do that, we relax the restriction when searching with a `parent_of` or `child_of` on a related field, so that it also includes ids of related field records you don't have access to. This should not be a problem, since in the end the search will return records of a model restricted by its own access rules. task-3503204 closes odoo/odoo#138942 Signed-off-by: William André (wan) Signed-off-by: Dylan Kiss (dyki) --- odoo/addons/base/tests/test_expression.py | 8 ++++---- odoo/osv/expression.py | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/odoo/addons/base/tests/test_expression.py b/odoo/addons/base/tests/test_expression.py index 388f248eba7..fd534039477 100644 --- a/odoo/addons/base/tests/test_expression.py +++ b/odoo/addons/base/tests/test_expression.py @@ -226,15 +226,15 @@ class TestExpression(SavepointCaseWithUserDemo): # same kind of search from another model Bank = self.env['res.partner.bank'].with_user(self.user_demo) - bank_top, _bank_med, bank_bot = Bank.create([ + bank_top, bank_med, bank_bot = Bank.create([ {'acc_number': '1', 'partner_id': top.id}, {'acc_number': '2', 'partner_id': med.id}, {'acc_number': '3', 'partner_id': bot.id}, ]) self.assertEqual(Bank.search([('partner_id', 'in', accessible.ids)]), bank_top + bank_bot) - self.assertEqual(Bank.search([('partner_id', 'child_of', top.ids)]), bank_top + bank_bot) - self.assertEqual(Bank.search([('partner_id', 'parent_of', bot.ids)]), bank_top + bank_bot) + self.assertEqual(Bank.search([('partner_id', 'child_of', top.ids)]), bank_top + bank_med + bank_bot) + self.assertEqual(Bank.search([('partner_id', 'parent_of', bot.ids)]), bank_top + bank_med + bank_bot) def test_10_eq_lt_gt_lte_gte(self): # test if less/greater than or equal operators work @@ -1251,7 +1251,7 @@ class TestQueries(TransactionCase): SELECT "res_partner_title"."id" FROM "res_partner_title" WHERE (COALESCE("res_partner_title"."name"->>'fr_FR', "res_partner_title"."name"->>'en_US') like %s) - ORDER BY COALESCE("res_partner_title"."name"->>'fr_FR', "res_partner_title"."name"->>'en_US') + ORDER BY COALESCE("res_partner_title"."name"->>'fr_FR', "res_partner_title"."name"->>'en_US') ''']): Model.search([('name', 'like', 'foo')]) diff --git a/odoo/osv/expression.py b/odoo/osv/expression.py index b588923c566..697dacd4f93 100644 --- a/odoo/osv/expression.py +++ b/odoo/osv/expression.py @@ -869,11 +869,11 @@ class expression(object): (when available), or as an expanded [(left,in,child_ids)] """ if not ids: return [FALSE_LEAF] - left_model = left_model.with_context(active_test=False) + left_model_sudo = left_model.sudo().with_context(active_test=False) if left_model._parent_store: domain = OR([ [('parent_path', '=like', rec.parent_path + '%')] - for rec in left_model.sudo().browse(ids) + for rec in left_model_sudo.browse(ids) ]) else: # recursively retrieve all children nodes with sudo(); the @@ -883,13 +883,13 @@ class expression(object): if (left_model._name != left_model._fields[parent_name].comodel_name): raise ValueError(f"Invalid parent field: {left_model._fields[parent_name]}") child_ids = set() - records = left_model.sudo().browse(ids) + records = left_model_sudo.browse(ids) while records: child_ids.update(records._ids) records = records.search([(parent_name, 'in', records.ids)], order='id') - records.browse(child_ids) domain = [('id', 'in', list(child_ids))] if prefix: - return [(left, 'in', left_model._search(domain))] + return [(left, 'in', left_model_sudo._search(domain))] return domain def parent_of_domain(left, ids, left_model, parent=None, prefix=''): @@ -899,11 +899,11 @@ class expression(object): ids = [id for id in ids if id] # ignore (left, 'parent_of', [False]) if not ids: return [FALSE_LEAF] - left_model = left_model.with_context(active_test=False) + left_model_sudo = left_model.sudo().with_context(active_test=False) if left_model._parent_store: parent_ids = [ int(label) - for rec in left_model.sudo().browse(ids) + for rec in left_model_sudo.browse(ids) for label in rec.parent_path.split('/')[:-1] ] domain = [('id', 'in', parent_ids)] @@ -913,13 +913,13 @@ class expression(object): # done by the rest of the domain parent_name = parent or left_model._parent_name parent_ids = set() - records = left_model.sudo().browse(ids) + records = left_model_sudo.browse(ids) while records: parent_ids.update(records._ids) records = records[parent_name] - records.browse(parent_ids) domain = [('id', 'in', list(parent_ids))] if prefix: - return [(left, 'in', left_model._search(domain))] + return [(left, 'in', left_model_sudo._search(domain))] return domain HIERARCHY_FUNCS = {'child_of': child_of_domain,