diff --git a/addons/web/static/src/model/relational_model/record.js b/addons/web/static/src/model/relational_model/record.js index 95291065f27..67541910f71 100644 --- a/addons/web/static/src/model/relational_model/record.js +++ b/addons/web/static/src/model/relational_model/record.js @@ -297,7 +297,15 @@ export class Record extends DataPoint { } _applyValues(values) { - Object.assign(this._values, this._parseServerValues(values)); + const newValues = this._parseServerValues(values); + Object.assign(this._values, newValues); + for (const fieldName in newValues) { + if (fieldName in this._changes) { + if (["one2many", "many2many"].includes(this.fields[fieldName].type)) { + this._changes[fieldName] = newValues[fieldName]; + } + } + } Object.assign(this.data, this._values, this._changes); this._setTextValues(Object.assign({}, values, this._changes)); this._setEvalContext(); diff --git a/addons/web/static/src/model/relational_model/static_list.js b/addons/web/static/src/model/relational_model/static_list.js index 748b3a2b9e5..4f35965d826 100644 --- a/addons/web/static/src/model/relational_model/static_list.js +++ b/addons/web/static/src/model/relational_model/static_list.js @@ -262,6 +262,11 @@ export class StaticList extends DataPoint { } } record._applyValues(data); + const commands = this._unknownRecordCommands[record.resId]; + delete this._unknownRecordCommands[record.resId]; + if (commands) { + this._applyCommands(commands); + } record._addSavePoint(); } else { // case 2: the record is a new record @@ -506,7 +511,20 @@ export class StaticList extends DataPoint { // records for the current page) this._unknownRecordCommands[command[1]].push(command); } else { - record._applyChanges(record._parseServerValues(command[2], record.data)); + const changes = {}; + for (const fieldName in command[2]) { + if (["one2many", "many2many"].includes(this.fields[fieldName].type)) { + if (record.activeFields[fieldName].invisible) { + if (!(command[1] in this._unknownRecordCommands)) { + this._unknownRecordCommands[command[1]] = []; + } + this._unknownRecordCommands[command[1]].push(command); + continue; + } + } + changes[fieldName] = command[2][fieldName]; + } + record._applyChanges(record._parseServerValues(changes, record.data)); } break; } diff --git a/addons/web/static/tests/views/fields/one2many_field_tests.js b/addons/web/static/tests/views/fields/one2many_field_tests.js index 99cd995deaf..e24ec35a9ec 100644 --- a/addons/web/static/tests/views/fields/one2many_field_tests.js +++ b/addons/web/static/tests/views/fields/one2many_field_tests.js @@ -13337,4 +13337,145 @@ QUnit.module("Fields", (hooks) => { ); } ); + + QUnit.test("forget command for nested x2manys in form, not in list", async function (assert) { + assert.expect(8); + + serverData.models.partner.records[0].p = [1, 2]; + serverData.models.partner.records[1].turtles = [2]; + serverData.models.partner.onchanges = { + int_field: function (obj) { + obj.p = [ + [ + 1, + 1, + { + foo: "new foo value (1)", + turtles: [ + [ + 1, + 2, + { + turtle_foo: "new turtle foo value (1)", + partner_ids: [[3, 4]], + }, + ], + ], + }, + ], + [ + 1, + 2, + { + foo: "new foo value (2)", + turtles: [ + [ + 1, + 2, + { + turtle_foo: "new turtle foo value (2)", + partner_ids: [[3, 2]], + }, + ], + ], + }, + ], + ]; + }, + }; + await makeView({ + type: "form", + resModel: "partner", + serverData, + arch: ` +
+ + + + + + + + + + + + + + + +
+ `, + mockRPC(route, args) { + if (args.method === "write") { + assert.deepEqual(args.args[1], { + int_field: 16, + p: [ + [ + 1, + 1, + { + foo: "new foo value (1)", + turtles: [ + [ + 1, + 2, + { + turtle_foo: "new turtle foo value (1)", + partner_ids: [[3, 4]], + }, + ], + ], + }, + ], + [ + 1, + 2, + { + foo: "new foo value (2)", + turtles: [ + [ + 1, + 2, + { + turtle_foo: "new turtle foo value (2)", + partner_ids: [[3, 2]], + }, + ], + ], + }, + ], + ], + }); + } + }, + resId: 1, + }); + + assert.strictEqual(target.querySelector("[name=int_field] input").value, "10"); + + // trigger the onchange + await editInput(target, "[name=int_field] input", "16"); + assert.strictEqual(target.querySelector("[name=foo]").innerText, "new foo value (1)"); + assert.strictEqual(target.querySelectorAll("[name=foo]")[1].innerText, "new foo value (2)"); + + // open the second x2many record + await click(target.querySelectorAll(".o_data_row")[1].querySelector("td")); + assert.containsOnce(target.querySelector(".o_dialog"), ".o_data_row"); + assert.strictEqual( + target.querySelector(".o_dialog .o_data_cell[name=turtle_foo]").innerText, + "new turtle foo value (2)" + ); + assert.containsOnce( + target.querySelector(".o_dialog .o_data_cell[name=partner_ids]"), + ".o_tag" + ); + assert.strictEqual( + target.querySelector(".o_dialog .o_data_cell[name=partner_ids] .o_tag").innerText, + "aaa" + ); + + await clickSave(target.querySelector(".o_dialog")); + await clickSave(target); + }); });