[FIX] web: legacy Many2ManyTags in list view: add/remove records

Have a list view (new RelationalModel inside a WOWL list view) that has
a legacy many2many tags field in its arch.

Try to add or remove some records from that many2many.

Before this commit, there was a crash, because the legacy field wrapper
doesn't use the model the right way for that case.

After this commit, there is no crash.

closes odoo/odoo#99431

Signed-off-by: Georis François (fge) <fge@odoo.com>
This commit is contained in:
Lucas Perais
2022-09-02 10:16:01 +02:00
parent 128b961bdd
commit f4a8d5bf9b
3 changed files with 70 additions and 6 deletions
@@ -336,6 +336,19 @@ function registerField(name, LegacyFieldWidget) {
update(fieldName, value) {
if (fieldName === this.props.name) {
const record = this.props.record;
const fieldType = record.fields[fieldName].type;
if (["one2many", "many2many"].includes(fieldType) && !record.model.__bm__) {
const staticList = this.props.value;
switch (value.operation) {
case "REPLACE_WITH": {
return staticList.replaceWith(value.resIds);
}
case "FORGET": {
return staticList.delete(value.ids);
}
}
}
return this.props.update(value);
} else {
return this.props.record.update({ [fieldName]: value });
@@ -2719,13 +2719,25 @@ export class StaticList extends DataPoint {
/**
* @param {RecordId} recordId
*/
async delete(recordId) {
const record = this._cache[recordId];
if (record.isVirtual) {
delete this._cache[recordId];
async delete(recordIds) {
if (!Array.isArray(recordIds)) {
recordIds = [recordIds];
}
const id = record.resId || record.virtualId;
this.applyCommand(x2ManyCommands.delete(id));
const ids = [];
for (const recordId of recordIds) {
const record = this._cache[recordId];
if (record.isVirtual) {
delete this._cache[recordId];
}
const id = record.resId || record.virtualId;
ids.push(id);
}
if (this.field.type === "many2many") {
const nextIds = this.records.filter((rec) => !ids.includes(rec.resId || rec.virtualId));
return this.replaceWith(nextIds);
}
const commands = ids.map((id) => x2ManyCommands.delete(id));
this.applyCommands(commands);
await this._loadRecords();
this.records = this._getRecords();
this.onChanges();
@@ -20,6 +20,9 @@ import { session } from "@web/session";
import { companyService } from "@web/webclient/company_service";
import { registry } from "@web/core/registry";
import legacyFieldRegistry from "web.field_registry";
import { FieldMany2ManyTags } from "web.relational_fields";
let target;
let serverData;
@@ -2052,4 +2055,40 @@ QUnit.module("Fields", (hooks) => {
);
}
);
QUnit.test("many2many legacy field in list add a record", async (assert) => {
const myM2M = FieldMany2ManyTags.extend({});
legacyFieldRegistry.add("many2many_tags_legacy", myM2M);
await makeView({
type: "list",
resModel: "partner",
serverData,
arch: `
<tree editable="top">
<field name="timmy" widget="many2many_tags_legacy"/>
</tree>`,
mockRPC(route, args) {
if (args.method === "write") {
assert.step(`write: ${JSON.stringify(args.args[1])}`);
}
},
});
assert.containsNone(target, ".o_badge_text");
await click(target.querySelectorAll(".o_data_cell")[0]);
await click(target, ".o_legacy_field_widget input");
await click(document.querySelectorAll(".ui-autocomplete .dropdown-item")[0]);
assert.strictEqual(target.querySelector(".o_badge_text").textContent, "gold");
await click(target);
assert.verifySteps([`write: {"timmy":[[6,false,[12]]]}`]);
await click(target.querySelectorAll(".o_data_cell")[0]);
await click(target.querySelector(".badge .o_delete"));
await click(target);
assert.containsNone(target, ".o_badge_text");
assert.verifySteps([`write: {"timmy":[[6,false,[]]]}`]);
delete legacyFieldRegistry.map["many2many_tags_legacy"];
});
});