diff options
| author | Aaron Bohy <aab@odoo.com> | 2021-04-13 10:18:45 +0000 |
|---|---|---|
| committer | Aaron Bohy <aab@odoo.com> | 2021-04-13 11:45:24 +0000 |
| commit | 3f54ca3e29d1537f66c6a3b56494dc065d9230e9 (patch) | |
| tree | c5fd722854100737502e4c28e6d2a85ed9a1af65 | |
| parent | bce6966b386c0e17840e1ea377faaab559e86108 (diff) | |
[FIX] web: onchange: send correct nested x2manys values
Commit [1] recently fixed an issue with nested x2many fields and
onchanges: in some cases, all field values weren't sent to the
server as they should.
However, there is a small issue with this fix. We didn't correctly
apply the default value to option `changesOnly`: when not given,
it was considered false, whereas in this particular function it
should have been true.
It caused an issue in the following scenario:
Have a form view with an x2many field (say A) displayed as a list.
In the list, there is another x2many field (say B), and (whatever
its type) a field C with an onchange. When the user changes C, the
onchange is performed, and we send to the server the value of all
fields. In particular, in the row, we send the value for the
many2one field pointing to the main record (the inverse field of
the x2many relation). The value for that field is basically the
whole record, containing itself field A. For field A, the value is
a list of commands, and for the updated record, it is a command 1.
Before this commit, in the values sent for this command, field B
was the empty array, even if it wasn't empty.
This issue was reproducible in account.move, on an existing record
having already a line in invoice_line_ids (this is field A). In
that line, tax_ids (this is field B) must have a tax which is
included in the price. When changing the quantity of the product,
the subtotal wasn't correctly computed.
[1] https://github.com/odoo/odoo/commit/a8b43d02066b2299ac2f4b88056c37725e9ce6cd
opw~2489755
closes odoo/odoo#69167
Signed-off-by: Lucas Perais (lpe) <lpe@odoo.com>
| -rw-r--r-- | addons/web/static/src/js/views/basic/basic_model.js | 7 | ||||
| -rw-r--r-- | addons/web/static/tests/fields/relational_fields/field_one2many_tests.js | 50 |
2 files changed, 53 insertions, 4 deletions
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 c51f512b966..a8538b70d98 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -3148,14 +3148,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) { @@ -3172,7 +3173,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 ea47207044c..e496b3674b7 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 @@ -1629,7 +1629,6 @@ QUnit.module('fields', {}, function () { '</form>' + '</field>' + '</form>', - debug: 1, }); @@ -4667,6 +4666,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: ` + <form> + <field name="foo"/> + <field name="p"> + <tree editable="top"> + <field name="display_name"/> + <field name="turtles" widget="many2many_tags"/> + </tree> + </field> + </form>`, + 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); |
