commit
65db48ac11
|
@ -189,6 +189,42 @@ class IrUiView(models.Model):
|
||||||
node.attrib[attribute_name] = new_value
|
node.attrib[attribute_name] = new_value
|
||||||
return source
|
return source
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def inheritance_handler_attributes_attrs_domain_add(self, source, specs):
|
||||||
|
"""Implement attrs_domain_add
|
||||||
|
|
||||||
|
<attribute name="$attribute" operation="attrs_domain_add"
|
||||||
|
key="$attrs_key" join_operator="OR">
|
||||||
|
$domain_to_add_to_attrs_key
|
||||||
|
</attribute>
|
||||||
|
"""
|
||||||
|
node = self.locate_node(source, specs)
|
||||||
|
for attribute_node in specs:
|
||||||
|
attribute_name = attribute_node.get("name")
|
||||||
|
key = attribute_node.get("key")
|
||||||
|
join_operator = attribute_node.get("join_operator") or "AND"
|
||||||
|
old_value = node.get(attribute_name) or ""
|
||||||
|
if old_value:
|
||||||
|
old_value = ast.literal_eval(
|
||||||
|
self.var2str_domain_text(old_value.strip())
|
||||||
|
)
|
||||||
|
old_domain_attrs = old_value.get(key)
|
||||||
|
new_domain = ast.literal_eval(
|
||||||
|
self.var2str_domain_text(attribute_node.text.strip())
|
||||||
|
)
|
||||||
|
if join_operator == "OR":
|
||||||
|
new_value = expression.OR([old_domain_attrs, new_domain])
|
||||||
|
else:
|
||||||
|
new_value = expression.AND([old_domain_attrs, new_domain])
|
||||||
|
old_value[key] = new_value
|
||||||
|
new_value = self.str2var_domain_text(str(old_value))
|
||||||
|
else:
|
||||||
|
# We must ensure that the domain definition has not line breaks because
|
||||||
|
# in update mode the domain cause an invalid syntax error
|
||||||
|
new_value = "{'%s': %s}" % (key, attribute_node.text.strip())
|
||||||
|
node.attrib[attribute_name] = new_value
|
||||||
|
return source
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def var2str_domain_text(self, domain_str):
|
def var2str_domain_text(self, domain_str):
|
||||||
"""Replaces var names with str names to allow eval without defined vars"""
|
"""Replaces var names with str names to allow eval without defined vars"""
|
||||||
|
|
|
@ -6,3 +6,4 @@
|
||||||
* Carlos Dauden
|
* Carlos Dauden
|
||||||
|
|
||||||
* Iván Todorovich <ivan.todorovich@camptocamp.com>
|
* Iván Todorovich <ivan.todorovich@camptocamp.com>
|
||||||
|
* Carlos Serra-Toro <carlos.serra@braintec.com>
|
||||||
|
|
|
@ -31,3 +31,12 @@ to refer to some xmlid, say ``%(xmlid)s``.
|
||||||
condition="$field_condition" join_operator="OR">
|
condition="$field_condition" join_operator="OR">
|
||||||
$domain_to_add
|
$domain_to_add
|
||||||
</attribute>
|
</attribute>
|
||||||
|
|
||||||
|
**Add domain with AND/OR join operator (AND if missed) for key in attrs**
|
||||||
|
|
||||||
|
.. code-block:: xml
|
||||||
|
|
||||||
|
<attribute name="$attribute" operation="attrs_domain_add"
|
||||||
|
key="$attrs_key" join_operator="OR">
|
||||||
|
$domain_to_add_to_attrs_key
|
||||||
|
</attribute>
|
||||||
|
|
|
@ -240,3 +240,70 @@ class TestBaseViewInheritanceExtension(TransactionCase):
|
||||||
)
|
)
|
||||||
with self.assertRaisesRegex(TypeError, "Attribute `domain` is not a dict"):
|
with self.assertRaisesRegex(TypeError, "Attribute `domain` is not a dict"):
|
||||||
self.env["ir.ui.view"].apply_inheritance_specs(source, specs)
|
self.env["ir.ui.view"].apply_inheritance_specs(source, specs)
|
||||||
|
|
||||||
|
def test_attrs_domain_add_join_operator_or(self):
|
||||||
|
"""Test that we can add an OR domain to an existing attrs key."""
|
||||||
|
self._test_attrs_domain_add(join_operator="OR")
|
||||||
|
|
||||||
|
def test_attrs_domain_add_join_operator_and(self):
|
||||||
|
"""Test that we can add an AND domain to an existing attrs key."""
|
||||||
|
self._test_attrs_domain_add(join_operator="AND")
|
||||||
|
|
||||||
|
def _test_attrs_domain_add(self, join_operator):
|
||||||
|
"""Test that we can add a domain to an existing attrs domain key."""
|
||||||
|
source = etree.fromstring(
|
||||||
|
"""
|
||||||
|
<form>
|
||||||
|
<field
|
||||||
|
name="ref"
|
||||||
|
attrs="{
|
||||||
|
'invisible': [('state', '=', 'draft')],
|
||||||
|
'required': [('state', '=', False)],
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
specs = etree.fromstring(
|
||||||
|
"""
|
||||||
|
<field name="ref" position="attributes">
|
||||||
|
<attribute name="attrs" operation="attrs_domain_add"
|
||||||
|
key="required" join_operator="%s">
|
||||||
|
[('state', '!=', 'draft')]
|
||||||
|
</attribute>
|
||||||
|
</field>
|
||||||
|
"""
|
||||||
|
% (join_operator,)
|
||||||
|
)
|
||||||
|
res = self.env["ir.ui.view"].apply_inheritance_specs(source, specs)
|
||||||
|
self.assertEqual(
|
||||||
|
res.xpath('//field[@name="ref"]')[0].attrib["attrs"],
|
||||||
|
"{'invisible': [('state', '=', 'draft')], "
|
||||||
|
"'required': ['%s', ('state', '=', False), ('state', '!=', 'draft')]}"
|
||||||
|
% ("|" if join_operator == "OR" else "&"),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_attrs_domain_add_no_attrs(self):
|
||||||
|
"""Test attrs_domain_add if there is no attrs: attrs is created."""
|
||||||
|
source = etree.fromstring(
|
||||||
|
"""
|
||||||
|
<form>
|
||||||
|
<field name="ref"/>
|
||||||
|
</form>
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
specs = etree.fromstring(
|
||||||
|
"""
|
||||||
|
<field name="ref" position="attributes">
|
||||||
|
<attribute name="attrs" operation="attrs_domain_add"
|
||||||
|
key="required" join_operator="OR">
|
||||||
|
[('state', '!=', 'draft')]
|
||||||
|
</attribute>
|
||||||
|
</field>
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
res = self.env["ir.ui.view"].apply_inheritance_specs(source, specs)
|
||||||
|
self.assertEqual(
|
||||||
|
res.xpath('//field[@name="ref"]')[0].attrib["attrs"],
|
||||||
|
"{'required': [('state', '!=', 'draft')]}",
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in New Issue