From 4a7d93d08975d17241eff80b9843c4ab39ca7d7d Mon Sep 17 00:00:00 2001 From: "Maruan Aguerdouh (magm)" Date: Wed, 20 Sep 2023 15:19:12 +0000 Subject: [PATCH] [FIX] web: incomplete record reload in x2many form view context Steps to reproduce: - Install eLearning - Create or go to an existing course. - Add Content - Fill the name and use Save & Close - Click again in the same content we have just created. - Click on website preview. Issue: Saving a record from a form view that is part of an x2many field would only reload the fields present in the list view. This led to incomplete data being loaded into the model. Solution: - Pass the `viewType` option to `_fetchRecord` to ensure that the record is reloaded in the context of the form view, thereby including all fields. - Add `viewType` to the `saveOptions` in the `basic_relational_model.js` to ensure the correct view context is used during the save operation. This ensures that all fields are reloaded into the model, providing a complete view of the data. opw-3330010 closes odoo/odoo#139968 X-original-commit: 3cec34e659222073b0fba36983eaec9f7bf5514f Signed-off-by: Aaron Bohy (aab) --- .../src/model/relational_model/static_list.js | 15 +++- .../tests/views/form/form_view_tests.js | 87 +++++++++++++++++++ 2 files changed, 98 insertions(+), 4 deletions(-) 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 7f6cd9aa019..ebb58329c71 100644 --- a/addons/web/static/src/model/relational_model/static_list.js +++ b/addons/web/static/src/model/relational_model/static_list.js @@ -797,7 +797,7 @@ export class StaticList extends DataPoint { } _getCommands({ withReadonly } = {}) { - const { CREATE, UPDATE } = x2ManyCommands; + const { CREATE, UPDATE, LINK } = x2ManyCommands; const commands = []; for (const command of this._commands) { if (command[0] === UPDATE && command[1] in this._unknownRecordCommands) { @@ -814,9 +814,16 @@ export class StaticList extends DataPoint { } } else if (command[0] === CREATE || command[0] === UPDATE) { const record = this._cache[command[1]]; - const values = record._getChanges(record._changes, { withReadonly }); - if (command[0] === CREATE || Object.keys(values).length) { - commands.push([command[0], command[1], values]); + if (command[0] === CREATE && record.resId) { + // we created a new record, but it has already been saved (e.g. because we clicked + // on a view button in the x2many dialog), so replace the CREATE command by a + // LINK + commands.push([LINK, record.resId]); + } else { + const values = record._getChanges(record._changes, { withReadonly }); + if (command[0] === CREATE || Object.keys(values).length) { + commands.push([command[0], command[1], values]); + } } } else { commands.push(command); diff --git a/addons/web/static/tests/views/form/form_view_tests.js b/addons/web/static/tests/views/form/form_view_tests.js index ff4c8bc5ae8..e64314b22dd 100644 --- a/addons/web/static/tests/views/form/form_view_tests.js +++ b/addons/web/static/tests/views/form/form_view_tests.js @@ -127,6 +127,7 @@ QUnit.module("Views", (hooks) => { ["partner", "Partner"], ], }, + user_id: { string: "User", type: "many2one", relation: "user" }, }, records: [ { @@ -14299,4 +14300,90 @@ QUnit.module("Views", (hooks) => { await editInput(target, "[name='int_field'] input", "42"); assert.verifySteps(["get_special_data 9", "get_special_data 42"]); }); + + QUnit.test( + "x2many field in form dialog view is correctly saved when using a view button", + async function (assert) { + serverData.actions = { + 1: { + id: 1, + name: "Partner", + res_model: "partner", + type: "ir.actions.act_window", + views: [[false, "form"]], + view_mode: "form", + res_id: 6, + }, + }; + + serverData.views = { + "partner,false,form": ` +
+ + `, + "partner,false,search": ``, + "user,false,form": ` +
+ + + + + +
+
+ + + + + `, + "user,false,search": ``, + }; + + const webClient = await createWebClient({ + serverData, + mockRPC: (route, { method, args, model }) => { + if (method === "web_save") { + if (model === "partner") { + assert.step(`web_save_partner`); + assert.deepEqual(args[1], { + display_name: "new value", + }); + } else if (model === "user") { + assert.step(`web_save_user`); + assert.deepEqual( + args[1], + { + partner_ids: [[4, 6]], + }, + "Should be a LINK_TO command" + ); + } + } + }, + }); + await doAction(webClient, { + res_id: 19, + type: "ir.actions.act_window", + res_model: "user", + view_mode: "form", + views: [[false, "form"]], + }); + + assert.containsNone(target, ".o_data_cell"); + await click(target.querySelector(".o_field_x2many_list_row_add a")); + await editInput(target, ".o_field_widget[name=display_name] input", "new value"); + await click(target, ".modal-dialog .o_form_button_save"); + await click(target.querySelector(".o_data_cell")); + await click(target, "[name='1']"); + assert.verifySteps( + ["web_save_partner", "web_save_user"], + "Verify that the x2many record is saved (partner is saved, then user is saved with a link to" + ); + assert.strictEqual( + target.querySelector(".o_field_widget[name=display_name] input").value, + "new value" + ); + } + ); });