diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js index 39c66abbfab..5a9b847bb8e 100644 --- a/addons/web/static/src/js/fields/relational_fields.js +++ b/addons/web/static/src/js/fields/relational_fields.js @@ -2826,6 +2826,9 @@ var FieldMany2ManyCheckBoxes = AbstractField.extend({ specialData: "_fetchSpecialRelation", supportedFieldTypes: ['many2many'], isQuickEditable: true, + // set an arbitrary high limit to ensure that all data returned by the server + // are processed by the BasicModel (otherwise it would be 40) + limit: 100000, init: function () { this._super.apply(this, arguments); this.m2mValues = this.record.specialData[this.name]; diff --git a/addons/web/static/tests/fields/relational_fields_tests.js b/addons/web/static/tests/fields/relational_fields_tests.js index e0327cfeb6d..880a6e95409 100644 --- a/addons/web/static/tests/fields/relational_fields_tests.js +++ b/addons/web/static/tests/fields/relational_fields_tests.js @@ -2534,6 +2534,56 @@ QUnit.module('relational_fields', { form.destroy(); }); + QUnit.test('widget many2many_checkboxes with 40+ values', async function (assert) { + // 40 is the default limit for x2many fields. However, the many2many_checkboxes is a + // special field that fetches its data through the fetchSpecialData mechanism, and it + // uses the name_search server-side limit of 100. This test comes with a fix for a bug + // that occurred when the user (un)selected a checkbox that wasn't in the 40 first checkboxes, + // because the piece of data corresponding to that checkbox hadn't been processed by the + // BasicModel, whereas the code handling the change assumed it had. + assert.expect(3); + + const records = []; + for (let id = 1; id <= 90; id++) { + records.push({ + id, + display_name: `type ${id}`, + color: id % 7, + }); + } + this.data.partner_type.records = records; + this.data.partner.records[0].timmy = records.map((r) => r.id); + + const form = await createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '
', + res_id: 1, + async mockRPC(route, args) { + if (args.method === 'write') { + const expectedIds = records.map((r) => r.id); + expectedIds.pop(); + assert.deepEqual(args.args[1].timmy, [[6, false, expectedIds]]); + } + return this._super(...arguments); + }, + viewOptions: { + mode: 'edit', + }, + }); + + assert.containsN(form, '.o_field_widget[name=timmy] input[type=checkbox]:checked', 90); + + // toggle the last value + await testUtils.dom.click(form.$('.o_field_widget[name=timmy] input[type=checkbox]:last')); + assert.notOk(form.$('.o_field_widget[name=timmy] input[type=checkbox]:last').is(':checked')); + + await testUtils.form.clickSave(form); + + form.destroy(); + }); + QUnit.module('FieldMany2ManyBinaryMultiFiles'); QUnit.test('widget many2many_binary', async function (assert) {