Files
odoo_source/addons/resource/models/utils.py
T
Hugo Carlier (Huca) 20b8635737 [REF] resource, project: replace the function remove_domain_leaf
The function remove_domain_leaf is currently used for project burdown
chart. Due to an increasing need of such a function in multiple modules
for various functional cases, it has been decided to:
- Move this function in 'resource' that is imported in all the modules
where this function is needed.
- Implement extensive unit test to ensure that it address corner cases.
- Refactor the function to address the corner cases it was not
addressing until now.

The refactored function 'filter_domain_leaf' is used to transform a
given domain to a new domain using only the leaves that verify a given
check (more precisely, the leaves whose first element verify this check). To perform this transformation, the leaves that do not verify
this check are considered as undetermined. All the logical operators
dealing with undetermined leaves are ignored, which means:
- AND(leaf, ?) = leaf
- OR(leaf, ?) = leaf
- AND(? , ?) = ?
- OR(?, ?) = ?
- NOT(?) = ?
If the result of the operation is undetermined, it is returned as an
empty domain ([]).

closes odoo/odoo#105470

Related: odoo/enterprise#33657
Related: odoo/upgrade#4221
Signed-off-by: Xavier Bol (xbo) <xbo@odoo.com>
2023-01-16 15:43:01 +01:00

44 lines
2.0 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.osv.expression import normalize_domain, NOT_OPERATOR, DOMAIN_OPERATORS
def filter_domain_leaf(domain, leaf_check):
"""
filter_domain_lead only keep the leaves of a domain that verify a given check. Logical operators that involves
a leaf that is undetermined (because it does not pass the check) are ignored.
each operator is a logic gate:
- '&' and '|' take two entries and can be ignored if one of them (or the two of them) is undetermined
-'!' takes one entry and can be ignored if this entry is undetermined
params:
- domain: the domain that needs to be filtered
- leaf_check: the function that the field used in the leaf needs to verify to keep the leaf
returns: The filtered version of the domain
"""
def _filter_domain_leaf_recursive(domain, leaf_check, operator=False):
"""
return domain, rest_domain -> rest_domain should be empty if the operation is finished
"""
if len(domain) == 0:
return ([], [])
if not operator:
first_elem = domain[0]
if first_elem not in DOMAIN_OPERATORS: #End of a current leaf
return ([], domain[1:]) if not leaf_check(first_elem[0]) else ([first_elem], domain[1:])
operator = first_elem
domain = domain[1:]
leaf_1, rest_domain = _filter_domain_leaf_recursive(domain, leaf_check)
if operator == NOT_OPERATOR:
return ([operator, *leaf_1], rest_domain) if leaf_1 else ([], rest_domain)
leaf_2, rest_domain = _filter_domain_leaf_recursive(rest_domain, leaf_check)
if leaf_1 == [] or leaf_2 == []:
return ((leaf_1 or leaf_2), rest_domain)
return ([operator, *leaf_1, *leaf_2], rest_domain)
domain = normalize_domain(domain)
operator = domain[0] if len(domain) > 1 else False
domain = domain[1:] if len(domain) > 1 else domain
return _filter_domain_leaf_recursive(domain, leaf_check, operator=operator)[0]