[FIX] web: forget command for nested x2many in form, not in list
Have a form view with an x2many field A displayed as a non editable list view. In A's form view, there's an x2many field B, which isn't in the list. B is itself displayed in the dialog form view as a list, which contains an x2many fields C displayed as many2many_tags. A contains a record. For this record, B contains also a record, which contains two tags for C. Have an onchange on the main record which triggers an update command for the record in A, such that the command also updates the record in B, which deletes (or forgets), i.e. commands 2 or 3, a tag C. Before this commit, if the user opened the x2many record of A after the onchange, it didn't displayed the remaining tag in C. The reason is that we received commands to remove the tag before we actually fetched them (as we don't need them for the list of A). The tags were then fetched when we opened the record in a dialog, but we didn't correctly merge the values read from the server with the commands we received earlier. With this commit, we properly store the commands and apply them after reading the values. Part of task~3179751 Part-of: odoo/odoo#114024
This commit is contained in:
@@ -297,7 +297,15 @@ export class Record extends DataPoint {
|
||||
}
|
||||
|
||||
_applyValues(values) {
|
||||
Object.assign(this._values, this._parseServerValues(values));
|
||||
const newValues = this._parseServerValues(values);
|
||||
Object.assign(this._values, newValues);
|
||||
for (const fieldName in newValues) {
|
||||
if (fieldName in this._changes) {
|
||||
if (["one2many", "many2many"].includes(this.fields[fieldName].type)) {
|
||||
this._changes[fieldName] = newValues[fieldName];
|
||||
}
|
||||
}
|
||||
}
|
||||
Object.assign(this.data, this._values, this._changes);
|
||||
this._setTextValues(Object.assign({}, values, this._changes));
|
||||
this._setEvalContext();
|
||||
|
||||
@@ -262,6 +262,11 @@ export class StaticList extends DataPoint {
|
||||
}
|
||||
}
|
||||
record._applyValues(data);
|
||||
const commands = this._unknownRecordCommands[record.resId];
|
||||
delete this._unknownRecordCommands[record.resId];
|
||||
if (commands) {
|
||||
this._applyCommands(commands);
|
||||
}
|
||||
record._addSavePoint();
|
||||
} else {
|
||||
// case 2: the record is a new record
|
||||
@@ -506,7 +511,20 @@ export class StaticList extends DataPoint {
|
||||
// records for the current page)
|
||||
this._unknownRecordCommands[command[1]].push(command);
|
||||
} else {
|
||||
record._applyChanges(record._parseServerValues(command[2], record.data));
|
||||
const changes = {};
|
||||
for (const fieldName in command[2]) {
|
||||
if (["one2many", "many2many"].includes(this.fields[fieldName].type)) {
|
||||
if (record.activeFields[fieldName].invisible) {
|
||||
if (!(command[1] in this._unknownRecordCommands)) {
|
||||
this._unknownRecordCommands[command[1]] = [];
|
||||
}
|
||||
this._unknownRecordCommands[command[1]].push(command);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
changes[fieldName] = command[2][fieldName];
|
||||
}
|
||||
record._applyChanges(record._parseServerValues(changes, record.data));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -13337,4 +13337,145 @@ QUnit.module("Fields", (hooks) => {
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test("forget command for nested x2manys in form, not in list", async function (assert) {
|
||||
assert.expect(8);
|
||||
|
||||
serverData.models.partner.records[0].p = [1, 2];
|
||||
serverData.models.partner.records[1].turtles = [2];
|
||||
serverData.models.partner.onchanges = {
|
||||
int_field: function (obj) {
|
||||
obj.p = [
|
||||
[
|
||||
1,
|
||||
1,
|
||||
{
|
||||
foo: "new foo value (1)",
|
||||
turtles: [
|
||||
[
|
||||
1,
|
||||
2,
|
||||
{
|
||||
turtle_foo: "new turtle foo value (1)",
|
||||
partner_ids: [[3, 4]],
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
[
|
||||
1,
|
||||
2,
|
||||
{
|
||||
foo: "new foo value (2)",
|
||||
turtles: [
|
||||
[
|
||||
1,
|
||||
2,
|
||||
{
|
||||
turtle_foo: "new turtle foo value (2)",
|
||||
partner_ids: [[3, 2]],
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
];
|
||||
},
|
||||
};
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
serverData,
|
||||
arch: `
|
||||
<form>
|
||||
<group>
|
||||
<field name="int_field"/>
|
||||
<field name="p">
|
||||
<tree>
|
||||
<field name="foo"/>
|
||||
</tree>
|
||||
<form>
|
||||
<field name="turtles">
|
||||
<tree editable="bottom">
|
||||
<field name="turtle_foo"/>
|
||||
<field name="partner_ids" widget="many2many_tags"/>
|
||||
</tree>
|
||||
</field>
|
||||
</form>
|
||||
</field>
|
||||
</group>
|
||||
</form>`,
|
||||
mockRPC(route, args) {
|
||||
if (args.method === "write") {
|
||||
assert.deepEqual(args.args[1], {
|
||||
int_field: 16,
|
||||
p: [
|
||||
[
|
||||
1,
|
||||
1,
|
||||
{
|
||||
foo: "new foo value (1)",
|
||||
turtles: [
|
||||
[
|
||||
1,
|
||||
2,
|
||||
{
|
||||
turtle_foo: "new turtle foo value (1)",
|
||||
partner_ids: [[3, 4]],
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
[
|
||||
1,
|
||||
2,
|
||||
{
|
||||
foo: "new foo value (2)",
|
||||
turtles: [
|
||||
[
|
||||
1,
|
||||
2,
|
||||
{
|
||||
turtle_foo: "new turtle foo value (2)",
|
||||
partner_ids: [[3, 2]],
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
});
|
||||
}
|
||||
},
|
||||
resId: 1,
|
||||
});
|
||||
|
||||
assert.strictEqual(target.querySelector("[name=int_field] input").value, "10");
|
||||
|
||||
// trigger the onchange
|
||||
await editInput(target, "[name=int_field] input", "16");
|
||||
assert.strictEqual(target.querySelector("[name=foo]").innerText, "new foo value (1)");
|
||||
assert.strictEqual(target.querySelectorAll("[name=foo]")[1].innerText, "new foo value (2)");
|
||||
|
||||
// open the second x2many record
|
||||
await click(target.querySelectorAll(".o_data_row")[1].querySelector("td"));
|
||||
assert.containsOnce(target.querySelector(".o_dialog"), ".o_data_row");
|
||||
assert.strictEqual(
|
||||
target.querySelector(".o_dialog .o_data_cell[name=turtle_foo]").innerText,
|
||||
"new turtle foo value (2)"
|
||||
);
|
||||
assert.containsOnce(
|
||||
target.querySelector(".o_dialog .o_data_cell[name=partner_ids]"),
|
||||
".o_tag"
|
||||
);
|
||||
assert.strictEqual(
|
||||
target.querySelector(".o_dialog .o_data_cell[name=partner_ids] .o_tag").innerText,
|
||||
"aaa"
|
||||
);
|
||||
|
||||
await clickSave(target.querySelector(".o_dialog"));
|
||||
await clickSave(target);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user