diff --git a/addons/web/static/src/js/views/basic/basic_model.js b/addons/web/static/src/js/views/basic/basic_model.js index 79e19818e92..0330fccef81 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -3241,14 +3241,15 @@ var BasicModel = AbstractModel.extend({ options = options || {}; var viewType = options.viewType || record.viewType; var changes; - if ('changesOnly' in options && !options.changesOnly) { + const changesOnly = 'changesOnly' in options ? !!options.changesOnly : true; + if (!changesOnly) { changes = _.extend({}, record.data, record._changes); } else { changes = _.extend({}, record._changes); } var withReadonly = options.withReadonly || false; var commands = this._generateX2ManyCommands(record, { - changesOnly: 'changesOnly' in options ? options.changesOnly : true, + changesOnly: changesOnly, withReadonly: withReadonly, }); for (var fieldName in record.fields) { @@ -3265,7 +3266,7 @@ var BasicModel = AbstractModel.extend({ var type = record.fields[fieldName].type; var value; if (type === 'one2many' || type === 'many2many') { - if (!options.changesOnly || (commands[fieldName] && commands[fieldName].length)) { // replace localId by commands + if (!changesOnly || (commands[fieldName] && commands[fieldName].length)) { // replace localId by commands changes[fieldName] = commands[fieldName]; } else { // no command -> no change for that field delete changes[fieldName]; diff --git a/addons/web/static/tests/fields/relational_fields/field_one2many_tests.js b/addons/web/static/tests/fields/relational_fields/field_one2many_tests.js index e50c8dff3de..2278825ea0a 100644 --- a/addons/web/static/tests/fields/relational_fields/field_one2many_tests.js +++ b/addons/web/static/tests/fields/relational_fields/field_one2many_tests.js @@ -1633,7 +1633,6 @@ QUnit.module('fields', {}, function () { '' + '' + '', - debug: 1, }); @@ -4668,6 +4667,55 @@ QUnit.module('fields', {}, function () { form.destroy(); }); + QUnit.test('parent data is properly sent on an onchange rpc (existing x2many record)', async function (assert) { + assert.expect(4); + + this.data.partner.onchanges = { + display_name: function () {}, + }; + this.data.partner.records[0].p = [1]; + this.data.partner.records[0].turtles = [2]; + const form = await createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: ` +
+ + + + + + + + `, + res_id: 1, + mockRPC(route, args) { + if (args.method === 'onchange') { + const fieldValues = args.args[1]; + assert.strictEqual(fieldValues.trululu.foo, "yop"); + // we only send fields that changed inside the reverse many2one + assert.deepEqual(fieldValues.trululu.p, [ + [1, 1, { display_name: 'new val' }], + ]); + } + return this._super(...arguments); + }, + viewOptions: { + mode: 'edit', + }, + }); + + assert.containsOnce(form, '.o_data_row'); + + await testUtils.dom.click(form.$('.o_data_row .o_data_cell:first')); + + assert.containsOnce(form, '.o_data_row.o_selected_row'); + await testUtils.fields.editInput(form.$('.o_selected_row .o_field_widget[name=display_name]'), "new val"); + + form.destroy(); + }); + QUnit.test('parent data is properly sent on an onchange rpc, new record', async function (assert) { assert.expect(4);