[FIX] web: resequence x2many ordered by id but id not in view

Have a form view with an x2many list with handle field and a
default_order containing id (e.g. sequence,id), but id not being
defined in the list view. Before this commit, on an existing
record, it was impossible to resequence records of the x2many.

The reason is that after resequencing (drag&drop), the model tried
to sort the records, and since the "id" field wasn't in the view,
but was in the default_order, records were reloaded and the changes
(the new sequences) were lost.

The "id" case is special because the field doesn't need to be set
in the view, it is always known by the model. However, it is only
available in record.data if it is defined in the view. This commit
treats the "id" field individually in the sort algorithm.

Bug reported in the new relational model feedback pad.

closes odoo/odoo#135045

Signed-off-by: Francois Georis (fge) <fge@odoo.com>
This commit is contained in:
Aaron Bohy
2023-09-11 22:41:11 +00:00
parent 237748a980
commit 3faa9ab0a5
2 changed files with 52 additions and 2 deletions
@@ -19,8 +19,11 @@ function compareFieldValues(v1, v2, fieldType) {
function compareRecords(r1, r2, orderBy, fields) {
const { name, asc } = orderBy[0];
const v1 = asc ? r1.data[name] : r2.data[name];
const v2 = asc ? r2.data[name] : r1.data[name];
function getValue(record, fieldName) {
return fieldName === "id" ? record.resId : record.data[fieldName];
}
const v1 = asc ? getValue(r1, name) : getValue(r2, name);
const v2 = asc ? getValue(r2, name) : getValue(r1, name);
if (compareFieldValues(v1, v2, fields[name].type)) {
return -1;
}
@@ -783,6 +786,7 @@ export class StaticList extends DataPoint {
return true;
}
// record has already been loaded -> check if we already read all orderBy fields
fieldNames = fieldNames.filter((fieldName) => fieldName !== "id");
return intersection(fieldNames, record.fieldNames).length !== fieldNames.length;
});
}
@@ -14125,4 +14125,50 @@ QUnit.module("Fields", (hooks) => {
await click(target.querySelector(".o-autocomplete--dropdown-menu li a"));
}
);
QUnit.test("one2many with default_order on id, but id not in view", async function (assert) {
serverData.models.partner.records[0].turtles = [1, 2, 3];
await makeView({
type: "form",
resModel: "partner",
serverData,
arch: `
<form>
<field name="turtles">
<tree editable="top" default_order="turtle_int,id">
<field name="turtle_int" widget="handle"/>
<field name="turtle_foo"/>
</tree>
</field>
</form>`,
mockRPC(route, args) {
assert.step(args.method);
if (args.method === "web_save") {
assert.deepEqual(args.args[1].turtles, [
[1, 3, { turtle_int: 0 }],
[1, 1, { turtle_int: 1 }],
[1, 2, { turtle_int: 2 }],
]);
}
},
resId: 1,
});
assert.deepEqual(getNodesTextContent(target.querySelectorAll(".o_data_cell.o_list_char")), [
"yop",
"blip",
"kawa",
]);
// drag the third record to top of the list
await dragAndDrop("tbody tr:nth-child(3) .o_handle_cell", "tbody tr", "top");
await clickSave(target);
assert.deepEqual(getNodesTextContent(target.querySelectorAll(".o_data_cell.o_list_char")), [
"kawa",
"yop",
"blip",
]);
assert.verifySteps(["get_views", "web_read", "web_save"]);
});
});