diff --git a/odoo/addons/test_testing_utilities/ir.model.access.csv b/odoo/addons/test_testing_utilities/ir.model.access.csv index ced191d38e2..697a7334581 100644 --- a/odoo/addons/test_testing_utilities/ir.model.access.csv +++ b/odoo/addons/test_testing_utilities/ir.model.access.csv @@ -12,3 +12,5 @@ access_test_testing_utilities_parent,access_test_testing_utilities_parent,model_ access_test_testing_utilities_sub,access_test_testing_utilities_sub,model_test_testing_utilities_sub,,1,0,0,0 access_test_testing_utilities_sub2,access_test_testing_utilities_sub2,model_test_testing_utilities_sub2,,1,0,0,0 access_test_testing_utilities_sub3,access_test_testing_utilities_sub3,model_test_testing_utilities_sub3,,1,0,0,0 +access_test_testing_utilities_onchange_parent,access_test_testing_utilities_onchange_parent,model_test_testing_utilities_onchange_parent,,1,0,0,0 +access_test_testing_utilities_onchange_line,access_test_testing_utilities_onchange_line,model_test_testing_utilities_onchange_line,,1,0,0,0 diff --git a/odoo/addons/test_testing_utilities/menu.xml b/odoo/addons/test_testing_utilities/menu.xml index 0ca37f58658..fa5263efeca 100644 --- a/odoo/addons/test_testing_utilities/menu.xml +++ b/odoo/addons/test_testing_utilities/menu.xml @@ -104,4 +104,25 @@ + + + Dynamic Onchange Test View + test_testing_utilities.onchange_parent + +
+ + + + + + + + + + + + +
+
+
diff --git a/odoo/addons/test_testing_utilities/models.py b/odoo/addons/test_testing_utilities/models.py index 2bb6e5e5dd6..8d911e2135c 100644 --- a/odoo/addons/test_testing_utilities/models.py +++ b/odoo/addons/test_testing_utilities/models.py @@ -169,3 +169,26 @@ class O2MSub3(models.Model): def _compute_name(self): for r in self: r.name = str(r.v) + + +class O2MOnchangeParent(models.Model): + _name = 'test_testing_utilities.onchange_parent' + + line_ids = fields.One2many('test_testing_utilities.onchange_line', 'parent') + + @api.onchange('line_ids') + def _onchange_line_ids(self): + for line in self.line_ids.filtered(lambda l: l.flag): + self.env['test_testing_utilities.onchange_line'].new({'parent': self.id}) + + +class M2OOnchangeLine(models.Model): + _name = 'test_testing_utilities.onchange_line' + + parent = fields.Many2one('test_testing_utilities.onchange_parent') + dummy = fields.Float() + flag = fields.Boolean(store=False) + + @api.onchange('dummy') + def _onchange_flag(self): + self.flag = True 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 2806a972335..2232e872dc6 100644 --- a/odoo/addons/test_testing_utilities/tests/test_form_impl.py +++ b/odoo/addons/test_testing_utilities/tests/test_form_impl.py @@ -393,6 +393,17 @@ class TestO2M(TransactionCase): with self.assertRaises(AssertionError): f.subs.remove(index=0) + def test_o2m_dyn_onchange(self): + f = Form(self.env['test_testing_utilities.onchange_parent'], view='test_testing_utilities.m2o_onchange_view') + + with f.line_ids.new() as new_line: + new_line.dummy = 42 + self.assertTrue(new_line.flag) + + with f.line_ids.edit(index=0) as new_line: + self.assertTrue(new_line.flag) + + 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 7e974a96656..c26a8e5323a 100644 --- a/odoo/tests/common.py +++ b/odoo/tests/common.py @@ -955,7 +955,6 @@ class Form(object): # marks any onchange source as changed (default_get or explicit set) self._changed.update(fields) - result = self._model.onchange( self._onchange_values(), fields, @@ -1071,6 +1070,25 @@ class O2MForm(Form): # FIXME: should be called when performing on change => value needs to be serialised into parent every time? proxy._parent._perform_onchange([proxy._field]) + def _values_to_save(self): + """ Validates values and returns only fields modified since + load/save + """ + values = {} + for f in self._view['fields']: + v = self._values[f] + if self._get_modifier(f, 'required'): + assert v is not False, "{} is a required field".format(f) + + # skip unmodified fields + if f not in self._changed: + continue + # if self._get_modifier(f, 'readonly'): + # continue + # TODO: filter out (1, _, {}) from o2m values + values[f] = v + return values + class X2MProxy(object): _parent = None _field = None