[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) <aab@odoo.com>
This commit is contained in:
FrancoisGe
2023-12-08 17:19:12 +00:00
parent 9f5609fd70
commit 5fb51a7825
3 changed files with 54 additions and 3 deletions
@@ -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]);
}
@@ -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]];
});
@@ -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: `
<form>
<field name="foo"/>
<field name="turtles">
<tree editable="top" limit="1">
<field name="turtle_int"/>
<field name="turtle_foo"/>
</tree>
</field>
</form>`,
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) {