diff --git a/odoo/addons/test_testing_utilities/menu.xml b/odoo/addons/test_testing_utilities/menu.xml index 60789cb490c..52bdeba2399 100644 --- a/odoo/addons/test_testing_utilities/menu.xml +++ b/odoo/addons/test_testing_utilities/menu.xml @@ -164,4 +164,19 @@ + + + Modifier check + test_testing_utilities.parent + + primary + + +
+ + + + +
+
diff --git a/odoo/addons/test_testing_utilities/tests/test_form_impl.py b/odoo/addons/test_testing_utilities/tests/test_form_impl.py index c0e5093fd3b..a7cd141696c 100644 --- a/odoo/addons/test_testing_utilities/tests/test_form_impl.py +++ b/odoo/addons/test_testing_utilities/tests/test_form_impl.py @@ -497,6 +497,17 @@ class TestO2M(TransactionCase): def test_o2m_self_recursive(self): Form(self.env['test_testing_utilities.recursive'], view='test_testing_utilities.o2m_recursive_relation_view') + def test_o2m_attrs(self): + Model = self.env['test_testing_utilities.parent'].with_context( + default_subs=[{ + 'value': 5, + }, { + 'value': 7, + }] + ) + f = Form(Model, view='test_testing_utilities.o2m_modifier') + f.save() + class TestEdition(TransactionCase): """ These use the context manager form as we don't need the record post-save (we already have it) and it's easier to see what bits act on diff --git a/odoo/tests/common.py b/odoo/tests/common.py index 59c4cd334b5..9350ff49327 100644 --- a/odoo/tests/common.py +++ b/odoo/tests/common.py @@ -1537,8 +1537,9 @@ class Form(object): values = {} fields = self._view['fields'] for f in fields: + descr = fields[f] v = self._values[f] - if self._get_modifier(f, 'required') and not fields[f]['type'] == 'boolean': + if self._get_modifier(f, 'required') and not descr['type'] == 'boolean': assert v is not False, "{} is a required field".format(f) # skip unmodified fields @@ -1550,8 +1551,8 @@ class Form(object): if not node.get('force_save'): continue - if fields[f]['type'] == 'one2many': - view = fields[f]['views']['edition'] + if descr['type'] == 'one2many': + view = descr['views']['edition'] modifiers = view['modifiers'] oldvals = v v = [] @@ -1565,7 +1566,21 @@ class Form(object): for (c, rid, vs) in oldvals: if c in (0, 1): items = list(getattr(vs, 'changed_items', vs.items)()) - # FIXME: should be more extensive processing of o2m defaults + fields_ = view['fields'] + missing = fields_.keys() - vs.keys() + if missing: + Model = self._env[descr['relation']] + if c == 0: + vs.update(dict.fromkeys(missing, False)) + vs.update( + (k, _cleanup_from_default(fields_[k], v)) + for k, v in Model.default_get(list(missing)).items() + ) + else: + vs.update(record_to_values( + {k: v for k, v in fields_.items() if k not in vs}, + Model.browse(rid) + )) vs.setdefault('id', False) vs['•parent•'] = self._values vs = { @@ -1971,6 +1986,23 @@ def record_to_values(fields, record): r[f] = v return r +def _cleanup_from_default(type_, value): + if not value: + if type_ == 'many2many': + return [(6, False, [])] + elif type_ == 'one2many': + return [] + elif type_ in ('integer', 'float'): + return 0 + return value + + if type_ == 'one2many': + return [c for c in value if c[0] != 6] + elif type_ == 'datetime' and isinstance(value, datetime): + return odoo.fields.Datetime.to_string(value) + elif type_ == 'date' and isinstance(value, date): + return odoo.fields.Date.to_string(value) + def _get_node(view, f, *arg): """ Find etree node for the field ``f`` in the view's arch """