diff --git a/base_view_inheritance_extension/models/ir_ui_view.py b/base_view_inheritance_extension/models/ir_ui_view.py index e6ee174f2..3a45dcc3b 100644 --- a/base_view_inheritance_extension/models/ir_ui_view.py +++ b/base_view_inheritance_extension/models/ir_ui_view.py @@ -1,14 +1,17 @@ # Copyright 2016 Therp BV # Copyright 2018 Tecnativa - Sergio Teruel # Copyright 2021 Camptocamp SA (https://www.camptocamp.com). +# Copyright 2023 Tecnativa - Carlos Dauden # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). import ast +import re import astor from lxml import etree from odoo import api, models +from odoo.osv import expression def ast_dict_update(source, update): @@ -128,3 +131,77 @@ class IrUiView(models.Model): pretty_source=lambda s: "".join(s).strip(), ) return source + + @api.model + def inheritance_handler_attributes_text_add(self, source, specs): + """Implement + <$node position="attributes"> + + $text_before {old_value} $text_after + + """ + node = self.locate_node(source, specs) + for attribute_node in specs: + attribute_name = attribute_node.get("name") + old_value = node.get(attribute_name) or "" + node.attrib[attribute_name] = attribute_node.text.format( + old_value=old_value + ) + return source + + @api.model + def inheritance_handler_attributes_domain_add(self, source, specs): + """Implement + <$node position="attributes"> + + $domain_to_add + + """ + node = self.locate_node(source, specs) + for attribute_node in specs: + attribute_name = attribute_node.get("name") + condition = attribute_node.get("condition") + join_operator = attribute_node.get("join_operator") or "AND" + old_value = node.get(attribute_name) or "" + if old_value: + old_domain = ast.literal_eval( + self.var2str_domain_text(old_value.strip()) + ) + new_domain = ast.literal_eval( + self.var2str_domain_text(attribute_node.text.strip()) + ) + if join_operator == "OR": + new_value = str(expression.OR([old_domain, new_domain])) + else: + new_value = str(expression.AND([old_domain, new_domain])) + new_value = self.str2var_domain_text(new_value) + else: + new_value = attribute_node.text + if condition: + new_value = "{condition} and {new_value} or {old_value}".format( + condition=condition, + new_value=new_value, + old_value=old_value, + ) + node.attrib[attribute_name] = new_value + return source + + @api.model + def var2str_domain_text(self, domain_str): + """Replaces var names with str names to allow eval without defined vars""" + # Replace fields in 2 steps because 1 step returns "parent_sufix"."var_sufix" + regex_parent = re.compile(r"parent\.(\b\w+\b)") + domain_str = re.sub( + regex_parent, r"'parent.\1_is_a_var_to_replace'", domain_str + ) + regex = re.compile(r"(? * Ronald Portier -* Sergio Teruel +* `Tecnativa `_: + + * Sergio Teruel + * Carlos Dauden + * Iván Todorovich diff --git a/base_view_inheritance_extension/readme/USAGE.rst b/base_view_inheritance_extension/readme/USAGE.rst index 66ae50d75..7acccf59c 100644 --- a/base_view_inheritance_extension/readme/USAGE.rst +++ b/base_view_inheritance_extension/readme/USAGE.rst @@ -14,3 +14,20 @@ Note that views are subject to evaluation of xmlids anyways, so if you need to refer to some xmlid, say ``%(xmlid)s``. + +**Add text after and/or before than original** + +.. code-block:: xml + + + $text_before {old_value} $text_after + + +**Add domain with AND/OR join operator (AND if missed) allowing conditional changes** + +.. code-block:: xml + + + $domain_to_add +