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 ce8d028d0af..d4e966440cb 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -3356,7 +3356,15 @@ var BasicModel = AbstractModel.extend({ var viewType = view ? view.type : fieldInfo.viewType; var toFetch = {}; - _.each(list.data, function (dataPoint) { + + // flattens the list.data ids in a grouped case + let dataPointIds = list.data; + for (let i = 0; i < list.groupedBy.length; i++) { + dataPointIds = dataPointIds.reduce((acc, groupId) => + acc.concat(this.localData[groupId].data), []); + } + + dataPointIds.forEach(function (dataPoint) { var record = self.localData[dataPoint]; if (typeof record.data[fieldName] === 'string'){ // in this case, the value is a local ID, which means that the diff --git a/addons/web/static/src/js/views/list/list_controller.js b/addons/web/static/src/js/views/list/list_controller.js index 611079ca3d5..fbd5e4a2af0 100644 --- a/addons/web/static/src/js/views/list/list_controller.js +++ b/addons/web/static/src/js/views/list/list_controller.js @@ -410,7 +410,7 @@ var ListController = BasicController.extend({ if (validRecordIds.length > 0) { const dialogOptions = { confirm_callback: () => { - this.model.saveRecords(recordId, validRecordIds, fieldName) + this.model.saveRecords(this.handle, recordId, validRecordIds, fieldName) .then(async () => { this._updateButtons('readonly'); const state = this.model.get(this.handle); diff --git a/addons/web/static/src/js/views/list/list_model.js b/addons/web/static/src/js/views/list/list_model.js index 65526346c8e..9ba0b473a5a 100644 --- a/addons/web/static/src/js/views/list/list_model.js +++ b/addons/web/static/src/js/views/list/list_model.js @@ -37,15 +37,16 @@ odoo.define('web.ListModel', function (require) { * For a list of records, performs a write with all changes and fetches * all data. * + * @param {string} listDatapointId id of the parent list * @param {string} referenceRecordId the record datapoint used to * generate the changes to apply to recordIds * @param {string[]} recordIds a list of record datapoint ids * @param {string} fieldName the field to write */ - saveRecords: function (referenceRecordId, recordIds, fieldName) { + saveRecords: function (listDatapointId, referenceRecordId, recordIds, fieldName) { var self = this; var referenceRecord = this.localData[referenceRecordId]; - var list = this.localData[referenceRecord.parentID]; + var list = this.localData[listDatapointId]; // generate all record values to ensure that we'll write something // (e.g. 2 records selected, edit a many2one in the first one, but // reset same value, we still want to save this value on the other diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js index 8a71bc38266..141a98e9a80 100644 --- a/addons/web/static/tests/views/list_tests.js +++ b/addons/web/static/tests/views/list_tests.js @@ -6042,6 +6042,38 @@ QUnit.module('Views', { list.destroy(); }); + QUnit.test('editable list view: m2m tags in grouped list', async function (assert) { + assert.expect(2); + + const list = await createView({ + arch: ` + + + + `, + data: this.data, + groupBy: ['bar'], + model: 'foo', + View: ListView, + }); + + // Opens first group + await testUtils.dom.click(list.$('.o_group_header:first')); + + assert.notEqual(list.$('.o_data_row:first').text(), list.$('.o_data_row:last').text(), + "First row and last row should have different values"); + + await testUtils.dom.click(list.$('thead .o_list_record_selector:first input')); + await testUtils.dom.click(list.$('.o_data_row:first .o_data_cell:eq(1)')); + await testUtils.dom.click(list.$('.o_selected_row .o_field_many2manytags .o_delete:first')); + await testUtils.dom.click($('.modal .btn-primary')); + + assert.strictEqual(list.$('.o_data_row:first').text(), list.$('.o_data_row:last').text(), + "All rows should have been correctly updated"); + + list.destroy(); + }); + QUnit.test('list grouped by date:month', async function (assert) { assert.expect(1);