[FIX] core: fix filtered_domain for hierarchical terms

The method filtered_domain() is broken for domains with hierarchical
terms ('child_of'/'parent_of').

To see *one* of the ways the implementation is broken, let `A` be a
model with `parent_id` pointing to `A`, and `a1` a record of model `A`
without parent (`a1.parent_id` is `False`), then this fails:

    assert a1 in a1.filtered_domain([("parent_id", "child_of", a1.id)])

The reason it fails is that on
https://github.com/odoo/odoo/blob/f5519586d214a9b34ad24683a7f97c47802a3bad/odoo/models.py#L5377-L5380
`data` is empty since `a1` has no parent, thus
https://github.com/odoo/odoo/blob/f5519586d214a9b34ad24683a7f97c47802a3bad/odoo/models.py#L5403-L5404
fails, therefore the result of `filtered_domain` is empty.

Note: the implementation of the hierarchical operators is full of quirks
that are hard to emulate otherwise than by reusing the original code.
As a consequence, the current implementation may be broken in more than
one way.

Let's see another way the implementation is broken: let `B` be a model
without a `parent_id` field and with a `friend_id` field pointing
to `B`, and let `b1` be a record of model `B`.  Then

    b1.filtered_domain([("friend_id", "child_of", b1.id)])

throws an exception of the form shown below:

    ValueError: Invalid field 'parent_id' in leaf "<osv.ExtendedLeaf: ('parent_id', 'child_of', 1) ...

Meanwhile the following code is still valid and returs b1:

    B.search([("friend_id", "child_of", b1.id)])

closes odoo/odoo#71237

X-original-commit: e7a5ba95d8b7df5bbf545ef8afe0a1f5d0f70272
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
This commit is contained in:
Alvaro Fuentes
2021-05-25 18:08:42 +00:00
committed by Raphael Collet
parent b1c90b96e1
commit 14036869c7
2 changed files with 14 additions and 3 deletions
+11
View File
@@ -115,6 +115,17 @@ class TestExpression(SavepointCaseWithUserDemo):
test('not ilike', 'B', ['0', 'a'])
test('not like', 'AB', ['0', 'a', 'b', 'a b'])
def test_09_hierarchy_filtered_domain(self):
Partner = self.env['res.partner']
p = Partner.create({'name': 'dummy'})
# hierarchy without parent
self.assertFalse(p.parent_id)
p2 = self._search(Partner, [('parent_id', 'child_of', p.id)], [('id', '=', p.id)])
self.assertEqual(p2, p)
p3 = self._search(Partner, [('parent_id', 'parent_of', p.id)], [('id', '=', p.id)])
self.assertEqual(p3, p)
def test_10_hierarchy_in_m2m(self):
Partner = self.env['res.partner']
Category = self.env['res.partner.category']
+3 -3
View File
@@ -5374,6 +5374,9 @@ Fields:
result.append(self.browse())
else:
(key, comparator, value) = d
if comparator in ('child_of', 'parent_of'):
result.append(self.search([('id', 'in', self.ids), d]))
continue
if key.endswith('.id'):
key = key[:-3]
if key == 'id':
@@ -5390,9 +5393,6 @@ Fields:
records_ids = OrderedSet()
for rec in self:
data = rec.mapped(key)
if comparator in ('child_of', 'parent_of'):
value = data.search([(data._parent_name, comparator, value)]).ids
comparator = 'in'
if isinstance(data, BaseModel):
v = value
if (isinstance(value, list) or isinstance(value, tuple)) and len(value):