diff --git a/openerp/addons/test_new_api/ir.model.access.csv b/openerp/addons/test_new_api/ir.model.access.csv index 757e2050363..c05160dde5e 100644 --- a/openerp/addons/test_new_api/ir.model.access.csv +++ b/openerp/addons/test_new_api/ir.model.access.csv @@ -2,6 +2,8 @@ access_category,test_new_api_category,test_new_api.model_test_new_api_category,,1,1,1,1 access_discussion,test_new_api_discussion,test_new_api.model_test_new_api_discussion,,1,1,1,1 access_message,test_new_api_message,test_new_api.model_test_new_api_message,,1,1,1,1 +access_multi,test_new_api_multi,test_new_api.model_test_new_api_multi,,1,1,1,1 +access_multi_line,test_new_api_multi_line,test_new_api.model_test_new_api_multi_line,,1,1,1,1 access_mixed,test_new_api_mixed,test_new_api.model_test_new_api_mixed,,1,1,1,1 access_test_function_noinfiniterecursion,access_test_function_noinfiniterecursion,model_test_old_api_function_noinfiniterecursion,,1,1,1,1 access_test_function_counter,access_test_function_counter,model_test_old_api_function_counter,,1,1,1,1 diff --git a/openerp/addons/test_new_api/models.py b/openerp/addons/test_new_api/models.py index 00e2681f324..50993d24277 100644 --- a/openerp/addons/test_new_api/models.py +++ b/openerp/addons/test_new_api/models.py @@ -222,6 +222,35 @@ class Message(models.Model): return [('author.partner_id', operator, value)] +class Multi(models.Model): + """ Model for testing multiple onchange methods in cascade that modify a + one2many field several times. + """ + _name = 'test_new_api.multi' + + name = fields.Char(related='partner.name', readonly=True) + partner = fields.Many2one('res.partner') + lines = fields.One2many('test_new_api.multi.line', 'multi') + + @api.onchange('name') + def _onchange_name(self): + for line in self.lines: + line.name = self.name + + @api.onchange('partner') + def _onchange_partner(self): + for line in self.lines: + line.partner = self.partner + + +class MultiLine(models.Model): + _name = 'test_new_api.multi.line' + + multi = fields.Many2one('test_new_api.multi', ondelete='cascade') + name = fields.Char() + partner = fields.Many2one('res.partner') + + class MixedModel(models.Model): _name = 'test_new_api.mixed' diff --git a/openerp/addons/test_new_api/tests/test_onchange.py b/openerp/addons/test_new_api/tests/test_onchange.py index 3d0745a5f8b..062cf6c4532 100644 --- a/openerp/addons/test_new_api/tests/test_onchange.py +++ b/openerp/addons/test_new_api/tests/test_onchange.py @@ -149,6 +149,45 @@ class TestOnChange(common.TransactionCase): }), ]) + def test_onchange_one2many_multi(self): + """ test the effect of multiple onchange methods on one2many fields """ + partner = self.env.ref('base.res_partner_1') + multi = self.env['test_new_api.multi'].create({'partner': partner.id}) + line = multi.lines.create({'multi': multi.id}) + + field_onchange = multi._onchange_spec() + self.assertEqual(field_onchange, { + 'name': '1', + 'partner': '1', + 'lines': None, + 'lines.name': None, + 'lines.partner': None, + }) + + values = multi._convert_to_write({key: multi[key] for key in ('name', 'partner', 'lines')}) + self.assertEqual(values, { + 'name': partner.name, + 'partner': partner.id, + 'lines': [(6, 0, [line.id])], + }) + + # modify 'partner' + # -> set 'partner' on all lines + # -> recompute 'name' + # -> set 'name' on all lines + partner = self.env.ref('base.res_partner_2') + values['partner'] = partner.id + values['lines'].append((0, 0, {'name': False, 'partner': False})) + self.env.invalidate_all() + result = multi.onchange(values, 'partner', field_onchange) + self.assertEqual(result['value'], { + 'name': partner.name, + 'lines': [ + (1, line.id, {'name': partner.name, 'partner': partner.id}), + (0, 0, {'name': partner.name, 'partner': partner.id}), + ], + }) + def test_onchange_specific(self): """ test the effect of field-specific onchange method """ discussion = self.env.ref('test_new_api.discussion_0') diff --git a/openerp/addons/test_new_api/views.xml b/openerp/addons/test_new_api/views.xml index 2e1290f5a09..cc2b363f753 100644 --- a/openerp/addons/test_new_api/views.xml +++ b/openerp/addons/test_new_api/views.xml @@ -20,6 +20,13 @@ + + Multi + test_new_api.multi + tree,form + + + @@ -125,5 +132,39 @@ + + + + multi tree view + test_new_api.multi + + + + + + + + + + multi form view + test_new_api.multi + +
+ + + + + + +
+
+
diff --git a/openerp/models.py b/openerp/models.py index 93642ba49b5..ca47981b806 100644 --- a/openerp/models.py +++ b/openerp/models.py @@ -5944,6 +5944,21 @@ class BaseModel(object): result = {'value': {}} + # special case for merging commands from *2many fields + # TODO: do not forward-port this in 9.0 + def merge_commands(commands1, commands2): + # retrieve updates from commands1 + updates = {cmd[1]: cmd[2] for cmd in commands1 if cmd[0] == 1} + # enrich commands2 with updates from commands1 + commands = [] + for cmd in commands2: + if cmd[0] == 1 and cmd[1] in updates: + cmd = (1, cmd[1], dict(updates[cmd[1]], **cmd[2])) + elif cmd[0] == 4 and cmd[1] in updates: + cmd = (1, cmd[1], updates[cmd[1]]) + commands.append(cmd) + return commands + # process names in order (or the keys of values if no name given) while todo: name = todo.pop(0) @@ -5966,9 +5981,10 @@ class BaseModel(object): newval = record[name] if field.type in ('one2many', 'many2many'): if newval != oldval or newval._is_dirty(): - # put new value in result - result['value'][name] = field.convert_to_write( - newval, record._origin, subfields.get(name), + # merge new value into result + result['value'][name] = merge_commands( + result['value'].get(name, []), + field.convert_to_write(newval, record._origin, subfields.get(name)), ) todo.append(name) else: