diff --git a/addons/hr_timesheet/static/tests/timesheet_graph_tests.js b/addons/hr_timesheet/static/tests/timesheet_graph_tests.js
index 56a3dcf9275..972294c7715 100644
--- a/addons/hr_timesheet/static/tests/timesheet_graph_tests.js
+++ b/addons/hr_timesheet/static/tests/timesheet_graph_tests.js
@@ -36,7 +36,7 @@ QUnit.module('Views', function (hooks) {
}
}
setupControlPanelServiceRegistry();
- serviceRegistry.add("company", companyService);
+ serviceRegistry.add("company", companyService, { force: true });
serviceRegistry.add("dialog", dialogService);
});
diff --git a/addons/web/static/src/views/relational_model.js b/addons/web/static/src/views/relational_model.js
index de72a14aad5..11cd7912650 100644
--- a/addons/web/static/src/views/relational_model.js
+++ b/addons/web/static/src/views/relational_model.js
@@ -457,6 +457,10 @@ export class Record extends DataPoint {
return {
// ...
...this.dataContext,
+ active_id: this.resId || false,
+ active_ids: this.resId ? [this.resId] : [],
+ active_model: this.resModel,
+ current_company_id: this.model.company.currentCompany.id,
};
}
@@ -3199,12 +3203,13 @@ export class StaticList extends DataPoint {
StaticList.DEFAULT_LIMIT = 40;
export class RelationalModel extends Model {
- setup(params, { action, dialog, notification, rpc, user, view }) {
+ setup(params, { action, dialog, notification, rpc, user, view, company }) {
this.action = action;
this.dialogService = dialog;
this.notificationService = notification;
this.rpc = rpc;
this.user = user;
+ this.company = company;
this.viewService = view;
this.orm = new RequestBatcherORM(rpc, user);
this.keepLast = new KeepLast();
@@ -3342,7 +3347,7 @@ export class RelationalModel extends Model {
}
}
-RelationalModel.services = ["action", "dialog", "notification", "rpc", "user", "view"];
+RelationalModel.services = ["action", "dialog", "notification", "rpc", "user", "view", "company"];
RelationalModel.Record = Record;
RelationalModel.Group = Group;
RelationalModel.DynamicRecordList = DynamicRecordList;
diff --git a/addons/web/static/tests/core/debug/debug_manager_tests.js b/addons/web/static/tests/core/debug/debug_manager_tests.js
index bba7f1992d2..096aa97f924 100644
--- a/addons/web/static/tests/core/debug/debug_manager_tests.js
+++ b/addons/web/static/tests/core/debug/debug_manager_tests.js
@@ -12,6 +12,7 @@ import { ActionDialog } from "@web/webclient/actions/action_dialog";
import { hotkeyService } from "@web/core/hotkeys/hotkey_service";
import { makeTestEnv, utils } from "../../helpers/mock_env";
import {
+ fakeCompanyService,
fakeCommandService,
makeFakeDialogService,
makeFakeLocalizationService,
@@ -296,6 +297,7 @@ QUnit.module("DebugMenu", (hooks) => {
}
};
prepareRegistriesWithCleanup();
+ registry.category("services").add("company", fakeCompanyService);
patchWithCleanup(odoo, {
debug: true,
@@ -387,6 +389,7 @@ QUnit.module("DebugMenu", (hooks) => {
}
};
prepareRegistriesWithCleanup();
+ registry.category("services").add("company", fakeCompanyService);
patchWithCleanup(odoo, {
debug: true,
diff --git a/addons/web/static/tests/helpers/mock_services.js b/addons/web/static/tests/helpers/mock_services.js
index c2f8aec04ce..1fa499ecc6c 100644
--- a/addons/web/static/tests/helpers/mock_services.js
+++ b/addons/web/static/tests/helpers/mock_services.js
@@ -10,7 +10,6 @@ import { effectService } from "@web/core/effects/effect_service";
import { objectToUrlEncodedString } from "@web/core/utils/urls";
import { registerCleanup } from "./cleanup";
import { patchWithCleanup } from "./utils";
-import { companyService } from "@web/webclient/company_service";
import { uiService } from "@web/core/ui/ui_service";
import { ConnectionAbortedError } from "../../src/core/network/rpc_service";
@@ -70,7 +69,8 @@ export function makeFakeRPCService(mockRPC) {
.then(resolve)
.catch(reject);
});
- rpcProm.abort = () => rejectFn(new ConnectionAbortedError("XmlHttpRequestError abort"));
+ rpcProm.abort = () =>
+ rejectFn(new ConnectionAbortedError("XmlHttpRequestError abort"));
return rpcProm;
};
},
@@ -79,7 +79,7 @@ export function makeFakeRPCService(mockRPC) {
}
export function makeMockXHR(response, sendCb, def) {
- let MockXHR = function () {
+ const MockXHR = function () {
return {
_loadListener: null,
url: "",
@@ -269,6 +269,17 @@ export function makeFakeUserService(hasGroup = () => false) {
};
}
+export const fakeCompanyService = {
+ start() {
+ return {
+ availableCompanies: {},
+ allowedCompanyIds: [],
+ currentCompany: {},
+ setCompanies: () => {},
+ };
+ },
+};
+
export function makeFakeHTTPService(getResponse, postResponse) {
getResponse =
getResponse ||
@@ -295,7 +306,7 @@ export function makeFakeHTTPService(getResponse, postResponse) {
}
export const mocks = {
- company: () => companyService,
+ company: () => fakeCompanyService,
command: () => fakeCommandService,
cookie: () => fakeCookieService,
effect: () => effectService, // BOI The real service ? Is this what we want ?
diff --git a/addons/web/static/tests/views/fields/many2many_field_tests.js b/addons/web/static/tests/views/fields/many2many_field_tests.js
index 8f56f04a870..90f7a1b18d1 100644
--- a/addons/web/static/tests/views/fields/many2many_field_tests.js
+++ b/addons/web/static/tests/views/fields/many2many_field_tests.js
@@ -16,6 +16,9 @@ import {
import { editSearch, validateSearch } from "@web/../tests/search/helpers";
import { AutoComplete } from "@web/core/autocomplete/autocomplete";
import { Many2XAutocomplete } from "@web/views/fields/relational_utils";
+import { session } from "@web/session";
+import { companyService } from "@web/webclient/company_service";
+import { registry } from "@web/core/registry";
let target;
let serverData;
@@ -1869,4 +1872,184 @@ QUnit.module("Fields", (hooks) => {
assert.containsOnce(target, ".modal");
assert.strictEqual(target.querySelector(".modal-title").textContent, "Search: pokemon");
});
+
+ QUnit.test("many2many basic keys in field evalcontext -- in list", async (assert) => {
+ assert.expect(6);
+ serverData.models.partner_type.fields.partner_id = {
+ string: "Partners",
+ type: "many2one",
+ relation: "partner",
+ };
+ serverData.views = {
+ "partner_type,false,form": `
`,
+ };
+
+ patchWithCleanup(session, {
+ user_companies: {
+ allowed_companies: {
+ 3: { id: 3, name: "Hermit", sequence: 1 },
+ 2: { id: 2, name: "Herman's", sequence: 2 },
+ 1: { id: 1, name: "Heroes TM", sequence: 3 },
+ },
+ current_company: 3,
+ },
+ });
+
+ registry.category("services").add("company", companyService, { force: true });
+
+ patchWithCleanup(AutoComplete, {
+ timeout: 0,
+ });
+
+ await makeView({
+ type: "list",
+ resModel: "partner",
+ serverData,
+ arch: `
+
+
+ `,
+ mockRPC(route, args) {
+ if (args.method === "onchange") {
+ assert.strictEqual(args.kwargs.context.default_partner_id, 1);
+ assert.strictEqual(args.kwargs.context.model, "partner");
+ assert.deepEqual(args.kwargs.context.ids, [1]);
+ assert.strictEqual(args.kwargs.context.company_id, 3);
+ }
+ },
+ });
+
+ await click(target.querySelector(".o_data_cell"));
+ await editInput(target, ".o_field_many2many_selection input", "indianapolis");
+ await clickOpenedDropdownItem(target, "timmy", "Create and edit...");
+ assert.containsOnce(target, ".modal .o_field_many2one");
+ assert.strictEqual(
+ target.querySelector(".modal .o_field_many2one input").value,
+ "first record"
+ );
+ });
+
+ QUnit.test("many2many basic keys in field evalcontext -- in form", async (assert) => {
+ assert.expect(6);
+ serverData.models.partner_type.fields.partner_id = {
+ string: "Partners",
+ type: "many2one",
+ relation: "partner",
+ };
+ serverData.views = {
+ "partner_type,false,form": ``,
+ };
+
+ patchWithCleanup(session, {
+ user_companies: {
+ allowed_companies: {
+ 3: { id: 3, name: "Hermit", sequence: 1 },
+ 2: { id: 2, name: "Herman's", sequence: 2 },
+ 1: { id: 1, name: "Heroes TM", sequence: 3 },
+ },
+ current_company: 3,
+ },
+ });
+
+ registry.category("services").add("company", companyService, { force: true });
+
+ patchWithCleanup(AutoComplete, {
+ timeout: 0,
+ });
+
+ await makeView({
+ type: "form",
+ resId: 1,
+ resModel: "partner",
+ serverData,
+ arch: `
+ `,
+ mockRPC(route, args) {
+ if (args.method === "onchange") {
+ assert.strictEqual(args.kwargs.context.default_partner_id, 1);
+ assert.strictEqual(args.kwargs.context.model, "partner");
+ assert.deepEqual(args.kwargs.context.ids, [1]);
+ assert.strictEqual(args.kwargs.context.company_id, 3);
+ }
+ },
+ });
+
+ await clickEdit(target);
+ await editInput(target, ".o_field_many2many_selection input", "indianapolis");
+ await clickOpenedDropdownItem(target, "timmy", "Create and edit...");
+ assert.containsOnce(target, ".modal .o_field_many2one");
+ assert.strictEqual(
+ target.querySelector(".modal .o_field_many2one input").value,
+ "first record"
+ );
+ });
+
+ QUnit.test(
+ "many2many basic keys in field evalcontext -- in a x2many in form",
+ async (assert) => {
+ assert.expect(6);
+ serverData.models.partner_type.fields.partner_id = {
+ string: "Partners",
+ type: "many2one",
+ relation: "partner",
+ };
+ serverData.views = {
+ "partner_type,false,form": ``,
+ };
+
+ const rec = serverData.models.partner.records.find(({ id }) => id === 2);
+ rec.p = [1];
+
+ patchWithCleanup(session, {
+ user_companies: {
+ allowed_companies: {
+ 3: { id: 3, name: "Hermit", sequence: 1 },
+ 2: { id: 2, name: "Herman's", sequence: 2 },
+ 1: { id: 1, name: "Heroes TM", sequence: 3 },
+ },
+ current_company: 3,
+ },
+ });
+ registry.category("services").add("company", companyService, { force: true });
+
+ patchWithCleanup(AutoComplete, {
+ timeout: 0,
+ });
+
+ await makeView({
+ type: "form",
+ resId: 2,
+ resModel: "partner",
+ serverData,
+ arch: `
+ `,
+ mockRPC(route, args) {
+ if (args.method === "onchange") {
+ assert.strictEqual(args.kwargs.context.default_partner_id, 1);
+ assert.strictEqual(args.kwargs.context.model, "partner");
+ assert.deepEqual(args.kwargs.context.ids, [1]);
+ assert.strictEqual(args.kwargs.context.company_id, 3);
+ }
+ },
+ });
+
+ await clickEdit(target);
+ await click(target, ".o_data_cell");
+ await editInput(target, ".o_field_many2many_selection input", "indianapolis");
+ await clickOpenedDropdownItem(target, "timmy", "Create and edit...");
+ assert.containsOnce(target, ".modal .o_field_many2one");
+ assert.strictEqual(
+ target.querySelector(".modal .o_field_many2one input").value,
+ "first record"
+ );
+ }
+ );
});
diff --git a/addons/web/static/tests/views/helpers.js b/addons/web/static/tests/views/helpers.js
index a78f7b1d8b0..4a7efbcf4f6 100644
--- a/addons/web/static/tests/views/helpers.js
+++ b/addons/web/static/tests/views/helpers.js
@@ -11,6 +11,7 @@ import {
} from "../search/helpers";
import { addLegacyMockEnvironment } from "../webclient/helpers";
import {
+ fakeCompanyService,
makeFakeLocalizationService,
makeFakeRouterService,
makeFakeUserService,
@@ -105,4 +106,5 @@ export function setupViewRegistries() {
serviceRegistry.add("localization", makeFakeLocalizationService()), { force: true };
serviceRegistry.add("dialog", dialogService), { force: true };
serviceRegistry.add("popover", popoverService), { force: true };
+ serviceRegistry.add("company", fakeCompanyService);
}
diff --git a/addons/web/static/tests/views/view_dialogs/export_data_dialog_tests.js b/addons/web/static/tests/views/view_dialogs/export_data_dialog_tests.js
index 8f00b3c45fa..836d605b3be 100644
--- a/addons/web/static/tests/views/view_dialogs/export_data_dialog_tests.js
+++ b/addons/web/static/tests/views/view_dialogs/export_data_dialog_tests.js
@@ -12,10 +12,8 @@ import {
triggerEvent,
mockTimeout,
} from "@web/../tests/helpers/utils";
-import { makeView } from "@web/../tests/views/helpers";
-import { dialogService } from "@web/core/dialog/dialog_service";
+import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
import { registry } from "@web/core/registry";
-import { setupControlPanelServiceRegistry } from "@web/../tests/search/helpers";
import { makeFakeUserService } from "../../helpers/mock_services";
const serviceRegistry = registry.category("services");
@@ -97,13 +95,12 @@ QUnit.module("ViewDialogs", (hooks) => {
},
};
target = getFixture();
- setupControlPanelServiceRegistry();
+ setupViewRegistries();
function hasGroup(group) {
return group === "base.group_allow_export";
}
serviceRegistry.add("user", makeFakeUserService(hasGroup), { force: true });
- serviceRegistry.add("dialog", dialogService);
fetchedFields = {
root: [
@@ -595,7 +592,7 @@ QUnit.module("ViewDialogs", (hooks) => {
QUnit.test("Export dialog: display on small screen after resize", async function (assert) {
const { execRegisteredTimeouts } = mockTimeout();
- let ui = {
+ const ui = {
activateElement: () => {},
deactivateElement: () => {},
size: 4,
diff --git a/addons/web/static/tests/webclient/helpers.js b/addons/web/static/tests/webclient/helpers.js
index 7451b1a7360..326322b7027 100644
--- a/addons/web/static/tests/webclient/helpers.js
+++ b/addons/web/static/tests/webclient/helpers.js
@@ -33,6 +33,7 @@ import { registerCleanup } from "../helpers/cleanup";
import { makeTestEnv } from "../helpers/mock_env";
import {
fakeTitleService,
+ fakeCompanyService,
makeFakeLocalizationService,
makeFakeRouterService,
makeFakeHTTPService,
@@ -74,7 +75,7 @@ export function setupWebClientRegistries() {
options: { sequence: 0 },
},
};
- for (let [key, { value, options }] of Object.entries(favoriveMenuItems)) {
+ for (const [key, { value, options }] of Object.entries(favoriveMenuItems)) {
if (!favoriteMenuRegistry.contains(key)) {
favoriteMenuRegistry.add(key, value, options);
}
@@ -97,8 +98,9 @@ export function setupWebClientRegistries() {
ui: () => uiService,
user: () => makeFakeUserService(),
view: () => viewService,
+ company: () => fakeCompanyService,
};
- for (let serviceName in services) {
+ for (const serviceName in services) {
if (!serviceRegistry.contains(serviceName)) {
serviceRegistry.add(serviceName, services[serviceName]());
}
@@ -195,7 +197,7 @@ export async function addLegacyMockEnvironment(env, legacyParams = {}) {
serviceRegistry.add("legacy_action_manager", legacyActionManagerService);
serviceRegistry.add("legacy_notification", makeLegacyNotificationService(legacyEnv));
// deploy wowl services into the legacy env.
- const wowlToLegacyServiceMappers = registry.category('wowlToLegacyServiceMappers').getEntries();
+ const wowlToLegacyServiceMappers = registry.category("wowlToLegacyServiceMappers").getEntries();
for (const [legacyServiceName, wowlToLegacyServiceMapper] of wowlToLegacyServiceMappers) {
serviceRegistry.add(legacyServiceName, wowlToLegacyServiceMapper(legacyEnv));
}