From 3e443edcf92cce9d5f0a16ae3074873b3294996d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20K=C3=BChn?= Date: Tue, 5 Dec 2023 15:30:06 +0100 Subject: [PATCH] [FIX] mail: insert data in relational field Before this commit, when a record was identified by relational fields, we couldn't insert this record by passing data rather than the records. We should be able to insert records and data in the models, so passing data should be ok. This commit fixes this issue by backporting some code of improvements and fixes from master. Note that the internal code of model is written for retrocompatibility, so some added features like store.Model in diff is ok. Part-of: odoo/odoo#144999 --- addons/mail/static/src/core/common/record.js | 27 +++++++++++++++++-- addons/mail/static/tests/core/record_tests.js | 22 +++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/addons/mail/static/src/core/common/record.js b/addons/mail/static/src/core/common/record.js index f0e9948f65c..e29f14499b2 100644 --- a/addons/mail/static/src/core/common/record.js +++ b/addons/mail/static/src/core/common/record.js @@ -28,6 +28,7 @@ export function OR(...args) { } export function makeStore(env) { + let storeReady = false; const res = { // fake store for now, until it becomes a model /** @type {import("models").Store} */ @@ -115,7 +116,16 @@ export function makeStore(env) { /** @param {Record} receiver */ set(target, name, val, receiver) { return Record.MAKE_UPDATE(() => { - if (name === "Model" || !(name in target.Model._fields)) { + if (name === "Model") { + Reflect.set(target, name, val, receiver); + return true; + } + if (target instanceof BaseStore && storeReady && name in Models) { + // "store.Model =" is considered a Model.insert() + res.store[name].insert(val); + return true; + } + if (!(name in target.Model._fields)) { Reflect.set(target, name, val, receiver); return true; } @@ -388,6 +398,7 @@ export function makeStore(env) { Model.store = res.store; res.store[Model.name] = Model; } + storeReady = true; return res.store; } @@ -1311,8 +1322,20 @@ export class Record { const obj = new this.Class(); obj.Model = this; const ids = this._retrieveIdFromData(data); + for (const name in ids) { + if ( + ids[name] && + !Record.isRecord(ids[name]) && + !Record.isCommand(ids[name]) && + Record.isRelation(this._fields[name]) + ) { + // preinsert that record in relational field, + // as it is required to make current local id + ids[name] = this.store[this._fields[name].targetModel].preinsert(ids[name]); + } + } let record = Object.assign(obj, { - localId: this.localId(data), + localId: this.localId(ids), ...ids, }); Object.assign(record, { _store: this.store }); diff --git a/addons/mail/static/tests/core/record_tests.js b/addons/mail/static/tests/core/record_tests.js index 20cc42cff30..c8e3d09c6b1 100644 --- a/addons/mail/static/tests/core/record_tests.js +++ b/addons/mail/static/tests/core/record_tests.js @@ -278,3 +278,25 @@ QUnit.test("onAdd hook should see fully inserted data", async (assert) => { thread.members.add({ name: "John", type: "admin" }); assert.verifySteps(["Thread.onAdd::John.admin"]); }); + +QUnit.test("Can insert with relation as id, using relation as data object", async (assert) => { + (class User extends Record { + static id = "name"; + name; + settings = Record.one("Settings"); + }).register(); + (class Settings extends Record { + static id = "user"; + pushNotif; + user = Record.one("User", { inverse: "settings" }); + }).register(); + const store = await start(); + store.Settings.insert([ + { pushNotif: true, user: { name: "John" } }, + { pushNotif: false, user: { name: "Paul" } }, + ]); + assert.ok(store.User.get("John")); + assert.ok(store.User.get("John").settings.pushNotif); + assert.ok(store.User.get("Paul")); + assert.notOk(store.User.get("Paul").settings.pushNotif); +});