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) {