[FIX] web: nested x2manys with context referencing parent

Before this commit, it crashed if an x2many field inside another
x2many field had a context with a key referencing the parent
record:
```xml
<form>
  <field name="foo"/>
  <field name="outer_x2many">
    <tree></tree>
    <form>
      <field name="inner_x2many" context="{'key': parent.foo}">
        <tree></tree>
      </field>
    </form>
  </field>
</form>
```

The crash occured because we tried to evaluate the context of the
static list representing inner_x2many before setting the parent
key on the eval context.

Part of task~3179751

Part-of: odoo/odoo#114024
This commit is contained in:
Aaron Bohy
2023-07-24 20:17:52 +02:00
parent f6a2086375
commit 575bb235c7
2 changed files with 55 additions and 12 deletions
@@ -37,6 +37,16 @@ export class Record extends DataPoint {
this._unsetRequiredFields = markRaw(new Set());
this._closeInvalidFieldsNotification = () => {};
const parentRecord = this._parentRecord;
if (parentRecord) {
this.evalContext = {
get parent() {
return parentRecord.evalContext;
},
};
} else {
this.evalContext = {};
}
const missingFields = this.fieldNames.filter((fieldName) => !(fieldName in data));
data = { ...this._getDefaultValues(missingFields), ...data };
const vals = this._parseServerValues(data);
@@ -55,23 +65,12 @@ export class Record extends DataPoint {
// expose string values (false fallbacks on the empty string) in this.data.
this._textValues = markRaw({});
this._setTextValues(data);
this._setEvalContext();
this._savePoint = markRaw({
dirty: false,
changes: { ...this._changes },
textValues: { ...this._textValues },
});
const parentRecord = this._parentRecord;
if (parentRecord) {
this.evalContext = {
get parent() {
return parentRecord.evalContext;
},
};
} else {
this.evalContext = {};
}
this._setEvalContext();
}
// -------------------------------------------------------------------------
@@ -7661,6 +7661,50 @@ QUnit.module("Fields", (hooks) => {
await click(target.querySelector(".o_field_x2many_list_row_add a"));
});
QUnit.test("nested x2manys with context referencing parent record", async function (assert) {
assert.expect(3);
serverData.models.partner.records[0].p = [2];
let onchangeNb = 0;
await makeView({
type: "form",
resModel: "partner",
serverData,
arch: `
<form>
<field name="foo"/>
<field name="p">
<tree>
<field name="display_name"/>
</tree>
<form>
<field name="p" context="{'parent_foo': parent.foo}">
<tree>
<field name="display_name"/>
</tree>
</field>
</form>
</field>
</form>`,
mockRPC(route, args) {
if (args.method === "onchange2") {
onchangeNb++;
if (onchangeNb === 1) {
assert.deepEqual(args.args[3].p.context, { parent_foo: "yop" });
} else {
assert.strictEqual(args.kwargs.context.parent_foo, "yop");
}
}
},
resId: 1,
});
await click(target.querySelector(".o_field_x2many_list_row_add a"));
assert.containsOnce(target, ".o_dialog");
await click(target.querySelector(".o_dialog .o_field_x2many_list_row_add a"));
});
QUnit.test("resetting invisible one2manys", async function (assert) {
serverData.models.partner.records[0].turtles = [];
serverData.models.partner.onchanges.foo = function (obj) {