mirror of
https://github.com/bringout/oca-ocb-hr.git
synced 2026-04-22 16:12:06 +02:00
19.0 vanilla
This commit is contained in:
parent
a1137a1456
commit
e1d89e11e3
2789 changed files with 1093187 additions and 605897 deletions
|
|
@ -1,10 +0,0 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import { addFakeModel, addModelNamesToFetch } from '@bus/../tests/helpers/model_definitions_helpers';
|
||||
|
||||
addModelNamesToFetch(['hr.employee.public']);
|
||||
|
||||
addFakeModel('m2x.avatar.employee', {
|
||||
employee_id: { string: "Employee", type: 'many2one', relation: 'hr.employee.public' },
|
||||
employee_ids: { string: "Employees", type: "many2many", relation: 'hr.employee.public' },
|
||||
});
|
||||
32
odoo-bringout-oca-ocb-hr/hr/static/tests/hr_test_helpers.js
Normal file
32
odoo-bringout-oca-ocb-hr/hr/static/tests/hr_test_helpers.js
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import { HrDepartment } from "@hr/../tests/mock_server/mock_models/hr_department";
|
||||
import { HrEmployee } from "@hr/../tests/mock_server/mock_models/hr_employee";
|
||||
import { HrEmployeePublic } from "@hr/../tests/mock_server/mock_models/hr_employee_public";
|
||||
import { M2xAvatarEmployee } from "@hr/../tests/mock_server/mock_models/m2x_avatar_employee";
|
||||
import { mailModels } from "@mail/../tests/mail_test_helpers";
|
||||
import { defineModels } from "@web/../tests/web_test_helpers";
|
||||
import { FakeUser } from "@hr/../tests/mock_server/mock_models/fake_user";
|
||||
import { HrVersion } from "./mock_server/mock_models/hr_version";
|
||||
import { HrJob } from "./mock_server/mock_models/hr_job";
|
||||
import { HrWorkLocation } from "./mock_server/mock_models/hr_work_location";
|
||||
import { ResourceResource } from "@resource/../tests/mock_server/mock_models/resource_resource";
|
||||
import { ResUsers } from "./mock_server/mock_models/res_users";
|
||||
import { ResPartner } from "./mock_server/mock_models/res_partner";
|
||||
|
||||
export function defineHrModels() {
|
||||
return defineModels(hrModels);
|
||||
}
|
||||
|
||||
export const hrModels = {
|
||||
...mailModels,
|
||||
M2xAvatarEmployee,
|
||||
HrDepartment,
|
||||
HrEmployee,
|
||||
HrVersion,
|
||||
HrEmployeePublic,
|
||||
FakeUser,
|
||||
HrJob,
|
||||
HrWorkLocation,
|
||||
ResourceResource,
|
||||
ResUsers,
|
||||
ResPartner,
|
||||
};
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import { unpatchAvatarCardPopover } from "@hr/components/avatar_card/avatar_card_popover_patch";
|
||||
|
||||
unpatchAvatarCardPopover();
|
||||
|
|
@ -0,0 +1,501 @@
|
|||
import { defineHrModels } from "@hr/../tests/hr_test_helpers";
|
||||
import { start } from "@mail/../tests/mail_test_helpers";
|
||||
import { describe, expect, test } from "@odoo/hoot";
|
||||
import { waitFor } from "@odoo/hoot-dom";
|
||||
import { contains, makeMockServer, mountView, onRpc } from "@web/../tests/web_test_helpers";
|
||||
import { getOrigin } from "@web/core/utils/urls";
|
||||
|
||||
describe.current.tags("desktop");
|
||||
defineHrModels();
|
||||
|
||||
test("many2one in list view", async () => {
|
||||
const { env } = await makeMockServer();
|
||||
const [partnerId_1, partnerId_2] = env["res.partner"].create([
|
||||
{ name: "Mario" },
|
||||
{ name: "Luigi" },
|
||||
]);
|
||||
const [userId_1, userId_2] = env["res.users"].create([
|
||||
{ partner_id: partnerId_1 },
|
||||
{ partner_id: partnerId_2 },
|
||||
]);
|
||||
const [employeeId_1, employeeId_2] = env["hr.employee.public"].create([
|
||||
{
|
||||
name: "Mario",
|
||||
user_id: userId_1,
|
||||
user_partner_id: partnerId_1,
|
||||
work_email: "Mario@partner.com",
|
||||
},
|
||||
{
|
||||
name: "Luigi",
|
||||
user_id: userId_2,
|
||||
user_partner_id: partnerId_2,
|
||||
},
|
||||
]);
|
||||
env["m2x.avatar.employee"].create([
|
||||
{
|
||||
employee_id: employeeId_1,
|
||||
employee_ids: [employeeId_1, employeeId_2],
|
||||
},
|
||||
{ employee_id: employeeId_2 },
|
||||
{ employee_id: employeeId_1 },
|
||||
]);
|
||||
await start();
|
||||
onRpc("has_group", () => false);
|
||||
await mountView({
|
||||
type: "list",
|
||||
resModel: "m2x.avatar.employee",
|
||||
arch: `<list><field name="employee_id" widget="many2one_avatar_employee"/></list>`,
|
||||
});
|
||||
expect(".o_data_cell div[name='employee_id']:eq(0)").toHaveText("Mario");
|
||||
expect(".o_data_cell div[name='employee_id']:eq(1)").toHaveText("Luigi");
|
||||
expect(".o_data_cell div[name='employee_id']:eq(2)").toHaveText("Mario");
|
||||
expect("div[name='employee_id'] a").toHaveCount(0);
|
||||
|
||||
// click on first employee avatar
|
||||
await contains(".o_data_cell .o_m2o_avatar > img:eq(0)").click();
|
||||
await waitFor(".o_avatar_card");
|
||||
expect(".o_card_user_infos > span").toHaveText("Mario");
|
||||
expect(".o_card_user_infos > a").toHaveText("Mario@partner.com");
|
||||
expect(".o_avatar_card_buttons button:eq(0)").toHaveText("Send message");
|
||||
await contains(".o_avatar_card_buttons button:eq(0)").click();
|
||||
await waitFor(".o-mail-ChatWindow");
|
||||
await waitFor(".o-mail-ChatWindow-header:contains('Mario')");
|
||||
|
||||
// click on second employee
|
||||
await contains(".o_data_cell .o_m2o_avatar > img:eq(1)").click();
|
||||
expect(".o_card_user_infos span").toHaveText("Luigi");
|
||||
expect(".o_avatar_card").toHaveCount(1);
|
||||
expect(".o_avatar_card_buttons button:eq(0)").toHaveText("Send message");
|
||||
await contains(".o_avatar_card_buttons button:eq(0)").click();
|
||||
await waitFor(".o-mail-ChatWindow-header:contains('Luigi')");
|
||||
expect(".o-mail-ChatWindow").toHaveCount(2);
|
||||
|
||||
// click on third employee (same as first)
|
||||
await contains(".o_data_cell .o_m2o_avatar > img:eq(2)").click();
|
||||
expect(".o_card_user_infos span").toHaveText("Mario");
|
||||
expect(".o_avatar_card").toHaveCount(1);
|
||||
expect(".o_card_user_infos span:eq(0)").toHaveText("Mario");
|
||||
expect(".o_card_user_infos > a").toHaveText("Mario@partner.com");
|
||||
expect(".o_avatar_card_buttons button:eq(0)").toHaveText("Send message");
|
||||
await contains(".o_avatar_card_buttons button:eq(0)").click();
|
||||
await waitFor(".o-mail-ChatWindow-header:contains('Mario')");
|
||||
expect(".o-mail-ChatWindow").toHaveCount(2);
|
||||
});
|
||||
|
||||
test("many2one in kanban view", async () => {
|
||||
const { env } = await makeMockServer();
|
||||
const partnerId = env["res.partner"].create({});
|
||||
const userId = env["res.users"].create({ partner_id: partnerId });
|
||||
const employeeId = env["hr.employee.public"].create({
|
||||
user_id: userId,
|
||||
user_partner_id: partnerId,
|
||||
});
|
||||
env["m2x.avatar.employee"].create({
|
||||
employee_id: employeeId,
|
||||
employee_ids: [employeeId],
|
||||
});
|
||||
onRpc("has_group", () => false);
|
||||
await mountView({
|
||||
type: "kanban",
|
||||
resModel: "m2x.avatar.employee",
|
||||
arch: `<kanban>
|
||||
<templates>
|
||||
<t t-name="card">
|
||||
<field name="employee_id" widget="many2one_avatar_employee"/>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>`,
|
||||
});
|
||||
expect(".o_kanban_record:eq(0)").toHaveText("");
|
||||
await waitFor(".o_m2o_avatar");
|
||||
expect(".o_m2o_avatar > img:eq(0)").toHaveAttribute(
|
||||
"data-src",
|
||||
`/web/image/hr.employee.public/${employeeId}/avatar_128`
|
||||
);
|
||||
});
|
||||
|
||||
test("many2one: click on an employee not associated with a user", async () => {
|
||||
const { env } = await makeMockServer();
|
||||
const employeeId = env["hr.employee.public"].create({ name: "Mario" });
|
||||
const avatarId = env["m2x.avatar.employee"].create({ employee_id: employeeId });
|
||||
onRpc("has_group", () => false);
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "m2x.avatar.employee",
|
||||
resId: avatarId,
|
||||
arch: `<form><field name="employee_id" widget="many2one_avatar_employee"/></form>`,
|
||||
});
|
||||
await waitFor(".o_field_widget[name=employee_id] input:value(Mario)");
|
||||
await contains(".o_m2o_avatar > img").click();
|
||||
});
|
||||
|
||||
test("many2one with hr group widget in kanban view", async () => {
|
||||
const { env } = await makeMockServer();
|
||||
const partnerId = env["res.partner"].create({});
|
||||
const userId = env["res.users"].create({ partner_id: partnerId });
|
||||
const employeeId = env["hr.employee.public"].create({
|
||||
user_id: userId,
|
||||
user_partner_id: partnerId,
|
||||
});
|
||||
env["m2x.avatar.employee"].create({
|
||||
employee_id: employeeId,
|
||||
employee_ids: [employeeId],
|
||||
});
|
||||
await mountView({
|
||||
type: "kanban",
|
||||
resModel: "m2x.avatar.employee",
|
||||
arch: `<kanban>
|
||||
<templates>
|
||||
<t t-name="card">
|
||||
<field name="employee_id" widget="many2one_avatar_employee"/>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>`,
|
||||
});
|
||||
expect(".o_kanban_record:eq(0)").toHaveText("");
|
||||
await waitFor(".o_m2o_avatar");
|
||||
expect(".o_m2o_avatar > img:eq(0)").toHaveAttribute(
|
||||
"data-src",
|
||||
`/web/image/hr.employee/${employeeId}/avatar_128`
|
||||
);
|
||||
});
|
||||
|
||||
test("many2one with relation set in options", async () => {
|
||||
const { env } = await makeMockServer();
|
||||
const partnerId = env["res.partner"].create({});
|
||||
const userId = env["res.users"].create({ partner_id: partnerId });
|
||||
const employeeId = env["hr.employee.public"].create({
|
||||
user_id: userId,
|
||||
user_partner_id: partnerId,
|
||||
});
|
||||
env["m2x.avatar.employee"].create({
|
||||
employee_id: employeeId,
|
||||
employee_ids: [employeeId],
|
||||
});
|
||||
await mountView({
|
||||
type: "kanban",
|
||||
resModel: "m2x.avatar.employee",
|
||||
arch: `<kanban>
|
||||
<templates>
|
||||
<t t-name="card">
|
||||
<field name="employee_id" widget="many2one_avatar_employee" options="{'relation': 'hr.employee.public'}"/>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>`,
|
||||
});
|
||||
expect(".o_kanban_record:eq(0)").toHaveText("");
|
||||
await waitFor(".o_m2o_avatar");
|
||||
expect(".o_m2o_avatar > img:eq(0)").toHaveAttribute(
|
||||
"data-src",
|
||||
`/web/image/hr.employee.public/${employeeId}/avatar_128`
|
||||
);
|
||||
});
|
||||
|
||||
test("many2one without hr.group_hr_user", async () => {
|
||||
const { env } = await makeMockServer();
|
||||
env["m2x.avatar.employee"].create({});
|
||||
env["hr.employee"].create({ name: "babar" });
|
||||
env["hr.employee.public"].create({ name: "babar" });
|
||||
onRpc("web_name_search", (args) => {
|
||||
expect.step("web_name_search");
|
||||
expect(args.model).toBe("hr.employee.public");
|
||||
});
|
||||
onRpc("web_search_read", (args) => {
|
||||
expect.step("web_search_read");
|
||||
expect(args.model).toBe("hr.employee.public");
|
||||
});
|
||||
onRpc("has_group", () => false);
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "m2x.avatar.employee",
|
||||
arch: `<form><field name="employee_id" widget="many2one_avatar_employee"/></form>`,
|
||||
});
|
||||
|
||||
await waitFor(".o-autocomplete--input.o_input");
|
||||
await contains(".o-autocomplete--input.o_input").click();
|
||||
expect.verifySteps(["web_name_search"]);
|
||||
|
||||
await waitFor(".o_m2o_dropdown_option_search_more");
|
||||
await contains(".o_m2o_dropdown_option_search_more").click();
|
||||
expect.verifySteps(["web_search_read"]);
|
||||
});
|
||||
|
||||
test("many2one in form view", async () => {
|
||||
const { env } = await makeMockServer();
|
||||
const [partnerId_1, partnerId_2] = env["res.partner"].create([
|
||||
{ name: "Mario" },
|
||||
{ name: "Luigi" },
|
||||
]);
|
||||
const [userId_1, userId_2] = env["res.users"].create([
|
||||
{ partner_id: partnerId_1 },
|
||||
{ partner_id: partnerId_2 },
|
||||
]);
|
||||
const [employeeId_1, employeeId_2] = env["hr.employee.public"].create([
|
||||
{
|
||||
user_id: userId_1,
|
||||
user_partner_id: partnerId_1,
|
||||
name: "Mario",
|
||||
work_email: "Mario@partner.com",
|
||||
},
|
||||
{
|
||||
name: "Luigi",
|
||||
user_id: userId_2,
|
||||
user_partner_id: partnerId_2,
|
||||
},
|
||||
]);
|
||||
const avatarId_1 = env["m2x.avatar.employee"].create({
|
||||
employee_ids: [employeeId_1, employeeId_2],
|
||||
});
|
||||
await start();
|
||||
onRpc("has_group", () => false);
|
||||
await mountView({
|
||||
type: "form",
|
||||
resId: avatarId_1,
|
||||
resModel: "m2x.avatar.employee",
|
||||
arch: `<form><field name="employee_ids" widget="many2many_avatar_employee"/></form>`,
|
||||
});
|
||||
expect(".o_field_many2many_avatar_employee .o_tag").toHaveCount(2);
|
||||
expect(".o_field_many2many_avatar_employee .o_tag img:eq(0)").toHaveAttribute(
|
||||
"data-src",
|
||||
`${getOrigin()}/web/image/hr.employee.public/${employeeId_1}/avatar_128`
|
||||
);
|
||||
|
||||
// Clicking on first employee's avatar
|
||||
await contains(".o_field_many2many_avatar_employee .o_tag .o_m2m_avatar:eq(0)").click();
|
||||
await waitFor(".o_avatar_card");
|
||||
expect(".o_card_user_infos > span").toHaveText("Mario");
|
||||
expect(".o_card_user_infos > a").toHaveText("Mario@partner.com");
|
||||
expect(".o_avatar_card_buttons button:eq(0)").toHaveText("Send message");
|
||||
await contains(".o_avatar_card_buttons button:eq(0)").click();
|
||||
await waitFor(".o-mail-ChatWindow");
|
||||
await waitFor(".o-mail-ChatWindow-header:contains('Mario')");
|
||||
|
||||
// Clicking on second employee's avatar
|
||||
await contains(".o_field_many2many_avatar_employee .o_tag .o_m2m_avatar:eq(1)").click();
|
||||
expect(".o_card_user_infos span").toHaveText("Luigi");
|
||||
expect(".o_avatar_card").toHaveCount(1);
|
||||
expect(".o_avatar_card_buttons button:eq(0)").toHaveText("Send message");
|
||||
await contains(".o_avatar_card_buttons button:eq(0)").click();
|
||||
await waitFor(".o-mail-ChatWindow-header:contains('Luigi')");
|
||||
expect(".o-mail-ChatWindow").toHaveCount(2);
|
||||
});
|
||||
|
||||
test("many2one with hr group widget in form view", async () => {
|
||||
const { env } = await makeMockServer();
|
||||
const [partnerId_1, partnerId_2] = env["res.partner"].create([{}, {}]);
|
||||
const [userId_1, userId_2] = env["res.users"].create([
|
||||
{ partner_id: partnerId_1 },
|
||||
{ partner_id: partnerId_2 },
|
||||
]);
|
||||
const [employeeData_1, employeeData_2] = [
|
||||
{ user_id: userId_1, user_partner_id: partnerId_1 },
|
||||
{ user_id: userId_2, user_partner_id: partnerId_2 },
|
||||
];
|
||||
env["hr.employee"].create([{ ...employeeData_1 }, { ...employeeData_2 }]);
|
||||
const [employeeId_1, employeeId_2] = env["hr.employee.public"].create([
|
||||
{ ...employeeData_1 },
|
||||
{ ...employeeData_2 },
|
||||
]);
|
||||
const avatarId_1 = env["m2x.avatar.employee"].create({
|
||||
employee_ids: [employeeId_1, employeeId_2],
|
||||
});
|
||||
expect.step(`read hr.employee ${employeeId_1}`);
|
||||
expect.step(`read hr.employee ${employeeId_2}`);
|
||||
await mountView({
|
||||
type: "form",
|
||||
resId: avatarId_1,
|
||||
resModel: "m2x.avatar.employee",
|
||||
arch: `<form><field name="employee_ids" widget="many2many_avatar_employee"/></form>`,
|
||||
});
|
||||
expect(".o_field_many2many_avatar_employee .o_tag").toHaveCount(2);
|
||||
expect(".o_field_many2many_avatar_employee .o_tag img:eq(0)").toHaveAttribute(
|
||||
"data-src",
|
||||
`${getOrigin()}/web/image/hr.employee/${employeeId_1}/avatar_128`
|
||||
);
|
||||
await contains(".o_field_many2many_avatar_employee .o_tag .o_m2m_avatar:eq(0)").click();
|
||||
await contains(".o_field_many2many_avatar_employee .o_tag .o_m2m_avatar:eq(1)").click();
|
||||
expect.verifySteps([
|
||||
`read hr.employee ${employeeId_1}`,
|
||||
`read hr.employee ${employeeId_2}`,
|
||||
]);
|
||||
});
|
||||
|
||||
test("many2one widget in list view", async () => {
|
||||
const { env } = await makeMockServer();
|
||||
const [partnerId_1, partnerId_2] = env["res.partner"].create([
|
||||
{ name: "Mario" },
|
||||
{ name: "Yoshi" },
|
||||
]);
|
||||
const [userId_1, userId_2] = env["res.users"].create([
|
||||
{ partner_id: partnerId_1 },
|
||||
{ partner_id: partnerId_2 },
|
||||
]);
|
||||
const [employeeId_1, employeeId_2] = env["hr.employee.public"].create([
|
||||
{
|
||||
name: "Mario",
|
||||
user_id: userId_1,
|
||||
user_partner_id: partnerId_1,
|
||||
work_email: "Mario@partner.com",
|
||||
},
|
||||
{
|
||||
name: "Yoshi",
|
||||
user_id: userId_2,
|
||||
user_partner_id: partnerId_2,
|
||||
},
|
||||
]);
|
||||
env["m2x.avatar.employee"].create({
|
||||
employee_ids: [employeeId_1, employeeId_2],
|
||||
});
|
||||
onRpc("has_group", () => false);
|
||||
await start();
|
||||
await mountView({
|
||||
type: "list",
|
||||
resModel: "m2x.avatar.employee",
|
||||
arch: `<list><field name="employee_ids" widget="many2many_avatar_employee"/></list>`,
|
||||
});
|
||||
expect(".o_data_cell:first .o_field_many2many_avatar_employee > div > span").toHaveCount(2);
|
||||
|
||||
// Clicking on first employee's avatar
|
||||
await contains(".o_data_cell .o_m2m_avatar:eq(0)").click();
|
||||
await waitFor(".o_avatar_card");
|
||||
expect(".o_card_user_infos > span").toHaveText("Mario");
|
||||
expect(".o_card_user_infos > a").toHaveText("Mario@partner.com");
|
||||
expect(".o_avatar_card_buttons button:eq(0)").toHaveText("Send message");
|
||||
await contains(".o_avatar_card_buttons button:eq(0)").click();
|
||||
await waitFor(".o-mail-ChatWindow");
|
||||
await waitFor(".o-mail-ChatWindow-header:contains('Mario')");
|
||||
|
||||
// Clicking on second employee's avatar
|
||||
await contains(".o_data_cell .o_m2m_avatar:eq(1)").click();
|
||||
expect(".o_card_user_infos span").toHaveText("Yoshi");
|
||||
expect(".o_avatar_card").toHaveCount(1);
|
||||
expect(".o_avatar_card_buttons button:eq(0)").toHaveText("Send message");
|
||||
await contains(".o_avatar_card_buttons button:eq(0)").click();
|
||||
await waitFor(".o-mail-ChatWindow-header:contains('Yoshi')");
|
||||
});
|
||||
|
||||
test("many2many in kanban view", async () => {
|
||||
const { env } = await makeMockServer();
|
||||
const [partnerId_1, partnerId_2] = env["res.partner"].create([
|
||||
{ name: "Mario" },
|
||||
{ name: "Luigi" },
|
||||
]);
|
||||
const [userId_1, userId_2] = env["res.users"].create([
|
||||
{ partner_id: partnerId_1 },
|
||||
{ partner_id: partnerId_2 },
|
||||
]);
|
||||
const [employeeId_1, employeeId_2] = env["hr.employee.public"].create([
|
||||
{
|
||||
user_id: userId_1,
|
||||
user_partner_id: partnerId_1,
|
||||
name: "Mario",
|
||||
work_email: "Mario@partner.com",
|
||||
},
|
||||
{
|
||||
name: "Luigi",
|
||||
user_id: userId_2,
|
||||
user_partner_id: partnerId_2,
|
||||
},
|
||||
]);
|
||||
env["m2x.avatar.employee"].create({
|
||||
employee_ids: [employeeId_1, employeeId_2],
|
||||
});
|
||||
onRpc("has_group", () => false);
|
||||
await start();
|
||||
await mountView({
|
||||
type: "kanban",
|
||||
resModel: "m2x.avatar.employee",
|
||||
arch: `<kanban>
|
||||
<templates>
|
||||
<t t-name="card">
|
||||
<footer>
|
||||
<field name="employee_ids" widget="many2many_avatar_employee"/>
|
||||
</footer>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>`,
|
||||
});
|
||||
expect(
|
||||
".o_kanban_record:first .o_field_many2many_avatar_employee img.o_m2m_avatar"
|
||||
).toHaveCount(2);
|
||||
expect(
|
||||
".o_kanban_record .o_field_many2many_avatar_employee img.o_m2m_avatar:eq(0)"
|
||||
).toHaveAttribute(
|
||||
"data-src",
|
||||
`${getOrigin()}/web/image/hr.employee.public/${employeeId_2}/avatar_128`
|
||||
);
|
||||
expect(
|
||||
".o_kanban_record .o_field_many2many_avatar_employee img.o_m2m_avatar:eq(1)"
|
||||
).toHaveAttribute(
|
||||
"data-src",
|
||||
`${getOrigin()}/web/image/hr.employee.public/${employeeId_1}/avatar_128`
|
||||
);
|
||||
|
||||
// Clicking on first employee's avatar
|
||||
await contains(".o_kanban_record img.o_m2m_avatar:eq(1)").click();
|
||||
await waitFor(".o_avatar_card");
|
||||
expect(".o_card_user_infos > span").toHaveText("Mario");
|
||||
expect(".o_card_user_infos > a").toHaveText("Mario@partner.com");
|
||||
expect(".o_avatar_card_buttons button:eq(0)").toHaveText("Send message");
|
||||
await contains(".o_avatar_card_buttons button:eq(0)").click();
|
||||
await waitFor(".o-mail-ChatWindow");
|
||||
await waitFor(".o-mail-ChatWindow-header:contains('Mario')");
|
||||
|
||||
// Clicking on second employee's avatar
|
||||
await contains(".o_kanban_record img.o_m2m_avatar:eq(0)").click();
|
||||
expect(".o_card_user_infos span").toHaveText("Luigi");
|
||||
expect(".o_avatar_card").toHaveCount(1);
|
||||
expect(".o_avatar_card_buttons button:eq(0)").toHaveText("Send message");
|
||||
await contains(".o_avatar_card_buttons button:eq(0)").click();
|
||||
await waitFor(".o-mail-ChatWindow-header:contains('Luigi')");
|
||||
expect(".o-mail-ChatWindow").toHaveCount(2);
|
||||
});
|
||||
|
||||
test("many2many: click on an employee not associated with a user", async () => {
|
||||
const { env } = await makeMockServer();
|
||||
const partnerId = env["res.partner"].create({ name: "Luigi" });
|
||||
const userId = env["res.users"].create({ partner_id: partnerId });
|
||||
const [employeeId_1, employeeId_2] = env["hr.employee.public"].create([
|
||||
{
|
||||
name: "Mario",
|
||||
work_email: "Mario@partner.com",
|
||||
},
|
||||
{
|
||||
name: "Luigi",
|
||||
user_id: userId,
|
||||
user_partner_id: partnerId,
|
||||
},
|
||||
]);
|
||||
const avatarId = env["m2x.avatar.employee"].create({
|
||||
employee_ids: [employeeId_1, employeeId_2],
|
||||
});
|
||||
onRpc("has_group", () => false);
|
||||
await start();
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "m2x.avatar.employee",
|
||||
resId: avatarId,
|
||||
arch: `<form><field name="employee_ids" widget="many2many_avatar_employee"/></form>`,
|
||||
});
|
||||
expect(".o_field_many2many_avatar_employee .o_tag").toHaveCount(2);
|
||||
expect(".o_field_many2many_avatar_employee .o_tag img:eq(0)").toHaveAttribute(
|
||||
"data-src",
|
||||
`${getOrigin()}/web/image/hr.employee.public/${employeeId_1}/avatar_128`
|
||||
);
|
||||
|
||||
// Clicking on first employee's avatar (employee with no user)
|
||||
await contains(".o_field_many2many_avatar_employee .o_tag .o_m2m_avatar:eq(0)").click();
|
||||
await waitFor(".o_avatar_card");
|
||||
expect(".o_card_user_infos > span").toHaveText("Mario");
|
||||
expect(".o_card_user_infos > a").toHaveText("Mario@partner.com");
|
||||
expect(".o_avatar_card_buttons button:eq(0)").toHaveText("View Profile");
|
||||
|
||||
// Clicking on second employee's avatar (employee with user)
|
||||
await contains(".o_field_many2many_avatar_employee .o_tag .o_m2m_avatar:eq(1)").click();
|
||||
expect(".o_card_user_infos span").toHaveText("Luigi");
|
||||
expect(".o_avatar_card").toHaveCount(1);
|
||||
expect(".o_avatar_card_buttons button:eq(0)").toHaveText("Send message");
|
||||
await contains(".o_avatar_card_buttons button:eq(0)").click();
|
||||
await waitFor(".o-mail-ChatWindow-header:contains('Luigi')");
|
||||
expect(".o-mail-ChatWindow").toHaveCount(1);
|
||||
});
|
||||
|
|
@ -1,182 +0,0 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import {
|
||||
start,
|
||||
startServer,
|
||||
} from '@mail/../tests/helpers/test_utils';
|
||||
|
||||
import { makeFakeNotificationService } from "@web/../tests/helpers/mock_services";
|
||||
|
||||
import { Many2OneAvatarEmployee } from '@hr/js/m2x_avatar_employee';
|
||||
import { dom } from 'web.test_utils';
|
||||
|
||||
QUnit.module('hr', {}, function () {
|
||||
QUnit.module('M2XAvatarEmployeeLegacy', {
|
||||
beforeEach() {
|
||||
Many2OneAvatarEmployee.prototype.partnerIds = {};
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test('many2one_avatar_employee: click on an employee not associated with a user', async function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
const pyEnv = await startServer();
|
||||
const hrEmployeePublicId1 = pyEnv['hr.employee.public'].create({ name: 'Mario' });
|
||||
const m2xHrAvatarUserId1 = pyEnv['m2x.avatar.employee'].create({ employee_id: hrEmployeePublicId1 });
|
||||
const views = {
|
||||
'm2x.avatar.employee,false,form': '<form js_class="legacy_form"><field name="employee_id" widget="many2one_avatar_employee"/></form>',
|
||||
};
|
||||
const { openView } = await start({
|
||||
mockRPC(route, args) {
|
||||
if (args.method === 'read') {
|
||||
assert.step(`read ${args.model} ${args.args[0]}`);
|
||||
}
|
||||
},
|
||||
serverData: { views },
|
||||
services: {
|
||||
notification: makeFakeNotificationService(message => {
|
||||
assert.ok(
|
||||
true,
|
||||
"should display a toast notification after failing to open chat"
|
||||
);
|
||||
assert.strictEqual(
|
||||
message,
|
||||
"You can only chat with employees that have a dedicated user.",
|
||||
"should display the correct information in the notification"
|
||||
);
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
await openView({
|
||||
res_model: 'm2x.avatar.employee',
|
||||
res_id: m2xHrAvatarUserId1,
|
||||
views: [[false, 'form']],
|
||||
});
|
||||
assert.strictEqual(document.querySelector('.o_field_widget[name=employee_id]').innerText.trim(), 'Mario');
|
||||
|
||||
await dom.click(document.querySelector('.o_m2o_avatar > img'));
|
||||
|
||||
assert.verifySteps([
|
||||
`read m2x.avatar.employee ${m2xHrAvatarUserId1}`,
|
||||
`read hr.employee.public ${hrEmployeePublicId1}`,
|
||||
]);
|
||||
});
|
||||
|
||||
QUnit.test('many2many_avatar_employee widget in form view', async function (assert) {
|
||||
assert.expect(8);
|
||||
|
||||
const pyEnv = await startServer();
|
||||
const [resPartnerId1, resPartnerId2] = pyEnv['res.partner'].create([{}, {}]);
|
||||
const [resUsersId1, resUsersId2] = pyEnv['res.users'].create([{}, {}]);
|
||||
const [hrEmployeePublicId1, hrEmployeePublicId2] = pyEnv['hr.employee.public'].create([
|
||||
{ user_id: resUsersId1, user_partner_id: resPartnerId1 },
|
||||
{ user_id: resUsersId2, user_partner_id: resPartnerId2 },
|
||||
]);
|
||||
const m2xAvatarEmployeeId1 = pyEnv['m2x.avatar.employee'].create(
|
||||
{ employee_ids: [hrEmployeePublicId1, hrEmployeePublicId2] },
|
||||
);
|
||||
const views = {
|
||||
'm2x.avatar.employee,false,form': '<form js_class="legacy_form"><field name="employee_ids" widget="many2many_avatar_employee"/></form>',
|
||||
};
|
||||
const { openView } = await start({
|
||||
mockRPC(route, args) {
|
||||
if (args.method === 'read') {
|
||||
assert.step(`read ${args.model} ${args.args[0]}`);
|
||||
}
|
||||
},
|
||||
serverData: { views },
|
||||
});
|
||||
|
||||
await openView({
|
||||
res_model: 'm2x.avatar.employee',
|
||||
res_id: m2xAvatarEmployeeId1,
|
||||
views: [[false, 'form']],
|
||||
});
|
||||
assert.containsN(document.body, '.o_field_many2manytags.avatar.o_field_widget .badge', 2,
|
||||
"should have 2 records");
|
||||
assert.strictEqual(document.querySelector('.o_field_many2manytags.avatar.o_field_widget .badge img').getAttribute('data-src'),
|
||||
`/web/image/hr.employee.public/${hrEmployeePublicId1}/avatar_128`,
|
||||
"should have correct avatar image");
|
||||
|
||||
await dom.click(document.querySelector('.o_field_many2manytags.avatar .badge .o_m2m_avatar'));
|
||||
await dom.click(document.querySelectorAll('.o_field_many2manytags.avatar .badge .o_m2m_avatar')[1]);
|
||||
|
||||
assert.verifySteps([
|
||||
`read m2x.avatar.employee ${m2xAvatarEmployeeId1}`,
|
||||
`read hr.employee.public ${hrEmployeePublicId1},${hrEmployeePublicId2}`,
|
||||
`read hr.employee.public ${hrEmployeePublicId1}`,
|
||||
`read hr.employee.public ${hrEmployeePublicId2}`,
|
||||
]);
|
||||
|
||||
assert.containsN(
|
||||
document.body,
|
||||
'.o_ChatWindowHeader_name',
|
||||
2,
|
||||
"should have 2 chat windows"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('many2many_avatar_employee: click on an employee not associated with a user', async function (assert) {
|
||||
assert.expect(10);
|
||||
|
||||
const pyEnv = await startServer();
|
||||
const resPartnerId1 = pyEnv['res.partner'].create({});
|
||||
const resUsersId1 = pyEnv['res.users'].create({});
|
||||
const [hrEmployeePublicId1, hrEmployeePublicId2] = pyEnv['hr.employee.public'].create([
|
||||
{},
|
||||
{ user_id: resUsersId1, user_partner_id: resPartnerId1 },
|
||||
]);
|
||||
const m2xAvatarEmployeeId1 = pyEnv['m2x.avatar.employee'].create(
|
||||
{ employee_ids: [hrEmployeePublicId1, hrEmployeePublicId2] },
|
||||
);
|
||||
const views = {
|
||||
'm2x.avatar.employee,false,form': '<form js_class="legacy_form"><field name="employee_ids" widget="many2many_avatar_employee"/></form>',
|
||||
};
|
||||
const { openView } = await start({
|
||||
mockRPC(route, args) {
|
||||
if (args.method === 'read') {
|
||||
assert.step(`read ${args.model} ${args.args[0]}`);
|
||||
}
|
||||
},
|
||||
serverData: { views },
|
||||
services: {
|
||||
notification: makeFakeNotificationService(message => {
|
||||
assert.ok(
|
||||
true,
|
||||
"should display a toast notification after failing to open chat"
|
||||
);
|
||||
assert.strictEqual(
|
||||
message,
|
||||
"You can only chat with employees that have a dedicated user.",
|
||||
"should display the correct information in the notification"
|
||||
);
|
||||
}),
|
||||
},
|
||||
});
|
||||
await openView({
|
||||
res_model: 'm2x.avatar.employee',
|
||||
res_id: m2xAvatarEmployeeId1,
|
||||
views: [[false, 'form']],
|
||||
});
|
||||
|
||||
assert.containsN(document.body, '.o_field_many2manytags.avatar.o_field_widget .badge', 2,
|
||||
"should have 2 records");
|
||||
assert.strictEqual(document.querySelector('.o_field_many2manytags.avatar.o_field_widget .badge img').getAttribute('data-src'),
|
||||
`/web/image/hr.employee.public/${hrEmployeePublicId1}/avatar_128`,
|
||||
"should have correct avatar image");
|
||||
|
||||
await dom.click(document.querySelector('.o_field_many2manytags.avatar .badge .o_m2m_avatar'));
|
||||
await dom.click(document.querySelectorAll('.o_field_many2manytags.avatar .badge .o_m2m_avatar')[1]);
|
||||
|
||||
assert.verifySteps([
|
||||
`read m2x.avatar.employee ${hrEmployeePublicId1}`,
|
||||
`read hr.employee.public ${hrEmployeePublicId1},${hrEmployeePublicId2}`,
|
||||
`read hr.employee.public ${hrEmployeePublicId1}`,
|
||||
`read hr.employee.public ${hrEmployeePublicId2}`
|
||||
]);
|
||||
|
||||
assert.containsOnce(document.body, '.o_ChatWindowHeader_name',
|
||||
"should have 1 chat window");
|
||||
});
|
||||
});
|
||||
|
|
@ -1,450 +0,0 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import {
|
||||
afterNextRender,
|
||||
start,
|
||||
startServer,
|
||||
} from '@mail/../tests/helpers/test_utils';
|
||||
|
||||
import { makeFakeNotificationService } from "@web/../tests/helpers/mock_services";
|
||||
|
||||
import { Many2OneAvatarEmployee } from '@hr/js/m2x_avatar_employee';
|
||||
import { dom } from 'web.test_utils';
|
||||
|
||||
QUnit.module('hr', {}, function () {
|
||||
QUnit.module('M2XAvatarEmployee', {
|
||||
beforeEach() {
|
||||
Many2OneAvatarEmployee.prototype.partnerIds = {};
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test('many2one_avatar_employee widget in list view', async function (assert) {
|
||||
assert.expect(13);
|
||||
|
||||
const pyEnv = await startServer();
|
||||
const [resPartnerId1, resPartnerId2] = pyEnv['res.partner'].create([
|
||||
{ display_name: "Mario" },
|
||||
{ display_name: "Luigi" },
|
||||
]);
|
||||
const [resUsersId1, resUsersId2] = pyEnv['res.users'].create([
|
||||
{ partner_id: resPartnerId1 },
|
||||
{ partner_id: resPartnerId2 },
|
||||
]);
|
||||
const [hrEmployeePublicId1, hrEmployeePublicId2] = pyEnv['hr.employee.public'].create([
|
||||
{ name: "Mario", user_id: resUsersId1, user_partner_id: resPartnerId1 },
|
||||
{ name: "Luigi", user_id: resUsersId2, user_partner_id: resPartnerId2 },
|
||||
]);
|
||||
pyEnv['m2x.avatar.employee'].create([
|
||||
{ employee_id: hrEmployeePublicId1, employee_ids: [hrEmployeePublicId1, hrEmployeePublicId2] },
|
||||
{ employee_id: hrEmployeePublicId2 },
|
||||
{ employee_id: hrEmployeePublicId1 },
|
||||
]);
|
||||
const views = {
|
||||
'm2x.avatar.employee,false,list': '<tree><field name="employee_id" widget="many2one_avatar_employee"/></tree>',
|
||||
};
|
||||
const { openView } = await start({
|
||||
mockRPC(route, args) {
|
||||
if (args.method === 'read') {
|
||||
assert.step(`read ${args.model} ${args.args[0]}`);
|
||||
}
|
||||
},
|
||||
serverData: { views },
|
||||
});
|
||||
await openView({
|
||||
res_model: 'm2x.avatar.employee',
|
||||
views: [[false, 'list']],
|
||||
});
|
||||
|
||||
assert.strictEqual(document.querySelector('.o_data_cell span:not(.o_m2o_avatar) span').innerText, 'Mario');
|
||||
assert.strictEqual(document.querySelectorAll('.o_data_cell span:not(.o_m2o_avatar) span')[1].innerText, 'Luigi');
|
||||
assert.strictEqual(document.querySelectorAll('.o_data_cell span:not(.o_m2o_avatar) span')[2].innerText, 'Mario');
|
||||
|
||||
// click on first employee
|
||||
await afterNextRender(() =>
|
||||
dom.click(document.querySelector('.o_data_cell .o_m2o_avatar > img'))
|
||||
);
|
||||
assert.verifySteps(
|
||||
[`read hr.employee.public ${hrEmployeePublicId1}`],
|
||||
"first employee should have been read to find its partner"
|
||||
);
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
'.o_ChatWindowHeader_name',
|
||||
'should have opened chat window'
|
||||
);
|
||||
assert.strictEqual(
|
||||
document.querySelector('.o_ChatWindowHeader_name').textContent,
|
||||
"Mario",
|
||||
'chat window should be with clicked employee'
|
||||
);
|
||||
|
||||
// click on second employee
|
||||
await afterNextRender(() =>
|
||||
dom.click(document.querySelectorAll('.o_data_cell .o_m2o_avatar > img')[1]
|
||||
));
|
||||
assert.verifySteps(
|
||||
[`read hr.employee.public ${hrEmployeePublicId2}`],
|
||||
"second employee should have been read to find its partner"
|
||||
);
|
||||
assert.containsN(
|
||||
document.body,
|
||||
'.o_ChatWindowHeader_name',
|
||||
2,
|
||||
'should have opened second chat window'
|
||||
);
|
||||
assert.strictEqual(
|
||||
document.querySelectorAll('.o_ChatWindowHeader_name')[1].textContent,
|
||||
"Luigi",
|
||||
'chat window should be with clicked employee'
|
||||
);
|
||||
|
||||
// click on third employee (same as first)
|
||||
await afterNextRender(() =>
|
||||
dom.click(document.querySelectorAll('.o_data_cell .o_m2o_avatar > img')[2])
|
||||
);
|
||||
assert.verifySteps(
|
||||
[],
|
||||
"employee should not have been read again because we already know its partner"
|
||||
);
|
||||
assert.containsN(
|
||||
document.body,
|
||||
'.o_ChatWindowHeader_name',
|
||||
2,
|
||||
"should still have only 2 chat windows because third is the same partner as first"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('many2one_avatar_employee widget in kanban view', async function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
const pyEnv = await startServer();
|
||||
const resPartnerId1 = pyEnv['res.partner'].create({});
|
||||
const resUsersId1 = pyEnv['res.users'].create({ partner_id: resPartnerId1 });
|
||||
const hrEmployeePublicId1 = pyEnv['hr.employee.public'].create({ user_id: resUsersId1, user_partner_id: resPartnerId1 });
|
||||
pyEnv['m2x.avatar.employee'].create({ employee_id: hrEmployeePublicId1, employee_ids: [hrEmployeePublicId1] });
|
||||
const views = {
|
||||
'm2x.avatar.employee,false,kanban':
|
||||
`<kanban>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div>
|
||||
<field name="employee_id" widget="many2one_avatar_employee"/>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>`,
|
||||
};
|
||||
const { openView } = await start({
|
||||
serverData: { views },
|
||||
});
|
||||
await openView({
|
||||
res_model: 'm2x.avatar.employee',
|
||||
views: [[false, 'kanban']],
|
||||
});
|
||||
|
||||
assert.strictEqual(document.querySelector('.o_kanban_record').innerText.trim(), '');
|
||||
assert.containsOnce(document.body, '.o_m2o_avatar');
|
||||
assert.strictEqual(document.querySelector('.o_m2o_avatar > img').getAttribute('data-src'), `/web/image/hr.employee.public/${hrEmployeePublicId1}/avatar_128`);
|
||||
});
|
||||
|
||||
QUnit.test('many2one_avatar_employee: click on an employee not associated with a user', async function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
const pyEnv = await startServer();
|
||||
const hrEmployeePublicId1 = pyEnv['hr.employee.public'].create({ name: 'Mario' });
|
||||
const m2xHrAvatarUserId1 = pyEnv['m2x.avatar.employee'].create({ employee_id: hrEmployeePublicId1 });
|
||||
const views = {
|
||||
'm2x.avatar.employee,false,form': '<form><field name="employee_id" widget="many2one_avatar_employee"/></form>',
|
||||
};
|
||||
const { openView } = await start({
|
||||
mockRPC(route, args) {
|
||||
if (args.method === 'read') {
|
||||
assert.step(`read ${args.model} ${args.args[0]}`);
|
||||
}
|
||||
},
|
||||
serverData: { views },
|
||||
services: {
|
||||
notification: makeFakeNotificationService(message => {
|
||||
assert.ok(
|
||||
true,
|
||||
"should display a toast notification after failing to open chat"
|
||||
);
|
||||
assert.strictEqual(
|
||||
message,
|
||||
"You can only chat with employees that have a dedicated user.",
|
||||
"should display the correct information in the notification"
|
||||
);
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
await openView({
|
||||
res_model: 'm2x.avatar.employee',
|
||||
res_id: m2xHrAvatarUserId1,
|
||||
views: [[false, 'form']],
|
||||
});
|
||||
assert.strictEqual(document.querySelector('.o_field_widget[name=employee_id] input').value.trim(), 'Mario');
|
||||
|
||||
await dom.click(document.querySelector('.o_m2o_avatar > img'));
|
||||
|
||||
assert.verifySteps([
|
||||
`read m2x.avatar.employee ${m2xHrAvatarUserId1}`,
|
||||
`read hr.employee.public ${hrEmployeePublicId1}`,
|
||||
]);
|
||||
});
|
||||
|
||||
QUnit.test('many2many_avatar_employee widget in form view', async function (assert) {
|
||||
assert.expect(8);
|
||||
|
||||
const pyEnv = await startServer();
|
||||
const [resPartnerId1, resPartnerId2] = pyEnv['res.partner'].create([{}, {}]);
|
||||
const [resUsersId1, resUsersId2] = pyEnv['res.users'].create([{}, {}]);
|
||||
const [hrEmployeePublicId1, hrEmployeePublicId2] = pyEnv['hr.employee.public'].create([
|
||||
{ user_id: resUsersId1, user_partner_id: resPartnerId1 },
|
||||
{ user_id: resUsersId2, user_partner_id: resPartnerId2 },
|
||||
]);
|
||||
const m2xAvatarEmployeeId1 = pyEnv['m2x.avatar.employee'].create(
|
||||
{ employee_ids: [hrEmployeePublicId1, hrEmployeePublicId2] },
|
||||
);
|
||||
const views = {
|
||||
'm2x.avatar.employee,false,form': '<form><field name="employee_ids" widget="many2many_avatar_employee"/></form>',
|
||||
};
|
||||
const { openView } = await start({
|
||||
mockRPC(route, args) {
|
||||
if (args.method === 'read') {
|
||||
assert.step(`read ${args.model} ${args.args[0]}`);
|
||||
}
|
||||
},
|
||||
serverData: { views },
|
||||
});
|
||||
|
||||
await openView({
|
||||
res_model: 'm2x.avatar.employee',
|
||||
res_id: m2xAvatarEmployeeId1,
|
||||
views: [[false, 'form']],
|
||||
});
|
||||
assert.containsN(document.body, '.o_field_many2many_avatar_employee .badge', 2,
|
||||
"should have 2 records");
|
||||
assert.strictEqual(document.querySelector('.o_field_many2many_avatar_employee .badge img').getAttribute('data-src'),
|
||||
`/web/image/hr.employee.public/${hrEmployeePublicId1}/avatar_128`,
|
||||
"should have correct avatar image");
|
||||
|
||||
await dom.click(document.querySelector('.o_field_many2many_avatar_employee .badge .o_m2m_avatar'));
|
||||
await dom.click(document.querySelectorAll('.o_field_many2many_avatar_employee .badge .o_m2m_avatar')[1]);
|
||||
|
||||
assert.verifySteps([
|
||||
`read m2x.avatar.employee ${m2xAvatarEmployeeId1}`,
|
||||
`read hr.employee.public ${hrEmployeePublicId1},${hrEmployeePublicId2}`,
|
||||
`read hr.employee.public ${hrEmployeePublicId1}`,
|
||||
`read hr.employee.public ${hrEmployeePublicId2}`,
|
||||
]);
|
||||
|
||||
assert.containsN(
|
||||
document.body,
|
||||
'.o_ChatWindowHeader_name',
|
||||
2,
|
||||
"should have 2 chat windows"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('many2many_avatar_employee widget in list view', async function (assert) {
|
||||
assert.expect(10);
|
||||
|
||||
const pyEnv = await startServer();
|
||||
const [resPartnerId1, resPartnerId2] = pyEnv['res.partner'].create([
|
||||
{ name: "Mario" },
|
||||
{ name: "Yoshi" },
|
||||
]);
|
||||
const [resUsersId1, resUsersId2] = pyEnv['res.users'].create([{}, {}]);
|
||||
const [hrEmployeePublicId1, hrEmployeePublicId2] = pyEnv['hr.employee.public'].create([
|
||||
{ user_id: resUsersId1, user_partner_id: resPartnerId1 },
|
||||
{ user_id: resUsersId2, user_partner_id: resPartnerId2 },
|
||||
]);
|
||||
pyEnv['m2x.avatar.employee'].create(
|
||||
{ employee_ids: [hrEmployeePublicId1, hrEmployeePublicId2] },
|
||||
);
|
||||
const views = {
|
||||
'm2x.avatar.employee,false,list': '<tree><field name="employee_ids" widget="many2many_avatar_employee"/></tree>',
|
||||
};
|
||||
const { openView } = await start({
|
||||
mockRPC(route, args) {
|
||||
if (args.method === 'read') {
|
||||
assert.step(`read ${args.model} ${args.args[0]}`);
|
||||
}
|
||||
},
|
||||
serverData: { views },
|
||||
});
|
||||
|
||||
await openView({
|
||||
res_model: 'm2x.avatar.employee',
|
||||
views: [[false, 'list']],
|
||||
});
|
||||
assert.containsN(document.body, '.o_data_cell:first .o_field_many2many_avatar_employee > div > span', 2,
|
||||
"should have two avatar");
|
||||
|
||||
// click on first employee badge
|
||||
await afterNextRender(() =>
|
||||
dom.click(document.querySelector('.o_data_cell .o_m2m_avatar'))
|
||||
);
|
||||
assert.verifySteps(
|
||||
[`read hr.employee.public ${hrEmployeePublicId1},${hrEmployeePublicId2}`, `read hr.employee.public ${hrEmployeePublicId1}`],
|
||||
"first employee should have been read to find its partner"
|
||||
);
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
'.o_ChatWindowHeader_name',
|
||||
'should have opened chat window'
|
||||
);
|
||||
assert.strictEqual(
|
||||
document.querySelector('.o_ChatWindowHeader_name').textContent,
|
||||
"Mario",
|
||||
'chat window should be with clicked employee'
|
||||
);
|
||||
|
||||
// click on second employee
|
||||
await afterNextRender(() =>
|
||||
dom.click(document.querySelectorAll('.o_data_cell .o_m2m_avatar')[1])
|
||||
);
|
||||
assert.verifySteps(
|
||||
[`read hr.employee.public ${hrEmployeePublicId2}`],
|
||||
"second employee should have been read to find its partner"
|
||||
);
|
||||
assert.containsN(
|
||||
document.body,
|
||||
'.o_ChatWindowHeader_name',
|
||||
2,
|
||||
'should have opened second chat window'
|
||||
);
|
||||
assert.strictEqual(
|
||||
document.querySelectorAll('.o_ChatWindowHeader_name')[1].textContent,
|
||||
"Yoshi",
|
||||
'chat window should be with clicked employee'
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('many2many_avatar_employee widget in kanban view', async function (assert) {
|
||||
assert.expect(7);
|
||||
|
||||
const pyEnv = await startServer();
|
||||
const [resPartnerId1, resPartnerId2] = pyEnv['res.partner'].create([{}, {}]);
|
||||
const [resUsersId1, resUsersId2] = pyEnv['res.users'].create([{}, {}]);
|
||||
const [hrEmployeePublicId1, hrEmployeePublicId2] = pyEnv['hr.employee.public'].create([
|
||||
{ user_id: resUsersId1, user_partner_id: resPartnerId1 },
|
||||
{ user_id: resUsersId2, user_partner_id: resPartnerId2 },
|
||||
]);
|
||||
pyEnv['m2x.avatar.employee'].create(
|
||||
{ employee_ids: [hrEmployeePublicId1, hrEmployeePublicId2] },
|
||||
);
|
||||
const views = {
|
||||
'm2x.avatar.employee,false,kanban':
|
||||
`<kanban>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div>
|
||||
<div class="oe_kanban_footer">
|
||||
<div class="o_kanban_record_bottom">
|
||||
<div class="oe_kanban_bottom_right">
|
||||
<field name="employee_ids" widget="many2many_avatar_employee"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>`,
|
||||
};
|
||||
const { openView } = await start({
|
||||
mockRPC(route, args) {
|
||||
if (args.method === 'read') {
|
||||
assert.step(`read ${args.model} ${args.args[0]}`);
|
||||
}
|
||||
},
|
||||
serverData: { views },
|
||||
});
|
||||
|
||||
await openView({
|
||||
res_model: 'm2x.avatar.employee',
|
||||
views: [[false, 'kanban']],
|
||||
});
|
||||
assert.containsN(document.body, '.o_kanban_record:first .o_field_many2many_avatar_employee img.o_m2m_avatar', 2,
|
||||
"should have 2 avatar images");
|
||||
assert.strictEqual(document.querySelector('.o_kanban_record .o_field_many2many_avatar_employee img.o_m2m_avatar').getAttribute('data-src'),
|
||||
`/web/image/hr.employee.public/${hrEmployeePublicId1}/avatar_128`,
|
||||
"should have correct avatar image");
|
||||
assert.strictEqual(document.querySelectorAll('.o_kanban_record .o_field_many2many_avatar_employee img.o_m2m_avatar')[1].getAttribute('data-src'),
|
||||
`/web/image/hr.employee.public/${hrEmployeePublicId2}/avatar_128`,
|
||||
"should have correct avatar image");
|
||||
|
||||
await dom.click(document.querySelector('.o_kanban_record .o_m2m_avatar'));
|
||||
await dom.click(document.querySelectorAll('.o_kanban_record .o_m2m_avatar')[1]);
|
||||
|
||||
assert.verifySteps([
|
||||
`read hr.employee.public ${hrEmployeePublicId1},${hrEmployeePublicId2}`,
|
||||
`read hr.employee.public ${hrEmployeePublicId1}`,
|
||||
`read hr.employee.public ${hrEmployeePublicId2}`
|
||||
]);
|
||||
});
|
||||
|
||||
QUnit.test('many2many_avatar_employee: click on an employee not associated with a user', async function (assert) {
|
||||
assert.expect(10);
|
||||
|
||||
const pyEnv = await startServer();
|
||||
const resPartnerId1 = pyEnv['res.partner'].create({});
|
||||
const resUsersId1 = pyEnv['res.users'].create({});
|
||||
const [hrEmployeePublicId1, hrEmployeePublicId2] = pyEnv['hr.employee.public'].create([
|
||||
{},
|
||||
{ user_id: resUsersId1, user_partner_id: resPartnerId1 },
|
||||
]);
|
||||
const m2xAvatarEmployeeId1 = pyEnv['m2x.avatar.employee'].create(
|
||||
{ employee_ids: [hrEmployeePublicId1, hrEmployeePublicId2] },
|
||||
);
|
||||
const views = {
|
||||
'm2x.avatar.employee,false,form': '<form><field name="employee_ids" widget="many2many_avatar_employee"/></form>',
|
||||
};
|
||||
const { openView } = await start({
|
||||
mockRPC(route, args) {
|
||||
if (args.method === 'read') {
|
||||
assert.step(`read ${args.model} ${args.args[0]}`);
|
||||
}
|
||||
},
|
||||
serverData: { views },
|
||||
services: {
|
||||
notification: makeFakeNotificationService(message => {
|
||||
assert.ok(
|
||||
true,
|
||||
"should display a toast notification after failing to open chat"
|
||||
);
|
||||
assert.strictEqual(
|
||||
message,
|
||||
"You can only chat with employees that have a dedicated user.",
|
||||
"should display the correct information in the notification"
|
||||
);
|
||||
}),
|
||||
},
|
||||
});
|
||||
await openView({
|
||||
res_model: 'm2x.avatar.employee',
|
||||
res_id: m2xAvatarEmployeeId1,
|
||||
views: [[false, 'form']],
|
||||
});
|
||||
|
||||
assert.containsN(document.body, '.o_field_many2many_avatar_employee .badge', 2,
|
||||
"should have 2 records");
|
||||
assert.strictEqual(document.querySelector('.o_field_many2many_avatar_employee .badge img').getAttribute('data-src'),
|
||||
`/web/image/hr.employee.public/${hrEmployeePublicId1}/avatar_128`,
|
||||
"should have correct avatar image");
|
||||
|
||||
await dom.click(document.querySelector('.o_field_many2many_avatar_employee .badge .o_m2m_avatar'));
|
||||
await dom.click(document.querySelectorAll('.o_field_many2many_avatar_employee .badge .o_m2m_avatar')[1]);
|
||||
|
||||
assert.verifySteps([
|
||||
`read m2x.avatar.employee ${hrEmployeePublicId1}`,
|
||||
`read hr.employee.public ${hrEmployeePublicId1},${hrEmployeePublicId2}`,
|
||||
`read hr.employee.public ${hrEmployeePublicId1}`,
|
||||
`read hr.employee.public ${hrEmployeePublicId2}`
|
||||
]);
|
||||
|
||||
assert.containsOnce(document.body, '.o_ChatWindowHeader_name',
|
||||
"should have 1 chat window");
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import { fields, models } from "@web/../tests/web_test_helpers";
|
||||
|
||||
export class FakeUser extends models.Model {
|
||||
_name = "fake.user";
|
||||
|
||||
name = fields.Char({ string: "Name" });
|
||||
lang = fields.Char({ string: "Lang" });
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
import { models, fields } from "@web/../tests/web_test_helpers";
|
||||
|
||||
export class HrDepartment extends models.ServerModel {
|
||||
_name = "hr.department";
|
||||
_rec_name = "complete_name";
|
||||
|
||||
name = fields.Char();
|
||||
complete_name = fields.Char({
|
||||
compute: "_compute_complete_name",
|
||||
});
|
||||
display_name = fields.Char({
|
||||
compute: "_compute_display_name",
|
||||
});
|
||||
|
||||
_compute_complete_name() {
|
||||
for (const department of this) {
|
||||
department.complete_name = department.name;
|
||||
}
|
||||
}
|
||||
|
||||
_compute_display_name() {
|
||||
this._compute_complete_name();
|
||||
for (const department of this) {
|
||||
department.display_name = department.complete_name;
|
||||
}
|
||||
}
|
||||
|
||||
get _to_store_defaults() {
|
||||
return ["name"];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import { fields, models } from "@web/../tests/web_test_helpers";
|
||||
import { mailDataHelpers } from "@mail/../tests/mock_server/mail_mock_server";
|
||||
|
||||
export class HrEmployee extends models.ServerModel {
|
||||
_name = "hr.employee";
|
||||
|
||||
department_id = fields.Many2one({ relation: "hr.department" });
|
||||
work_email = fields.Char();
|
||||
work_phone = fields.Char();
|
||||
work_location_type = fields.Char();
|
||||
work_location_id = fields.Many2one({ relation: "hr.work.location" });
|
||||
job_title = fields.Char();
|
||||
|
||||
_get_store_avatar_card_fields() {
|
||||
return [
|
||||
"company_id",
|
||||
mailDataHelpers.Store.one("department_id", ["name"]),
|
||||
"work_email",
|
||||
mailDataHelpers.Store.one("work_location_id", ["location_type", "name"]),
|
||||
"work_phone",
|
||||
"job_title",
|
||||
];
|
||||
}
|
||||
|
||||
_views = {
|
||||
search: `<search><field name="display_name" string="Name" /></search>`,
|
||||
list: `<list><field name="display_name"/></list>`,
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import { models } from "@web/../tests/web_test_helpers";
|
||||
|
||||
export class HrEmployeePublic extends models.ServerModel {
|
||||
_name = "hr.employee.public";
|
||||
|
||||
_views = {
|
||||
search: `<search><field name="display_name" string="Name" /></search>`,
|
||||
list: `<list><field name="display_name"/></list>`,
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import { models } from "@web/../tests/web_test_helpers";
|
||||
|
||||
export class HrJob extends models.ServerModel {
|
||||
_name = "hr.job";
|
||||
|
||||
_views = {
|
||||
search: `<search><field name="display_name" string="Name" /></search>`,
|
||||
list: `<list><field name="display_name"/></list>`,
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import { models } from "@web/../tests/web_test_helpers";
|
||||
|
||||
export class HrVersion extends models.ServerModel {
|
||||
_name = "hr.version";
|
||||
|
||||
_views = {
|
||||
search: `<search><field name="display_name" string="Name" /></search>`,
|
||||
list: `<list><field name="display_name"/></list>`,
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import { models, fields } from "@web/../tests/web_test_helpers";
|
||||
|
||||
export class HrWorkLocation extends models.ServerModel {
|
||||
_name = "hr.work.location";
|
||||
|
||||
name = fields.Char();
|
||||
location_type = fields.Selection({
|
||||
selection: [
|
||||
["office", "Office"],
|
||||
["home", "Home"],
|
||||
["other", "Other"],
|
||||
],
|
||||
});
|
||||
|
||||
_views = {
|
||||
search: `<search><field name="display_name" string="Name" /></search>`,
|
||||
list: `<list><field name="display_name"/></list>`,
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import { fields, models } from "@web/../tests/web_test_helpers";
|
||||
|
||||
export class M2xAvatarEmployee extends models.Model {
|
||||
_name = "m2x.avatar.employee";
|
||||
|
||||
employee_id = fields.Many2one({ string: "Employee", relation: "hr.employee.public" });
|
||||
employee_ids = fields.Many2many({ string: "Employees", relation: "hr.employee.public" });
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import { mailModels } from "@mail/../tests/mail_test_helpers";
|
||||
import { fields, makeKwArgs } from "@web/../tests/web_test_helpers";
|
||||
import { mailDataHelpers } from "@mail/../tests/mock_server/mail_mock_server";
|
||||
|
||||
export class ResPartner extends mailModels.ResPartner {
|
||||
employee_ids = fields.One2many({
|
||||
relation: "hr.employee",
|
||||
inverse: "work_contact_id",
|
||||
});
|
||||
|
||||
_get_store_avatar_card_fields() {
|
||||
return [
|
||||
...super._get_store_avatar_card_fields(),
|
||||
mailDataHelpers.Store.many(
|
||||
"employee_ids",
|
||||
makeKwArgs({
|
||||
fields: this.env["hr.employee"]._get_store_avatar_card_fields(),
|
||||
mode: "ADD",
|
||||
})
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
import { mailModels } from "@mail/../tests/mail_test_helpers";
|
||||
import { fields } from "@web/../tests/web_test_helpers";
|
||||
|
||||
export class ResUsers extends mailModels.ResUsers {
|
||||
employee_id = fields.Many2one({ relation: "hr.employee" });
|
||||
employee_ids = fields.One2many({
|
||||
relation: "hr.employee",
|
||||
inverse: "user_id",
|
||||
});
|
||||
department_id = fields.Many2one({
|
||||
related: "employee_id.department_id",
|
||||
relation: "hr.department",
|
||||
});
|
||||
work_email = fields.Char({ related: "employee_id.work_email" });
|
||||
work_phone = fields.Char({ related: "employee_id.work_phone" });
|
||||
work_location_type = fields.Char({ related: "employee_id.work_location_type" });
|
||||
work_location_id = fields.Many2one({
|
||||
related: "employee_id.work_location_id",
|
||||
relation: "hr.work.location",
|
||||
});
|
||||
job_title = fields.Char({ related: "employee_id.job_title" });
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import { onRpc } from "@web/../tests/web_test_helpers";
|
||||
|
||||
onRpc("get_avatar_card_data", function getAvatarCardData({ args }) {
|
||||
const resourceId = args[0][0];
|
||||
const resources = this.env["hr.employee.public"].search_read([["id", "=", resourceId]]);
|
||||
return resources.map((resource) => ({
|
||||
name: resource.name,
|
||||
work_email: resource.work_email,
|
||||
phone: resource.phone,
|
||||
user_id: resource.user_id,
|
||||
}));
|
||||
});
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
import {
|
||||
clickSave,
|
||||
contains,
|
||||
makeMockServer,
|
||||
mockService,
|
||||
mountView,
|
||||
} from "@web/../tests/web_test_helpers";
|
||||
import { describe, expect, test } from "@odoo/hoot";
|
||||
import { defineHrModels } from "@hr/../tests/hr_test_helpers";
|
||||
|
||||
describe.current.tags("desktop");
|
||||
defineHrModels();
|
||||
|
||||
test("editing the 'lang' field and saving it triggers a 'reload_context'", async function () {
|
||||
const { env } = await makeMockServer();
|
||||
const userId = env["fake.user"].create({
|
||||
name: "Aline",
|
||||
lang: "fr",
|
||||
});
|
||||
mockService("action", {
|
||||
doAction(action) {
|
||||
expect.step(action);
|
||||
},
|
||||
});
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "fake.user",
|
||||
arch: `
|
||||
<form js_class="hr_user_preferences_form">
|
||||
<field name="name"/>
|
||||
<field name="lang"/>
|
||||
</form>`,
|
||||
resId: userId,
|
||||
});
|
||||
await contains("[name='name'] input").edit("John");
|
||||
await clickSave();
|
||||
expect.verifySteps([]);
|
||||
await contains("[name='lang'] input").edit("En");
|
||||
await clickSave();
|
||||
expect.verifySteps(["reload_context"]);
|
||||
});
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
|
||||
import AbstractRendererOwl from 'web.AbstractRendererOwl';
|
||||
import BasicView from "web.BasicView";
|
||||
import BasicRenderer from "web.BasicRenderer";
|
||||
import RendererWrapper from 'web.RendererWrapper';
|
||||
import { createView } from 'web.test_utils';
|
||||
|
||||
import StandaloneM2OAvatarEmployee from '@hr/js/standalone_m2o_avatar_employee';
|
||||
|
||||
const { xml } = owl;
|
||||
|
||||
function getHtmlRenderer(html) {
|
||||
return BasicRenderer.extend({
|
||||
start: function () {
|
||||
this.$el.html(html);
|
||||
return this._super.apply(this, arguments);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getOwlView(owlRenderer, viewType) {
|
||||
viewType = viewType || "test";
|
||||
return BasicView.extend({
|
||||
viewType: viewType,
|
||||
config: Object.assign({}, BasicView.prototype.config, {
|
||||
Renderer: owlRenderer,
|
||||
}),
|
||||
getRenderer() {
|
||||
return new RendererWrapper(null, this.config.Renderer, {});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getHtmlView(html, viewType) {
|
||||
viewType = viewType || "test";
|
||||
return BasicView.extend({
|
||||
viewType: viewType,
|
||||
config: Object.assign({}, BasicView.prototype.config, {
|
||||
Renderer: getHtmlRenderer(html)
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
QUnit.module('hr', {}, function () {
|
||||
QUnit.module('StandaloneM2OEmployeeTests', {
|
||||
beforeEach: function () {
|
||||
this.data = {
|
||||
'foo': {
|
||||
fields: {
|
||||
employee_id: {string: "Employee", type: 'many2one', relation: 'hr.employee'},
|
||||
},
|
||||
records: [],
|
||||
},
|
||||
'hr.employee': {
|
||||
fields: {},
|
||||
records: [
|
||||
{id: 10, name: "Mario"},
|
||||
{id: 20, name: "Luigi"},
|
||||
{id: 30, name: "Yoshi"}
|
||||
],
|
||||
},
|
||||
'hr.employee.public': {
|
||||
fields: {},
|
||||
records: [
|
||||
{id: 10, name: "Mario"},
|
||||
{id: 20, name: "Luigi"},
|
||||
{id: 30, name: "Yoshi"}
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test('standalone_m2o_avatar_employee: legacy view', async function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
const html = "<div class='coucou_test'></div>";
|
||||
const view = await createView({
|
||||
View: getHtmlView(html, "test"),
|
||||
data: this.data,
|
||||
model: "foo",
|
||||
arch: "<test/>"
|
||||
});
|
||||
|
||||
const avatar10 = new StandaloneM2OAvatarEmployee(view, 10);
|
||||
const avatar20 = new StandaloneM2OAvatarEmployee(view, 20);
|
||||
const avatar30 = new StandaloneM2OAvatarEmployee(view, [30, 'Bowser']);
|
||||
|
||||
await avatar10.appendTo(view.el.querySelector('.coucou_test'));
|
||||
await avatar20.appendTo(view.el.querySelector('.coucou_test'));
|
||||
await avatar30.appendTo(view.el.querySelector('.coucou_test'));
|
||||
|
||||
assert.deepEqual(
|
||||
[...view.el.querySelectorAll('.o_field_many2one_avatar span')].map(el => el.innerText),
|
||||
["Mario", "Luigi", "Bowser"]
|
||||
);
|
||||
|
||||
view.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('standalone_m2o_avatar_employee: Owl view', async function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
class Renderer extends AbstractRendererOwl { }
|
||||
Renderer.template = xml`<div class='coucou_test'></div>`;
|
||||
|
||||
const view = await createView({
|
||||
View: getOwlView(Renderer, "test"),
|
||||
data: this.data,
|
||||
model: "foo",
|
||||
arch: "<test/>"
|
||||
});
|
||||
|
||||
const avatar10 = new StandaloneM2OAvatarEmployee(view, 10);
|
||||
const avatar20 = new StandaloneM2OAvatarEmployee(view, 20);
|
||||
const avatar30 = new StandaloneM2OAvatarEmployee(view, [30, 'Bowser']);
|
||||
|
||||
await avatar10.appendTo(view.el.querySelector('.coucou_test'));
|
||||
await avatar20.appendTo(view.el.querySelector('.coucou_test'));
|
||||
await avatar30.appendTo(view.el.querySelector('.coucou_test'));
|
||||
|
||||
assert.deepEqual(
|
||||
[...view.el.querySelectorAll('.o_field_many2one_avatar span')].map(el => el.innerText),
|
||||
["Mario", "Luigi", "Bowser"]
|
||||
);
|
||||
|
||||
view.destroy();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import { registry } from "@web/core/registry";
|
||||
|
||||
registry.category("web_tour.tours").add("check_public_employee_link_redirect", {
|
||||
// starts at /odoo/employee/<employee_id>
|
||||
steps: () => {
|
||||
/* ignoring inactive modals since the modal may appear multiple times
|
||||
thus hiding the inactive ones and playwright doesn't like doing
|
||||
actions on hidden elements */
|
||||
const msgSelector = '.o_dialog:not(.o_inactive_modal) .modal-content .modal-body div[role="alert"] p';
|
||||
const msg = `You are not allowed to access "Employee" (hr.employee) records.
|
||||
We can redirect you to the public employee list.`;
|
||||
return [
|
||||
{
|
||||
trigger: msgSelector,
|
||||
content: "See if redirect warning popup appears for current user",
|
||||
timeout: 3000,
|
||||
run: () => {
|
||||
const errorTxt = document.querySelector(msgSelector).innerText;
|
||||
if (errorTxt !== msg) {
|
||||
throw new Error("Could not find correct warning message when visiting private employee without required permissions")
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -1,29 +1,37 @@
|
|||
/** @odoo-module **/
|
||||
import { registry } from "@web/core/registry";
|
||||
import { stepUtils } from "@web_tour/tour_utils";
|
||||
|
||||
import tour from 'web_tour.tour';
|
||||
|
||||
tour.register('hr_employee_tour', {
|
||||
test: true,
|
||||
url: '/web',
|
||||
}, [
|
||||
tour.stepUtils.showAppsMenuItem(),
|
||||
{
|
||||
content: "Open Employees app",
|
||||
trigger: ".o_app[data-menu-xmlid='hr.menu_hr_root']",
|
||||
run: 'click',
|
||||
},
|
||||
{
|
||||
content: "Open an Employee Profile",
|
||||
trigger: ".o_kanban_record_title:contains('Johnny H.')",
|
||||
run: 'click',
|
||||
},
|
||||
{
|
||||
content: "Open user account menu",
|
||||
trigger: ".o_user_menu .oe_topbar_name",
|
||||
run: 'click',
|
||||
}, {
|
||||
content: "Open My Profile",
|
||||
trigger: "[data-menu=settings]",
|
||||
run: 'click',
|
||||
},
|
||||
]);
|
||||
registry.category("web_tour.tours").add("hr_employee_tour", {
|
||||
url: "/odoo",
|
||||
steps: () => [
|
||||
stepUtils.showAppsMenuItem(),
|
||||
{
|
||||
content: "Open Employees app",
|
||||
trigger: ".o_app[data-menu-xmlid='hr.menu_hr_root']",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Open an Employee Profile",
|
||||
trigger: ".o_kanban_record:contains('Johnny H.')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Open a chat with the employee",
|
||||
trigger: ".o_employee_chat_btn",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
trigger: ".o-mail-ChatWindow .o-mail-ChatWindow-header:contains('Johnny H.')",
|
||||
},
|
||||
{
|
||||
content: "Open user account menu",
|
||||
trigger: ".o_user_menu .dropdown-toggle",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Open My Preferences",
|
||||
trigger: "[data-menu=preferences]",
|
||||
run: "click",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,78 @@
|
|||
import { registry } from "@web/core/registry";
|
||||
import { stepUtils } from "@web_tour/tour_utils";
|
||||
|
||||
registry.category("web_tour.tours").add("hr_employee_multiple_bank_accounts_tour", {
|
||||
url: "/odoo",
|
||||
steps: () => [
|
||||
stepUtils.showAppsMenuItem(),
|
||||
{
|
||||
content: "Open Employees app",
|
||||
trigger: ".o_app[data-menu-xmlid='hr.menu_hr_root']",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Open an Employee Profile",
|
||||
trigger: ".o_kanban_record:contains('Johnny H.')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Open personal tab",
|
||||
trigger: ".nav-link:contains('Personal')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "add bank 1",
|
||||
trigger: "input#bank_account_ids_2",
|
||||
run: "edit 1",
|
||||
},
|
||||
{
|
||||
content: "add bank 1",
|
||||
trigger: ".dropdown-item:contains('Create and edit')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "save bank 1",
|
||||
trigger: ".o_form_button_save:contains('Save')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "add bank 2",
|
||||
trigger: "input#bank_account_ids_2",
|
||||
run: "edit 2",
|
||||
},
|
||||
{
|
||||
content: "add bank 2",
|
||||
trigger: ".dropdown-item:contains('Create and edit')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "save",
|
||||
trigger: ".o_form_button_save:contains('Save')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "add bank 3",
|
||||
trigger: "input#bank_account_ids_1",
|
||||
run: "edit 3",
|
||||
},
|
||||
{
|
||||
content: "add bank 3",
|
||||
trigger: ".dropdown-item:contains('Create and edit')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "save bank 3",
|
||||
trigger: ".o_form_button_save:contains('Save')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "save employee form",
|
||||
trigger: ".fa-cloud-upload",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "wait for save completion",
|
||||
trigger: ".o_form_readonly, .o_form_saved",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import tour from 'web_tour.tour';
|
||||
|
||||
/**
|
||||
* As 'hr' changes the flow a bit and displays the user preferences form in a full view instead of
|
||||
* a modal, we adapt the steps of the original tour accordingly.
|
||||
*/
|
||||
tour.tours['mail/static/tests/tours/user_modify_own_profile_tour.js'].steps = [{
|
||||
content: 'Open user account menu',
|
||||
trigger: '.o_user_menu button',
|
||||
}, {
|
||||
content: "Open preferences / profile screen",
|
||||
trigger: '[data-menu=settings]',
|
||||
}, {
|
||||
content: "Update the email address",
|
||||
trigger: 'div[name="email"] input',
|
||||
run: 'text updatedemail@example.com',
|
||||
}, ...tour.stepUtils.saveForm()];
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
import { registry } from "@web/core/registry";
|
||||
import { stepUtils } from "@web_tour/tour_utils";
|
||||
|
||||
registry.category("web_tour.tours").add("version_timeline_auto_save_tour", {
|
||||
url: "/odoo",
|
||||
steps: () => [
|
||||
stepUtils.showAppsMenuItem(),
|
||||
{
|
||||
content: "Open Employees app",
|
||||
trigger: ".o_app[data-menu-xmlid='hr.menu_hr_root']",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Open an Employee Profile",
|
||||
trigger: ".o_kanban_record:contains('Bob M.')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Open Payroll Page",
|
||||
trigger: ".o_notebook_headers a[name='payroll_information']",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Open contract end date",
|
||||
trigger: ".o_field_widget[name='contract_date_end'] .o_input",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Go to the next month",
|
||||
trigger: ".o_next",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Choose date X + 1",
|
||||
trigger: ".o_date_item_cell:nth-child(11) > div",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Open Create New Version",
|
||||
trigger: ".o_field_widget[name='version_id'] > .o_arrow_button_wrapper > button",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Go to the next month",
|
||||
trigger: ".o_next",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Choose date X + 2",
|
||||
trigger: ".o_date_item_cell:nth-child(12) > div",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Wait until the form is saved",
|
||||
trigger: "body .o_form_saved",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
import { describe, expect, test } from "@odoo/hoot";
|
||||
import { queryAllTexts } from "@odoo/hoot-dom";
|
||||
import { contains, makeMockServer, mountView } from "@web/../tests/web_test_helpers";
|
||||
import { contains as mailContains } from "@mail/../tests/mail_test_helpers";
|
||||
import { defineHrModels } from "@hr/../tests/hr_test_helpers";
|
||||
|
||||
describe.current.tags("desktop");
|
||||
defineHrModels();
|
||||
|
||||
test("avatar card preview with hr", async () => {
|
||||
const { env } = await makeMockServer();
|
||||
const departmentId = env["hr.department"].create({
|
||||
name: "Management",
|
||||
complete_name: "Management",
|
||||
});
|
||||
const partnerId = env["res.partner"].create({
|
||||
name: "Mario",
|
||||
email: "Mario@odoo.test",
|
||||
phone: "+7878698799",
|
||||
});
|
||||
const jobId = env["hr.job"].create({
|
||||
name: "sub manager",
|
||||
});
|
||||
const workLocationId = env["hr.work.location"].create({
|
||||
name: "Odoo",
|
||||
location_type: "office",
|
||||
});
|
||||
const versionId = env["hr.version"].create({
|
||||
job_id: jobId,
|
||||
work_location_id: workLocationId,
|
||||
department_id: departmentId,
|
||||
});
|
||||
const employeeId = env["hr.employee"].create({
|
||||
version_id: versionId,
|
||||
work_email: "Mario@odoo.pro",
|
||||
work_location_type: "office",
|
||||
work_phone: "+585555555",
|
||||
});
|
||||
const userId = env["res.users"].create({
|
||||
partner_id: partnerId,
|
||||
im_status: "online",
|
||||
employee_id: employeeId,
|
||||
employee_ids: [employeeId],
|
||||
});
|
||||
env["hr.employee"].write(employeeId, {
|
||||
user_id: userId,
|
||||
work_contact_id: partnerId,
|
||||
});
|
||||
env["m2x.avatar.user"].create({ user_id: userId });
|
||||
await mountView({
|
||||
type: "kanban",
|
||||
resModel: "m2x.avatar.user",
|
||||
arch: `<kanban>
|
||||
<templates>
|
||||
<t t-name="card">
|
||||
<field name="user_id" widget="many2one_avatar_user"/>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>`,
|
||||
});
|
||||
await contains(".o_m2o_avatar > img").click();
|
||||
await mailContains(".o_avatar_card");
|
||||
await mailContains(".o_avatar_card span[data-tooltip='Work Location'] .fa-building-o");
|
||||
expect(queryAllTexts(".o_card_user_infos > *:not(.o_avatar_card_buttons)")).toEqual([
|
||||
"Mario",
|
||||
"Management",
|
||||
"Mario@odoo.pro",
|
||||
"+585555555",
|
||||
"Odoo",
|
||||
]);
|
||||
await contains(".o_action_manager:eq(0)").click();
|
||||
await mailContains(".o_avatar_card", { count: 0 });
|
||||
});
|
||||
|
||||
test("avatar card preview with hr (partner_id field)", async () => {
|
||||
const { env } = await makeMockServer();
|
||||
const departmentId = env["hr.department"].create({
|
||||
name: "Management",
|
||||
complete_name: "Management",
|
||||
});
|
||||
const partnerId = env["res.partner"].create({
|
||||
name: "Mario",
|
||||
email: "Mario@odoo.test",
|
||||
phone: "+7878698799",
|
||||
});
|
||||
const jobId = env["hr.job"].create({
|
||||
name: "sub manager",
|
||||
});
|
||||
const workLocationId = env["hr.work.location"].create({
|
||||
name: "Odoo",
|
||||
location_type: "office",
|
||||
});
|
||||
const versionId = env["hr.version"].create({
|
||||
job_id: jobId,
|
||||
work_location_id: workLocationId,
|
||||
department_id: departmentId,
|
||||
});
|
||||
const employeeId = env["hr.employee"].create({
|
||||
version_id: versionId,
|
||||
work_email: "Mario@odoo.pro",
|
||||
work_location_type: "office",
|
||||
work_phone: "+585555555",
|
||||
});
|
||||
env["hr.employee"].write(employeeId, {
|
||||
work_contact_id: partnerId,
|
||||
});
|
||||
env["m2x.avatar.user"].create({ partner_id: partnerId });
|
||||
await mountView({
|
||||
type: "kanban",
|
||||
resModel: "m2x.avatar.user",
|
||||
arch: `<kanban>
|
||||
<templates>
|
||||
<t t-name="card">
|
||||
<field name="partner_id" widget="many2one_avatar_user"/>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>`,
|
||||
});
|
||||
await contains(".o_m2o_avatar > img").click();
|
||||
await mailContains(".o_avatar_card");
|
||||
await mailContains(".o_avatar_card span[data-tooltip='Work Location'] .fa-building-o");
|
||||
expect(queryAllTexts(".o_card_user_infos > *:not(.o_avatar_card_buttons)")).toEqual([
|
||||
"Mario",
|
||||
"Management",
|
||||
"Mario@odoo.pro",
|
||||
"+585555555",
|
||||
"Odoo",
|
||||
]);
|
||||
await contains(".o_action_manager:eq(0)").click();
|
||||
await mailContains(".o_avatar_card", { count: 0 });
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue