From 5fb51a78251405f7e299b73d9181772bfdce5e71 Mon Sep 17 00:00:00 2001 From: FrancoisGe Date: Fri, 8 Dec 2023 14:08:21 +0100 Subject: [PATCH] [FIX] web: don't save readonly field in unknownCommand Before this commit, during an onchange, when we received an update command for an x2many referring to an unknown record on the front end (does not have a Datapoint Record) during the save, we sent all the contents of these commands without removing the readonly fields. In this commit, we're going to filter all the readonly fields according to the backend (fields). We're not taking modifiers into account because the command refers to an unknown record, so we don't have the data to evaluate modifiers correctly. How to reproduce: - Go to a form view with an x2many field - Edit a field that causes an onchange - The onchange command returns an "update" command for an x2many record which is not on the actual page (unknown record) with a value which is readonly according to the backend - Click on the Save button Before this commit: The "update" command doesn't contain the readonly field After this commit: The "update" command contains the readonly field Task ID: 3607260 closes odoo/odoo#145556 Signed-off-by: Aaron Bohy (aab) --- .../src/model/relational_model/static_list.js | 3 +- .../src/model/relational_model/utils.js | 12 +++++- .../views/fields/one2many_field_tests.js | 42 +++++++++++++++++++ 3 files changed, 54 insertions(+), 3 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 ebb58329c71..4ba40616026 100644 --- a/addons/web/static/src/model/relational_model/static_list.js +++ b/addons/web/static/src/model/relational_model/static_list.js @@ -808,7 +808,8 @@ export class StaticList extends DataPoint { const values = fromUnityToServerValues( uCommand[2], this.fields, - this.activeFields + this.activeFields, + { withReadonly } ); commands.push([uCommand[0], uCommand[1], values]); } diff --git a/addons/web/static/src/model/relational_model/utils.js b/addons/web/static/src/model/relational_model/utils.js index 2e7608b48b4..7928e8cc799 100644 --- a/addons/web/static/src/model/relational_model/utils.js +++ b/addons/web/static/src/model/relational_model/utils.js @@ -560,11 +560,15 @@ function getValueFromGroupData(field, rawValue, range) { * expected by the server for a write. * For instance, for a many2one: { id: 3, display_name: "Marc" } => 3. */ -export function fromUnityToServerValues(values, fields, activeFields) { +export function fromUnityToServerValues(values, fields, activeFields, { withReadonly } = {}) { const { CREATE, UPDATE } = x2ManyCommands; const serverValues = {}; for (const fieldName in values) { let value = values[fieldName]; + const field = fields[fieldName]; + if (!withReadonly && field.readonly) { + continue; + } switch (fields[fieldName].type) { case "one2many": case "many2many": @@ -572,7 +576,11 @@ export function fromUnityToServerValues(values, fields, activeFields) { if (c[0] === CREATE || c[0] === UPDATE) { const _fields = activeFields[fieldName].related.fields; const _activeFields = activeFields[fieldName].related.activeFields; - return [c[0], c[1], fromUnityToServerValues(c[2], _fields, _activeFields)]; + return [ + c[0], + c[1], + fromUnityToServerValues(c[2], _fields, _activeFields, { withReadonly }), + ]; } return [c[0], c[1]]; }); 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 9ab9c75b3e2..d12e1563777 100644 --- a/addons/web/static/tests/views/fields/one2many_field_tests.js +++ b/addons/web/static/tests/views/fields/one2many_field_tests.js @@ -9676,6 +9676,48 @@ QUnit.module("Fields", (hooks) => { ]); }); + QUnit.test( + "one2many with several pages, onchange return command update on unknown record (readonly field)", + async function (assert) { + serverData.models.turtle.fields.turtle_int.readonly = true; + serverData.models.partner.onchanges = { + foo: function (obj) { + obj.turtles = [[1, 3, { turtle_int: 57, turtle_foo: "yop" }]]; + }, + }; + + await makeView({ + type: "form", + resModel: "partner", + serverData, + arch: ` +
+ + + + + + + + `, + mockRPC(route, { args, method }) { + if (method === "web_save") { + assert.deepEqual(args[0], [1]); + // for unknownCommand, we should not send readonly fields + assert.deepEqual(args[1], { + foo: "blip", + turtles: [[1, 3, { turtle_foo: "yop" }]], + }); + } + }, + resId: 1, + }); + + await editInput(target, ".o_field_widget[name=foo] input", "blip"); + await clickSave(target); + } + ); + QUnit.test( "new record, with one2many with more default values than limit", async function (assert) {