mirror of
https://github.com/bringout/oca-ocb-hr.git
synced 2026-04-25 11:52:00 +02:00
19.0 vanilla
This commit is contained in:
parent
a1137a1456
commit
e1d89e11e3
2789 changed files with 1093187 additions and 605897 deletions
|
|
@ -0,0 +1,33 @@
|
|||
import { describe, test } from "@odoo/hoot";
|
||||
import { Command, serverState } from "@web/../tests/web_test_helpers";
|
||||
import { contains, openDiscuss, start, startServer } from "@mail/../tests/mail_test_helpers";
|
||||
import { defineHrHolidaysModels } from "@hr_holidays/../tests/hr_holidays_test_helpers";
|
||||
|
||||
describe.current.tags("desktop");
|
||||
defineHrHolidaysModels();
|
||||
|
||||
test("on leave members are categorised correctly in online/offline", async () => {
|
||||
const pyEnv = await startServer();
|
||||
const [partnerId1, partnerId2, partnerId3] = pyEnv["res.partner"].create([
|
||||
{ name: "Online Partner", im_status: "online" },
|
||||
{ name: "On Leave Online", im_status: "online" },
|
||||
{ name: "On Leave Idle", im_status: "away" },
|
||||
]);
|
||||
pyEnv["res.users"].write([serverState.userId], { leave_date_to: "2023-01-02" });
|
||||
pyEnv["res.users"].create({ partner_id: partnerId2, leave_date_to: "2023-01-03" });
|
||||
pyEnv["res.users"].create({ partner_id: partnerId3, leave_date_to: "2023-01-04" });
|
||||
const channelId = pyEnv["discuss.channel"].create({
|
||||
name: "TestChanel",
|
||||
channel_member_ids: [
|
||||
Command.create({ partner_id: serverState.partnerId }),
|
||||
Command.create({ partner_id: partnerId1 }),
|
||||
Command.create({ partner_id: partnerId2 }),
|
||||
Command.create({ partner_id: partnerId3 }),
|
||||
],
|
||||
channel_type: "channel",
|
||||
});
|
||||
await start();
|
||||
await openDiscuss(channelId);
|
||||
await contains(".o-discuss-ChannelMemberList h6", { text: "Online - 3" });
|
||||
await contains(".o-discuss-ChannelMemberList h6", { text: "Offline - 1" });
|
||||
});
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import '@mail/../tests/helpers/mock_server'; // ensure mail overrides are applied first
|
||||
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { MockServer } from "@web/../tests/helpers/mock_server";
|
||||
|
||||
patch(MockServer.prototype, 'hr_holidays', {
|
||||
/**
|
||||
* Overrides to add out of office to employees.
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
_mockResPartnerMailPartnerFormat(ids) {
|
||||
const partnerFormats = this._super(...arguments);
|
||||
const partners = this.getRecords(
|
||||
'res.partner',
|
||||
[['id', 'in', ids]],
|
||||
{ active_test: false },
|
||||
);
|
||||
for (const partner of partners) {
|
||||
// Not a real field but ease the testing
|
||||
partnerFormats.get(partner.id).out_of_office_date_end = partner.out_of_office_date_end;
|
||||
}
|
||||
return partnerFormats;
|
||||
},
|
||||
});
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import { insertModelFields } from '@bus/../tests/helpers/model_definitions_helpers';
|
||||
|
||||
insertModelFields('res.partner', {
|
||||
out_of_office_date_end: { type: 'date' },
|
||||
});
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
import { defineModels } from "@web/../tests/web_test_helpers";
|
||||
import { ResUsers } from "@hr_holidays/../tests/mock_server/mock_models/res_users";
|
||||
import { ResPartner } from "@hr_holidays/../tests/mock_server/mock_models/res_partner";
|
||||
import { HrEmployee } from "@hr_holidays/../tests/mock_server/mock_models/hr_employee";
|
||||
import { HrLeave } from "@hr_holidays/../tests/mock_server/mock_models/hr_leave";
|
||||
import { HrDepartment } from "@hr_holidays/../tests/mock_server/mock_models/hr_department";
|
||||
import { HrLeaveType } from "@hr_holidays/../tests/mock_server/mock_models/hr_leave_type";
|
||||
import { hrModels } from "@hr/../tests/hr_test_helpers";
|
||||
|
||||
export function defineHrHolidaysModels() {
|
||||
return defineModels(hrHolidaysModels);
|
||||
}
|
||||
|
||||
export const hrHolidaysModels = {
|
||||
...hrModels,
|
||||
ResUsers,
|
||||
ResPartner,
|
||||
HrEmployee,
|
||||
HrDepartment,
|
||||
HrLeaveType,
|
||||
HrLeave,
|
||||
};
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
import { describe, test } from "@odoo/hoot";
|
||||
|
||||
import { Store } from "@mail/core/common/store_service";
|
||||
import { startServer, start, openDiscuss, contains } from "@mail/../tests/mail_test_helpers";
|
||||
|
||||
import { serverState, patchWithCleanup } from "@web/../tests/web_test_helpers";
|
||||
import { defineHrHolidaysModels } from "@hr_holidays/../tests/hr_holidays_test_helpers";
|
||||
|
||||
describe.current.tags("desktop");
|
||||
defineHrHolidaysModels();
|
||||
|
||||
test("change icon on change partner im_status for leave variants", async () => {
|
||||
const pyEnv = await startServer();
|
||||
pyEnv["res.partner"].write([serverState.partnerId], { im_status: "online" });
|
||||
pyEnv["res.users"].write([serverState.userId], { leave_date_to: "2023-01-01" });
|
||||
const channelId = pyEnv["discuss.channel"].create({ channel_type: "chat" });
|
||||
patchWithCleanup(Store, { IM_STATUS_DEBOUNCE_DELAY: 0 });
|
||||
await start();
|
||||
await openDiscuss(channelId);
|
||||
await contains(
|
||||
".o-mail-DiscussContent-header .o-mail-ImStatus .fa-plane[title='On Leave (Online)']"
|
||||
);
|
||||
pyEnv["bus.bus"]._sendone("broadcast", "bus.bus/im_status_updated", {
|
||||
partner_id: serverState.partnerId,
|
||||
im_status: "leave_offline",
|
||||
presence_status: "offline",
|
||||
});
|
||||
await contains(".o-mail-DiscussContent-header .o-mail-ImStatus .fa-plane[title='On Leave']");
|
||||
pyEnv["bus.bus"]._sendone("broadcast", "bus.bus/im_status_updated", {
|
||||
partner_id: serverState.partnerId,
|
||||
im_status: "leave_away",
|
||||
presence_status: "away",
|
||||
});
|
||||
await contains(
|
||||
".o-mail-DiscussContent-header .o-mail-ImStatus .fa-plane[title='On Leave (Idle)']"
|
||||
);
|
||||
pyEnv["bus.bus"]._sendone("broadcast", "bus.bus/im_status_updated", {
|
||||
partner_id: serverState.partnerId,
|
||||
im_status: "leave_online",
|
||||
presence_status: "online",
|
||||
});
|
||||
await contains(
|
||||
".o-mail-DiscussContent-header .o-mail-ImStatus .fa-plane[title='On Leave (Online)']"
|
||||
);
|
||||
});
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
import { describe, test } from "@odoo/hoot";
|
||||
import { Command, serverState } from "@web/../tests/web_test_helpers";
|
||||
import { startServer, start, openDiscuss, contains } from "@mail/../tests/mail_test_helpers";
|
||||
import { defineHrHolidaysModels } from "@hr_holidays/../tests/hr_holidays_test_helpers";
|
||||
|
||||
describe.current.tags("desktop");
|
||||
defineHrHolidaysModels();
|
||||
|
||||
test("on leave & online", async () => {
|
||||
const pyEnv = await startServer();
|
||||
const partnerId = pyEnv["res.partner"].create({ name: "Demo", im_status: "online" });
|
||||
pyEnv["res.users"].create({ partner_id: partnerId, leave_date_to: "2023-01-01" });
|
||||
const channelId = pyEnv["discuss.channel"].create({
|
||||
channel_member_ids: [
|
||||
Command.create({ partner_id: serverState.partnerId }),
|
||||
Command.create({ partner_id: partnerId }),
|
||||
],
|
||||
channel_type: "chat",
|
||||
});
|
||||
await start();
|
||||
await openDiscuss(channelId);
|
||||
await contains(
|
||||
".o-mail-DiscussContent-header .o-mail-ImStatus i.fa-plane[title='On Leave (Online)']"
|
||||
);
|
||||
});
|
||||
|
||||
test("on leave & away", async () => {
|
||||
const pyEnv = await startServer();
|
||||
const partnerId = pyEnv["res.partner"].create({ name: "Demo", im_status: "away" });
|
||||
pyEnv["res.users"].create({ partner_id: partnerId, leave_date_to: "2023-01-01" });
|
||||
const channelId = pyEnv["discuss.channel"].create({
|
||||
channel_member_ids: [
|
||||
Command.create({ partner_id: serverState.partnerId }),
|
||||
Command.create({ partner_id: partnerId }),
|
||||
],
|
||||
channel_type: "chat",
|
||||
});
|
||||
await start();
|
||||
await openDiscuss(channelId);
|
||||
await contains(
|
||||
".o-mail-DiscussContent-header .o-mail-ImStatus i.fa-plane[title='On Leave (Idle)']"
|
||||
);
|
||||
});
|
||||
|
||||
test("on leave & offline", async () => {
|
||||
const pyEnv = await startServer();
|
||||
const partnerId = pyEnv["res.partner"].create({ name: "Demo", im_status: "offline" });
|
||||
pyEnv["res.users"].create({ partner_id: partnerId, leave_date_to: "2023-01-01" });
|
||||
const channelId = pyEnv["discuss.channel"].create({
|
||||
channel_member_ids: [
|
||||
Command.create({ partner_id: serverState.partnerId }),
|
||||
Command.create({ partner_id: partnerId }),
|
||||
],
|
||||
channel_type: "chat",
|
||||
});
|
||||
await start();
|
||||
await openDiscuss(channelId);
|
||||
await contains(".o-mail-DiscussContent-header .o-mail-ImStatus i.fa-plane[title='On Leave']");
|
||||
});
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
import { HrLeave } from "@hr_holidays/../tests/mock_server/mock_models/hr_leave";
|
||||
import { ResUsers } from "@hr_holidays/../tests/mock_server/mock_models/res_users";
|
||||
import { defineHrHolidaysModels } from "@hr_holidays/../tests/hr_holidays_test_helpers";
|
||||
import { mountView, onRpc, patchWithCleanup } from "@web/../tests/web_test_helpers";
|
||||
import { clickDate } from "@web/../tests/views/calendar/calendar_test_helpers";
|
||||
import { describe, test } from "@odoo/hoot";
|
||||
import { mockDate } from "@odoo/hoot-mock";
|
||||
import { click, waitFor } from "@odoo/hoot-dom";
|
||||
import { user } from "@web/core/user";
|
||||
|
||||
describe.current.tags("desktop");
|
||||
defineHrHolidaysModels();
|
||||
|
||||
test("Test request creator buttons", async() => {
|
||||
mockDate("2024-01-03 12:00:00", 0);
|
||||
patchWithCleanup(user, { userId: 100 });
|
||||
|
||||
HrLeave._views = {
|
||||
"form,hr_leave_view_form_dashboard_new_time_off": `
|
||||
<form>
|
||||
<field name="state"/>
|
||||
<field name="holiday_status_id"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="user_id"/>
|
||||
<field name="can_cancel"/>
|
||||
</form>
|
||||
`,
|
||||
};
|
||||
|
||||
HrLeave._records = [
|
||||
{
|
||||
'id': 1, 'state': 'confirm', 'holiday_status_id': 55, 'employee_id': 100,
|
||||
'user_id': 100, 'date_from': '2024-01-09 09:00:00', 'date_to': '2024-01-09 18:00:00'
|
||||
},
|
||||
{
|
||||
'id': 2, 'state': 'validate1', 'holiday_status_id': 55, 'employee_id': 100,
|
||||
'can_cancel': true, 'user_id': 100, 'date_from': '2024-01-10 09:00:00', 'date_to': '2024-01-10 18:00:00'
|
||||
},
|
||||
]
|
||||
|
||||
ResUsers._records = [
|
||||
...ResUsers._records,
|
||||
{ 'id': 100, 'name': "User 1", 'employee_id': 100 },
|
||||
]
|
||||
|
||||
onRpc("get_mandatory_days", () => ({}));
|
||||
onRpc("get_unusual_days", () => ({}));
|
||||
onRpc("get_allocation_data_request", () => ({}));
|
||||
onRpc("get_special_days_data", () => ({bankHolidays: [], mandatoryDays: []}));
|
||||
onRpc("hr.employee", "get_time_off_dashboard_data", () => (
|
||||
{has_accrual_allocation: true, allocation_data: {}, allocation_request_amount: 0}
|
||||
));
|
||||
|
||||
await mountView({
|
||||
type: "calendar",
|
||||
resModel: "hr.leave",
|
||||
arch: `
|
||||
<calendar js_class="time_off_calendar_dashboard"
|
||||
string="Time Off Request"
|
||||
form_view_id="hr_leave_view_form_dashboard_new_time_off"
|
||||
event_open_popup="true"
|
||||
date_start="date_from"
|
||||
date_stop="date_to"
|
||||
quick_create="0"
|
||||
show_date_picker="0"
|
||||
show_unusual_days="True"
|
||||
hide_time="True"
|
||||
mode="year">
|
||||
<field name="display_name" string=""/>
|
||||
<field name="holiday_status_id" filters="1" invisible="1" color="color"/>
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="is_hatched" invisible="1" />
|
||||
<field name="is_striked" invisible="1"/>
|
||||
</calendar>`,
|
||||
context: user.context
|
||||
});
|
||||
await clickDate("2024-01-09");
|
||||
await click(".o_cw_popover_link");
|
||||
await waitFor("button:contains(Delete Time Off)");
|
||||
await click(".btn-close");
|
||||
await clickDate("2024-01-10");
|
||||
await click(".o_cw_popover_link");
|
||||
await waitFor("button:contains(Cancel Time Off)");
|
||||
})
|
||||
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
import { describe, test, expect, beforeEach } from "@odoo/hoot";
|
||||
import { click, edit, queryAll, queryOne } from "@odoo/hoot-dom";
|
||||
import { mountView, onRpc, selectFieldDropdownItem } from "@web/../tests/web_test_helpers";
|
||||
import { defineHrHolidaysModels } from "@hr_holidays/../tests/hr_holidays_test_helpers";
|
||||
import { HrLeave } from "@hr_holidays/../tests/mock_server/mock_models/hr_leave";
|
||||
import { mockTimeZone } from "@odoo/hoot-mock";
|
||||
|
||||
describe.current.tags("desktop");
|
||||
defineHrHolidaysModels();
|
||||
|
||||
beforeEach(() => {
|
||||
mockTimeZone("Europe/Brussels");
|
||||
HrLeave._records = [
|
||||
{
|
||||
id: 12,
|
||||
employee_id: 100,
|
||||
department_id: 11,
|
||||
date_from: "2016-10-20 09:00:00",
|
||||
date_to: "2016-10-25 18:00:00",
|
||||
holiday_status_id: 55,
|
||||
state: "validate",
|
||||
number_of_days: 5,
|
||||
number_of_hours: 40,
|
||||
leave_type_request_unit: "day",
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
employee_id: 100,
|
||||
department_id: 11,
|
||||
date_from: "2016-10-02 09:00:00",
|
||||
date_to: "2016-10-02 18:00:00",
|
||||
holiday_status_id: 55,
|
||||
state: "validate",
|
||||
number_of_days: 1,
|
||||
number_of_hours: 8,
|
||||
leave_type_request_unit: "day",
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
employee_id: 200,
|
||||
department_id: 11,
|
||||
date_from: "2016-10-15 09:00:00",
|
||||
date_to: "2016-10-21 18:00:00",
|
||||
holiday_status_id: 55,
|
||||
state: "confirm",
|
||||
number_of_days: 8,
|
||||
number_of_hours: 64,
|
||||
leave_type_request_unit: "day",
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
employee_id: 200,
|
||||
department_id: 11,
|
||||
date_from: "2016-10-05 10:00:00",
|
||||
date_to: "2016-10-05 11:00:00",
|
||||
holiday_status_id: 65,
|
||||
state: "validate",
|
||||
number_of_days: 0,
|
||||
number_of_hours: 1,
|
||||
leave_type_request_unit: "hour",
|
||||
},
|
||||
{
|
||||
id: 16,
|
||||
employee_id: 200,
|
||||
department_id: 11,
|
||||
date_from: "2016-09-11 09:00:00",
|
||||
date_to: "2016-09-12 18:00:00",
|
||||
holiday_status_id: 55,
|
||||
state: "validate",
|
||||
number_of_days: 2,
|
||||
number_of_hours: 16,
|
||||
leave_type_request_unit: "day",
|
||||
},
|
||||
{
|
||||
id: 17,
|
||||
employee_id: 100,
|
||||
department_id: 11,
|
||||
date_from: "2016-10-16 09:00:00",
|
||||
date_to: "2016-10-16 11:00:00",
|
||||
holiday_status_id: 65,
|
||||
state: "validate",
|
||||
number_of_days: 0,
|
||||
number_of_hours: 2,
|
||||
leave_type_request_unit: "hour",
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
test("leave stats render correctly", async () => {
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "hr.leave",
|
||||
resId: 14,
|
||||
arch: `
|
||||
<form string="Leave">
|
||||
<field name="employee_id"/>
|
||||
<field name="department_id"/>
|
||||
<field name="date_from"/>
|
||||
<field name="date_to"/>
|
||||
<widget name="hr_leave_stats"/>
|
||||
</form>`,
|
||||
});
|
||||
|
||||
const individualLeaves = queryOne(".o_leave_stats #o_leave_stats_employee");
|
||||
const DepartmentLeaves = queryOne(".o_leave_stats #o_leave_stats_department");
|
||||
// Displays leaves with the correct unit
|
||||
expect(queryAll("span:contains(Legal Leave)", { root: individualLeaves })).toHaveCount(1);
|
||||
expect(queryAll("span:contains(2 days)", { root: individualLeaves })).toHaveCount(1);
|
||||
expect(queryAll("span:contains(Unpaid Leave)", { root: individualLeaves })).toHaveCount(1);
|
||||
expect(queryAll("span:contains(01:00 hours)", { root: individualLeaves })).toHaveCount(1);
|
||||
|
||||
// Displays all leaves for that department
|
||||
expect(queryAll("span:contains(Richard)", { root: DepartmentLeaves })).toHaveCount(2);
|
||||
expect(queryAll("span:contains(10/16/2016)", { root: DepartmentLeaves })).toHaveCount(1);
|
||||
expect(queryAll("span:contains(02:00 hours)", { root: DepartmentLeaves })).toHaveCount(1);
|
||||
expect(queryAll("span:contains(10/20/2016)", { root: DepartmentLeaves })).toHaveCount(1);
|
||||
expect(queryAll("span:contains(10/25/2016)", { root: DepartmentLeaves })).toHaveCount(1);
|
||||
|
||||
expect(
|
||||
queryAll("div.o_horizontal_separator:contains(R&D)", { root: DepartmentLeaves })
|
||||
).toHaveCount(1);
|
||||
});
|
||||
|
||||
test("leave stats reload when employee/department changes", async () => {
|
||||
onRpc(({ args, kwargs, method, model }) => {
|
||||
if (
|
||||
model === "hr.leave" &&
|
||||
method === "search_read" &&
|
||||
kwargs.domain[0][0] === "department_id"
|
||||
) {
|
||||
expect(
|
||||
kwargs.domain.some(
|
||||
(x) => JSON.stringify(x) === JSON.stringify(["department_id", "=", 11])
|
||||
)
|
||||
).toBe(true);
|
||||
}
|
||||
if (
|
||||
model === "hr.leave" &&
|
||||
method === "search_read" &&
|
||||
kwargs.domain[0][0] === "employee_id"
|
||||
) {
|
||||
expect(
|
||||
kwargs.domain.some(
|
||||
(x) => JSON.stringify(x) === JSON.stringify(["employee_id", "=", 200])
|
||||
)
|
||||
).toBe(true);
|
||||
}
|
||||
});
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "hr.leave",
|
||||
arch: `
|
||||
<form string="Leave">
|
||||
<field name="employee_id"/>
|
||||
<field name="department_id"/>
|
||||
<field name="date_from"/>
|
||||
<widget name="hr_leave_stats"/>
|
||||
</form>`,
|
||||
});
|
||||
|
||||
// Set date => shouldn't load data yet (no employee nor department defined)
|
||||
await click("div[name='date_from'] input");
|
||||
await edit("2016-10-12 09:00");
|
||||
// Set employee => should load employee's date
|
||||
await selectFieldDropdownItem("employee_id", "Jane");
|
||||
// Set department => should load department's data
|
||||
await selectFieldDropdownItem("department_id", "R&D");
|
||||
});
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
import { fields } from "@web/../tests/web_test_helpers";
|
||||
import { hrModels } from "@hr/../tests/hr_test_helpers";
|
||||
|
||||
export class HrDepartment extends hrModels.HrDepartment {
|
||||
_name = "hr.department";
|
||||
|
||||
id = fields.Integer();
|
||||
|
||||
_records = [
|
||||
{
|
||||
id: 11,
|
||||
name: "R&D",
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import { hrModels } from "@hr/../tests/hr_test_helpers";
|
||||
import { fields } from "@web/../tests/web_test_helpers";
|
||||
|
||||
export class HrEmployee extends hrModels.HrEmployee {
|
||||
_name = "hr.employee";
|
||||
|
||||
name = fields.Char();
|
||||
leave_date_to = fields.Date();
|
||||
user_id = fields.Many2one({ relation: "res.users" });
|
||||
|
||||
_get_store_avatar_card_fields() {
|
||||
return [...super._get_store_avatar_card_fields(), "leave_date_to"];
|
||||
}
|
||||
|
||||
_records = [
|
||||
{
|
||||
id: 100,
|
||||
name: "Richard",
|
||||
department_id: 11,
|
||||
},
|
||||
{
|
||||
id: 200,
|
||||
name: "Jane",
|
||||
department_id: 11,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
import { fields, models } from "@web/../tests/web_test_helpers";
|
||||
|
||||
export class HrLeave extends models.Model {
|
||||
_name = "hr.leave";
|
||||
|
||||
id = fields.Integer();
|
||||
employee_id = fields.Many2one({
|
||||
relation: "hr.employee",
|
||||
});
|
||||
user_id = fields.Many2one({
|
||||
relation: "res.users"
|
||||
});
|
||||
department_id = fields.Many2one({
|
||||
relation: "hr.department",
|
||||
});
|
||||
date_from = fields.Datetime();
|
||||
date_to = fields.Datetime();
|
||||
holiday_status_id = fields.Many2one({
|
||||
relation: "hr.leave.type",
|
||||
});
|
||||
state = fields.Char();
|
||||
number_of_days = fields.Integer();
|
||||
number_of_hours = fields.Integer();
|
||||
leave_type_request_unit = fields.Selection({
|
||||
string: "Leave Type Request Unit",
|
||||
type: "selection",
|
||||
selection: [
|
||||
["day", "Day"],
|
||||
["half_day", "Half Day"],
|
||||
["hour", "Hours"],
|
||||
],
|
||||
});
|
||||
can_cancel = fields.Boolean();
|
||||
is_hatched = fields.Boolean();
|
||||
is_striked = fields.Boolean();
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import { fields, models } from "@web/../tests/web_test_helpers";
|
||||
|
||||
export class HrLeaveType extends models.Model {
|
||||
_name = "hr.leave.type";
|
||||
|
||||
id = fields.Integer();
|
||||
name = fields.Char();
|
||||
|
||||
_records = [
|
||||
{
|
||||
id: 55,
|
||||
name: "Legal Leave",
|
||||
},
|
||||
{
|
||||
id: 65,
|
||||
name: "Unpaid Leave",
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
import { hrModels } from "@hr/../tests/hr_test_helpers";
|
||||
import { fields } from "@web/../tests/web_test_helpers";
|
||||
import { mailDataHelpers } from "@mail/../tests/mock_server/mail_mock_server";
|
||||
|
||||
export class ResPartner extends hrModels.ResPartner {
|
||||
leave_date_to = fields.Date({ related: false });
|
||||
|
||||
compute_im_status(partner) {
|
||||
/** @type {import("mock_models").ResUsers} */
|
||||
const ResUsers = this.env["res.users"];
|
||||
if (partner.main_user_id && ResUsers.browse(partner.main_user_id).leave_date_to) {
|
||||
if (partner.im_status === "online") {
|
||||
return "leave_online";
|
||||
} else if (partner.im_status === "away") {
|
||||
return "leave_away";
|
||||
} else {
|
||||
return "leave_offline";
|
||||
}
|
||||
} else {
|
||||
return super.compute_im_status(partner);
|
||||
}
|
||||
}
|
||||
|
||||
get _to_store_defaults() {
|
||||
return [
|
||||
...super._to_store_defaults,
|
||||
mailDataHelpers.Store.one(
|
||||
"main_user_id",
|
||||
mailDataHelpers.Store.many("employee_ids", "leave_date_to")
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
import { hrModels } from "@hr/../tests/hr_test_helpers";
|
||||
import { fields } from "@web/../tests/web_test_helpers";
|
||||
|
||||
export class ResUsers extends hrModels.ResUsers {
|
||||
leave_date_to = fields.Date({ related: false });
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
import { describe, test } from "@odoo/hoot";
|
||||
|
||||
import {
|
||||
startServer,
|
||||
start,
|
||||
click,
|
||||
openFormView,
|
||||
contains,
|
||||
openDiscuss,
|
||||
insertText,
|
||||
} from "@mail/../tests/mail_test_helpers";
|
||||
|
||||
import { defineHrHolidaysModels } from "@hr_holidays/../tests/hr_holidays_test_helpers";
|
||||
import { Command, serverState } from "@web/../tests/web_test_helpers";
|
||||
import { press } from "@odoo/hoot-dom";
|
||||
import { mockDate } from "@odoo/hoot-mock";
|
||||
|
||||
describe.current.tags("desktop");
|
||||
defineHrHolidaysModels();
|
||||
|
||||
const { DateTime } = luxon;
|
||||
|
||||
test("Show 'back on' in avatar card", async () => {
|
||||
mockDate("2025-04-08 12:00:00");
|
||||
const pyEnv = await startServer();
|
||||
const employee = pyEnv["hr.employee"].create({
|
||||
user_id: serverState.userId,
|
||||
work_contact_id: serverState.partnerId,
|
||||
leave_date_to: DateTime.now().plus({ days: 3 }).toISODate(),
|
||||
});
|
||||
pyEnv["res.users"].write([serverState.userId], {
|
||||
employee_ids: [Command.link(employee)],
|
||||
});
|
||||
|
||||
const fakeId = pyEnv["res.fake"].create({ name: "Salutations, voyageur" });
|
||||
pyEnv["mail.message"].create({
|
||||
author_id: serverState.partnerId,
|
||||
body: "not empty",
|
||||
model: "res.fake",
|
||||
res_id: fakeId,
|
||||
subject: "Another Subject",
|
||||
});
|
||||
await start();
|
||||
await openFormView("res.fake", fakeId);
|
||||
await click(".o-mail-Message-avatar");
|
||||
await contains(".o_avatar_card span", { text: "Back on Apr 11" });
|
||||
});
|
||||
|
||||
test("Show 'back on' in mention list", async () => {
|
||||
mockDate("2025-04-08 12:00:00");
|
||||
const pyEnv = await startServer();
|
||||
const employee = pyEnv["hr.employee"].create({
|
||||
user_id: serverState.userId,
|
||||
leave_date_to: DateTime.now().plus({ days: 3 }).toISODate(),
|
||||
});
|
||||
pyEnv["res.users"].write([serverState.userId], {
|
||||
employee_ids: [Command.link(employee)],
|
||||
});
|
||||
const channelId = pyEnv["discuss.channel"].create({
|
||||
name: "General & good",
|
||||
channel_member_ids: [Command.create({ partner_id: serverState.partnerId })],
|
||||
});
|
||||
await start();
|
||||
await openDiscuss(channelId);
|
||||
await insertText(".o-mail-Composer-input", "@");
|
||||
await contains(".o-mail-NavigableList-item span", { text: "Back on Apr 11" });
|
||||
});
|
||||
|
||||
test("Show year when 'back on' is on different year than now", async () => {
|
||||
mockDate("2024-12-20 12:00:00");
|
||||
const pyEnv = await startServer();
|
||||
const employee = pyEnv["hr.employee"].create({
|
||||
user_id: serverState.userId,
|
||||
work_contact_id: serverState.partnerId,
|
||||
leave_date_to: DateTime.now().plus({ days: 15 }).toISODate(),
|
||||
});
|
||||
pyEnv["res.users"].write([serverState.userId], {
|
||||
employee_ids: [(6, 0, employee)],
|
||||
});
|
||||
const fakeId = pyEnv["res.fake"].create({ name: "Salutations, voyageur" });
|
||||
pyEnv["mail.message"].create({
|
||||
author_id: serverState.partnerId,
|
||||
body: "not empty",
|
||||
model: "res.fake",
|
||||
res_id: fakeId,
|
||||
subject: "Another Subject",
|
||||
});
|
||||
await start();
|
||||
await openFormView("res.fake", fakeId);
|
||||
await click(".o-mail-Message-avatar");
|
||||
await contains(".o_avatar_card span", { text: "Back on Jan 4, 2025" });
|
||||
});
|
||||
|
||||
test("Discuss Sidebar shows out of office indication", async () => {
|
||||
mockDate("2025-04-08 12:00:00");
|
||||
const pyEnv = await startServer();
|
||||
pyEnv["hr.employee"].create({
|
||||
user_id: serverState.userId,
|
||||
leave_date_to: DateTime.now().plus({ days: 3 }).toISODate(),
|
||||
});
|
||||
const channelId = pyEnv["discuss.channel"].create({
|
||||
channel_member_ids: [Command.create({ partner_id: serverState.partnerId })],
|
||||
channel_type: "chat",
|
||||
});
|
||||
await start();
|
||||
await openDiscuss(channelId);
|
||||
await contains(".o-mail-DiscussSidebarChannel-itemName .text-warning", {
|
||||
text: "Back on Apr 11",
|
||||
});
|
||||
});
|
||||
|
||||
test("CTRL+K command shows out of office indication", async () => {
|
||||
mockDate("2025-04-08 12:00:00");
|
||||
const pyEnv = await startServer();
|
||||
pyEnv["hr.employee"].create({
|
||||
user_id: serverState.userId,
|
||||
leave_date_to: DateTime.now().plus({ days: 3 }).toISODate(),
|
||||
});
|
||||
const channelId = pyEnv["discuss.channel"].create({
|
||||
channel_member_ids: [Command.create({ partner_id: serverState.partnerId })],
|
||||
channel_type: "chat",
|
||||
});
|
||||
await start();
|
||||
await openDiscuss(channelId);
|
||||
await contains(".o-mail-Discuss[data-active]");
|
||||
await press(["ctrl", "k"]);
|
||||
await contains(".o-mail-DiscussCommand .text-warning", {
|
||||
text: "Back on Apr 11",
|
||||
});
|
||||
});
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import { UPDATE_BUS_PRESENCE_DELAY } from '@bus/im_status_service';
|
||||
|
||||
import { start, startServer } from '@mail/../tests/helpers/test_utils';
|
||||
|
||||
QUnit.module('hr_holidays', {}, function () {
|
||||
QUnit.module('components', {}, function () {
|
||||
QUnit.module('persona_im_status_icon_tests.js');
|
||||
|
||||
QUnit.test('on leave & online', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
const pyEnv = await startServer();
|
||||
const partnerId = pyEnv['res.partner'].create({ im_status: 'leave_online' });
|
||||
const mailChannelId = pyEnv['mail.channel'].create({});
|
||||
pyEnv['mail.message'].create({
|
||||
author_id: partnerId,
|
||||
body: 'not empty',
|
||||
model: 'mail.channel',
|
||||
res_id: mailChannelId,
|
||||
});
|
||||
const { advanceTime, afterNextRender, openDiscuss } = await start({
|
||||
discuss: {
|
||||
params: {
|
||||
default_active_id: mailChannelId,
|
||||
},
|
||||
},
|
||||
hasTimeControl: true,
|
||||
});
|
||||
await openDiscuss();
|
||||
await afterNextRender(() => advanceTime(UPDATE_BUS_PRESENCE_DELAY));
|
||||
assert.hasClass(
|
||||
document.querySelector('.o_PersonaImStatusIcon_icon'),
|
||||
'o-online',
|
||||
"persona IM status icon should have online status rendering"
|
||||
);
|
||||
assert.hasClass(
|
||||
document.querySelector('.o_PersonaImStatusIcon_icon'),
|
||||
'fa-plane',
|
||||
"persona IM status icon should have leave status rendering"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('on leave & away', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
const pyEnv = await startServer();
|
||||
const partnerId = pyEnv['res.partner'].create({ im_status: 'leave_away' });
|
||||
const mailChannelId = pyEnv['mail.channel'].create({});
|
||||
pyEnv['mail.message'].create({
|
||||
author_id: partnerId,
|
||||
body: 'not empty',
|
||||
model: 'mail.channel',
|
||||
res_id: mailChannelId,
|
||||
});
|
||||
const { advanceTime, afterNextRender, openDiscuss } = await start({
|
||||
discuss: {
|
||||
params: {
|
||||
default_active_id: mailChannelId,
|
||||
},
|
||||
},
|
||||
hasTimeControl: true,
|
||||
});
|
||||
await openDiscuss();
|
||||
await afterNextRender(() => advanceTime(UPDATE_BUS_PRESENCE_DELAY));
|
||||
assert.hasClass(
|
||||
document.querySelector('.o_PersonaImStatusIcon_icon'),
|
||||
'o-away',
|
||||
"persona IM status icon should have away status rendering"
|
||||
);
|
||||
assert.hasClass(
|
||||
document.querySelector('.o_PersonaImStatusIcon_icon'),
|
||||
'fa-plane',
|
||||
"persona IM status icon should have leave status rendering"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('on leave & offline', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
const pyEnv = await startServer();
|
||||
const partnerId = pyEnv['res.partner'].create({ im_status: 'leave_offline' });
|
||||
const mailChannelId = pyEnv['mail.channel'].create({});
|
||||
pyEnv['mail.message'].create({
|
||||
author_id: partnerId,
|
||||
body: 'not empty',
|
||||
model: 'mail.channel',
|
||||
res_id: mailChannelId,
|
||||
});
|
||||
const { advanceTime, afterNextRender, openDiscuss } = await start({
|
||||
discuss: {
|
||||
params: {
|
||||
default_active_id: mailChannelId,
|
||||
},
|
||||
},
|
||||
hasTimeControl: true,
|
||||
});
|
||||
await openDiscuss();
|
||||
await afterNextRender(() => advanceTime(UPDATE_BUS_PRESENCE_DELAY));
|
||||
assert.hasClass(
|
||||
document.querySelector('.o_PersonaImStatusIcon_icon'),
|
||||
'o-offline',
|
||||
"persona IM status icon should have offline status rendering"
|
||||
);
|
||||
assert.hasClass(
|
||||
document.querySelector('.o_PersonaImStatusIcon_icon'),
|
||||
'fa-plane',
|
||||
"persona IM status icon should have leave status rendering"
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import {
|
||||
start,
|
||||
startServer,
|
||||
} from '@mail/../tests/helpers/test_utils';
|
||||
|
||||
QUnit.module('mail', {}, function () {
|
||||
QUnit.module('components', {}, function () {
|
||||
QUnit.module('thread_icon_tests.js');
|
||||
|
||||
QUnit.test('thread icon of a chat when correspondent is on leave & online', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
const pyEnv = await startServer();
|
||||
const resPartnerId1 = pyEnv['res.partner'].create({
|
||||
im_status: 'leave_online',
|
||||
name: 'Demo',
|
||||
});
|
||||
pyEnv['mail.channel'].create({
|
||||
channel_member_ids: [
|
||||
[0, 0, { partner_id: pyEnv.currentPartnerId }],
|
||||
[0, 0, { partner_id: resPartnerId1 }],
|
||||
],
|
||||
channel_type: 'chat',
|
||||
});
|
||||
const { openDiscuss } = await start();
|
||||
await openDiscuss();
|
||||
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
'.o_ThreadIcon_online',
|
||||
"thread icon should have online status rendering"
|
||||
);
|
||||
assert.hasClass(
|
||||
document.querySelector('.o_ThreadIcon_online'),
|
||||
'fa-plane',
|
||||
"thread icon should have leave status rendering"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('thread icon of a chat when correspondent is on leave & away', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
const pyEnv = await startServer();
|
||||
const resPartnerId1 = pyEnv['res.partner'].create({
|
||||
im_status: 'leave_away',
|
||||
name: 'Demo',
|
||||
});
|
||||
pyEnv['mail.channel'].create({
|
||||
channel_member_ids: [
|
||||
[0, 0, { partner_id: pyEnv.currentPartnerId }],
|
||||
[0, 0, { partner_id: resPartnerId1 }],
|
||||
],
|
||||
channel_type: 'chat',
|
||||
});
|
||||
const { openDiscuss } = await start();
|
||||
await openDiscuss();
|
||||
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
'.o_ThreadIcon_away',
|
||||
"thread icon should have away status rendering"
|
||||
);
|
||||
assert.hasClass(
|
||||
document.querySelector('.o_ThreadIcon_away'),
|
||||
'fa-plane',
|
||||
"thread icon should have leave status rendering"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('thread icon of a chat when correspondent is on leave & offline', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
const pyEnv = await startServer();
|
||||
const resPartnerId1 = pyEnv['res.partner'].create({
|
||||
im_status: 'leave_offline',
|
||||
name: 'Demo',
|
||||
});
|
||||
pyEnv['mail.channel'].create({
|
||||
channel_member_ids: [
|
||||
[0, 0, { partner_id: pyEnv.currentPartnerId }],
|
||||
[0, 0, { partner_id: resPartnerId1 }],
|
||||
],
|
||||
channel_type: 'chat',
|
||||
});
|
||||
const { openDiscuss } = await start();
|
||||
await openDiscuss();
|
||||
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
'.o_ThreadIcon_offline',
|
||||
"thread icon should have offline status rendering"
|
||||
);
|
||||
assert.hasClass(
|
||||
document.querySelector('.o_ThreadIcon_offline'),
|
||||
'fa-plane',
|
||||
"thread icon should have leave status rendering"
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import { start, startServer } from '@mail/../tests/helpers/test_utils';
|
||||
|
||||
QUnit.module('hr_holidays', {}, function () {
|
||||
QUnit.module('components', {}, function () {
|
||||
QUnit.module('thread_view_tests.js');
|
||||
|
||||
QUnit.test('out of office message on direct chat with out of office partner', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
// Returning date of the out of office partner, simulates he'll be back in a month
|
||||
const returningDate = moment.utc().add(1, 'month');
|
||||
const pyEnv = await startServer();
|
||||
// Needed partner & user to allow simulation of message reception
|
||||
const resPartnerId1 = pyEnv['res.partner'].create({
|
||||
name: "Foreigner partner",
|
||||
out_of_office_date_end: returningDate.format("YYYY-MM-DD"),
|
||||
});
|
||||
const mailChannelId1 = pyEnv['mail.channel'].create({
|
||||
channel_member_ids: [
|
||||
[0, 0, { partner_id: pyEnv.currentPartnerId }],
|
||||
[0, 0, { partner_id: resPartnerId1 }],
|
||||
],
|
||||
channel_type: 'chat',
|
||||
});
|
||||
const { openDiscuss, messaging } = await start({
|
||||
discuss: {
|
||||
params: {
|
||||
default_active_id: `mail.channel_${mailChannelId1}`,
|
||||
},
|
||||
},
|
||||
});
|
||||
await openDiscuss();
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
'.o_ThreadView_outOfOffice',
|
||||
"should have an out of office alert on thread view"
|
||||
);
|
||||
const formattedDate = returningDate.toDate().toLocaleDateString(
|
||||
messaging.locale.language.replace(/_/g, '-'),
|
||||
{ day: 'numeric', month: 'short' }
|
||||
);
|
||||
assert.ok(
|
||||
document.querySelector('.o_ThreadView_outOfOffice').textContent.includes(formattedDate),
|
||||
"out of office message should mention the returning date"
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import { click, clickSave, getFixture } from "@web/../tests/helpers/utils";
|
||||
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
|
||||
|
||||
let serverData;
|
||||
let target;
|
||||
|
||||
QUnit.module("Fields", (hooks) => {
|
||||
hooks.beforeEach(() => {
|
||||
serverData = {
|
||||
models: {
|
||||
partner: {
|
||||
fields: {
|
||||
product_id: { string: "Product", type: "many2one", relation: "product" },
|
||||
},
|
||||
records: [{ id: 1, product_id: false }],
|
||||
},
|
||||
product: {
|
||||
fields: {
|
||||
name: { string: "Product Name", type: "char" },
|
||||
},
|
||||
records: [
|
||||
{ id: 1, display_name: "a" },
|
||||
{ id: 2, display_name: "b" },
|
||||
{ id: 3, display_name: "c" },
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
target = getFixture();
|
||||
setupViewRegistries();
|
||||
});
|
||||
|
||||
QUnit.module("RadioImageField");
|
||||
|
||||
QUnit.test("field is correctly renderered", async function (assert) {
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
resId: 1,
|
||||
serverData,
|
||||
arch: '<form><field name="product_id" widget="hr_holidays_radio_image"/></form>',
|
||||
});
|
||||
|
||||
assert.containsOnce(target, ".o_field_widget.o_field_hr_holidays_radio_image");
|
||||
assert.containsN(target, ".o_radio_input", 3);
|
||||
assert.containsNone(target, ".o_radio_input:checked");
|
||||
assert.containsN(target, "img", 3);
|
||||
|
||||
await click(target.querySelector("img"));
|
||||
assert.containsOnce(target, ".o_radio_input:checked");
|
||||
|
||||
await clickSave(target);
|
||||
assert.containsOnce(target, ".o_field_widget.o_field_hr_holidays_radio_image");
|
||||
assert.containsN(target, ".o_radio_input", 3);
|
||||
assert.containsN(target, "img", 3);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,159 +0,0 @@
|
|||
/** @odoo-module */
|
||||
|
||||
import { selectDropdownItem, editInput, getFixture } from '@web/../tests/helpers/utils';
|
||||
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
|
||||
|
||||
|
||||
let serverData;
|
||||
let target;
|
||||
|
||||
QUnit.module('leave_stats_widget', (hooks) => {
|
||||
hooks.beforeEach(() => {
|
||||
setupViewRegistries();
|
||||
|
||||
target = getFixture();
|
||||
serverData = {
|
||||
models: {
|
||||
department: {
|
||||
fields: {
|
||||
name: { string: "Name", type: "char" },
|
||||
},
|
||||
records: [{id:11, name: "R&D"}],
|
||||
},
|
||||
employee: {
|
||||
fields: {
|
||||
name: { string: "Name", type: "char" },
|
||||
department_id: { string: "Department", type: "many2one", relation: 'department' },
|
||||
},
|
||||
records: [{
|
||||
id: 100,
|
||||
name: "Richard",
|
||||
department_id: 11,
|
||||
},{
|
||||
id: 200,
|
||||
name: "Jesus",
|
||||
department_id: 11,
|
||||
}],
|
||||
},
|
||||
'hr.leave.type': {
|
||||
fields: {
|
||||
name: { string: "Name", type: "char" }
|
||||
},
|
||||
records: [{
|
||||
id: 55,
|
||||
name: "Legal Leave",
|
||||
}]
|
||||
},
|
||||
'hr.leave': {
|
||||
fields: {
|
||||
employee_id: { string: "Employee", type: "many2one", relation: 'employee' },
|
||||
department_id: { string: "Department", type: "many2one", relation: 'department' },
|
||||
date_from: { string: "From", type: "datetime" },
|
||||
date_to: { string: "To", type: "datetime" },
|
||||
holiday_status_id: { string: "Leave type", type: "many2one", relation: 'hr.leave.type' },
|
||||
state: { string: "State", type: "char" },
|
||||
holiday_type: { string: "Holiday Type", type: "char" },
|
||||
number_of_days: { string: "State", type: "integer" },
|
||||
},
|
||||
records: [{
|
||||
id: 12,
|
||||
employee_id: 100,
|
||||
department_id: 11,
|
||||
date_from: "2016-10-20 09:00:00",
|
||||
date_to: "2016-10-25 18:00:00",
|
||||
holiday_status_id: 55,
|
||||
state: 'validate',
|
||||
number_of_days: 5,
|
||||
holiday_type: 'employee',
|
||||
},{
|
||||
id: 13,
|
||||
employee_id: 100,
|
||||
department_id: 11,
|
||||
date_from: "2016-10-02 09:00:00",
|
||||
date_to: "2016-10-02 18:00:00",
|
||||
holiday_status_id: 55,
|
||||
state: 'validate',
|
||||
number_of_days: 1,
|
||||
holiday_type: 'employee',
|
||||
},{
|
||||
id: 14,
|
||||
employee_id: 200,
|
||||
department_id: 11,
|
||||
date_from: "2016-10-15 09:00:00",
|
||||
date_to: "2016-10-20 18:00:00",
|
||||
holiday_status_id: 55,
|
||||
state: 'validate',
|
||||
number_of_days: 8,
|
||||
holiday_type: 'employee',
|
||||
}]
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
QUnit.test('leave stats renders correctly', async (assert) => {
|
||||
assert.expect(5);
|
||||
await makeView({
|
||||
serverData,
|
||||
type: "form",
|
||||
resModel: 'hr.leave',
|
||||
arch: '<form string="Leave">' +
|
||||
'<field name="employee_id"/>' +
|
||||
'<field name="department_id"/>' +
|
||||
'<field name="date_from"/>' +
|
||||
'<widget name="hr_leave_stats"/>' +
|
||||
'</form>',
|
||||
resId: 12,
|
||||
mockRPC(route, args) {
|
||||
if (args.model === 'hr.leave' && args.method === 'search') {
|
||||
return Promise.resolve(this.data['hr.leave'].records.map(function (record) { return record.id; }));
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const $leaveTypeBody = target.querySelector('.o_leave_stats #o_leave_stats_employee');
|
||||
const $leavesDepartmentBody = target.querySelector('.o_leave_stats #o_leave_stats_department');
|
||||
|
||||
assert.containsOnce($leaveTypeBody, 'span:contains(Legal Leave)', "it should have leave type");
|
||||
assert.containsOnce($leaveTypeBody, 'span:contains(6)', "it should have 6 days");
|
||||
|
||||
assert.containsN($leavesDepartmentBody, 'span:contains(Richard)', 2, "it should have 2 leaves for Richard");
|
||||
assert.containsOnce($leavesDepartmentBody, 'span:contains(Jesus)', "it should have 1 leaves for Jesus");
|
||||
assert.containsOnce($leavesDepartmentBody, 'div.o_horizontal_separator:contains(R&D)', "it should have R&D title");
|
||||
});
|
||||
QUnit.test('leave stats reload when employee/department changes', async (assert) => {
|
||||
assert.expect(3);
|
||||
await makeView({
|
||||
serverData,
|
||||
type: "form",
|
||||
resModel: 'hr.leave',
|
||||
mode: 'edit',
|
||||
arch: '<form string="Leave">' +
|
||||
'<field name="employee_id"/>' +
|
||||
'<field name="department_id"/>' +
|
||||
'<field name="date_from"/>' +
|
||||
'<widget name="hr_leave_stats"/>' +
|
||||
'</form>',
|
||||
mockRPC(route, args) {
|
||||
if (args.model === 'hr.leave' && args.method === 'search_read') {
|
||||
assert.ok(_.some(args.kwargs.domain, _.matcher(['department_id', '=', 11])), "It should load department's leaves data");
|
||||
}
|
||||
if (args.model === 'hr.leave' && args.method === 'read_group') {
|
||||
assert.ok(_.some(args.kwargs.domain, _.matcher(['employee_id', '=', 200])), "It should load employee's leaves data");
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// Set date => shouldn't load data yet (no employee nor department defined)
|
||||
await editInput(
|
||||
target,
|
||||
"div[name='date_from'] .o_datepicker_input",
|
||||
"2016-10-12 09:00:00"
|
||||
);
|
||||
|
||||
// Set employee => should load employee's date
|
||||
await selectDropdownItem(target, "employee_id", "Jesus");
|
||||
// Set department => should load department's data
|
||||
await selectDropdownItem(target, "department_id", "R&D");
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
import { defineMailModels } from "@mail/../tests/mail_test_helpers";
|
||||
import { expect, test } from "@odoo/hoot";
|
||||
import { clickSave, contains, defineModels, fields, models, mountView } from "@web/../tests/web_test_helpers";
|
||||
|
||||
class Partner extends models.Model {
|
||||
_records = [{ id: 1, product_id: false }];
|
||||
|
||||
product_id = fields.Many2one({ relation: "product" });
|
||||
}
|
||||
|
||||
class Product extends models.Model {
|
||||
_records = [
|
||||
{ id: 1, name: "a" },
|
||||
{ id: 2, name: "b" },
|
||||
{ id: 3, name: "c" },
|
||||
];
|
||||
|
||||
name = fields.Char();
|
||||
}
|
||||
|
||||
defineModels([Partner, Product]);
|
||||
defineMailModels();
|
||||
|
||||
test(`field is correctly renderered`, async () => {
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
resId: 1,
|
||||
arch: `<form><field name="product_id" widget="hr_holidays_radio_image"/></form>`,
|
||||
});
|
||||
expect(`.o_field_widget.o_field_hr_holidays_radio_image`).toHaveCount(1);
|
||||
expect(`.o_radio_input`).toHaveCount(3);
|
||||
expect(`.o_radio_input:checked`).toHaveCount(0);
|
||||
expect(`img`).toHaveCount(3);
|
||||
|
||||
await contains(`img:eq(0)`).click();
|
||||
expect(`.o_radio_input:checked`).toHaveCount(1);
|
||||
|
||||
await clickSave();
|
||||
expect(`.o_field_widget.o_field_hr_holidays_radio_image`).toHaveCount(1);
|
||||
expect(`.o_radio_input`).toHaveCount(3);
|
||||
expect(`.o_radio_input:checked`).toHaveCount(1);
|
||||
expect(`img`).toHaveCount(3);
|
||||
});
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
import { describe, test } from "@odoo/hoot";
|
||||
import { Command, serverState } from "@web/../tests/web_test_helpers";
|
||||
import { startServer, start, openDiscuss, contains } from "@mail/../tests/mail_test_helpers";
|
||||
import { defineHrHolidaysModels } from "@hr_holidays/../tests/hr_holidays_test_helpers";
|
||||
|
||||
describe.current.tags("desktop");
|
||||
defineHrHolidaysModels();
|
||||
|
||||
test("thread icon of a chat when correspondent is on leave & online", async () => {
|
||||
const pyEnv = await startServer();
|
||||
const partnerId = pyEnv["res.partner"].create({ im_status: "online", name: "Demo" });
|
||||
pyEnv["res.users"].create({ partner_id: partnerId, leave_date_to: "2023-01-01" });
|
||||
pyEnv["discuss.channel"].create({
|
||||
channel_member_ids: [
|
||||
Command.create({ partner_id: serverState.partnerId }),
|
||||
Command.create({ partner_id: partnerId }),
|
||||
],
|
||||
channel_type: "chat",
|
||||
});
|
||||
await start();
|
||||
await openDiscuss();
|
||||
await contains(".o-mail-DiscussSidebarChannel", {
|
||||
contains: [".o-mail-ThreadIcon .fa-plane[title='On Leave (Online)']"],
|
||||
text: "Demo",
|
||||
});
|
||||
});
|
||||
|
||||
test("thread icon of a chat when correspondent is on leave & away", async () => {
|
||||
const pyEnv = await startServer();
|
||||
const partnerId = pyEnv["res.partner"].create({ im_status: "away", name: "Demo" });
|
||||
pyEnv["res.users"].create({ partner_id: partnerId, leave_date_to: "2023-01-01" });
|
||||
pyEnv["discuss.channel"].create({
|
||||
channel_member_ids: [
|
||||
Command.create({ partner_id: serverState.partnerId }),
|
||||
Command.create({ partner_id: partnerId }),
|
||||
],
|
||||
channel_type: "chat",
|
||||
});
|
||||
await start();
|
||||
await openDiscuss();
|
||||
await contains(".o-mail-DiscussSidebarChannel", {
|
||||
contains: [".o-mail-ThreadIcon .fa-plane[title='On Leave (Idle)']"],
|
||||
text: "Demo",
|
||||
});
|
||||
});
|
||||
|
||||
test("thread icon of a chat when correspondent is on leave & offline", async () => {
|
||||
const pyEnv = await startServer();
|
||||
const partnerId = pyEnv["res.partner"].create({ im_status: "offline", name: "Demo" });
|
||||
pyEnv["res.users"].create({ partner_id: partnerId, leave_date_to: "2023-01-01" });
|
||||
pyEnv["discuss.channel"].create({
|
||||
channel_member_ids: [
|
||||
Command.create({ partner_id: serverState.partnerId }),
|
||||
Command.create({ partner_id: partnerId }),
|
||||
],
|
||||
channel_type: "chat",
|
||||
});
|
||||
await start();
|
||||
await openDiscuss();
|
||||
await contains(".o-mail-DiscussSidebarChannel", {
|
||||
contains: [".o-mail-ThreadIcon .fa-plane[title='On Leave']"],
|
||||
text: "Demo",
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
import { describe, test } from "@odoo/hoot";
|
||||
import { Command, serverState } from "@web/../tests/web_test_helpers";
|
||||
import { startServer, start, openDiscuss, contains } from "@mail/../tests/mail_test_helpers";
|
||||
import { defineHrHolidaysModels } from "@hr_holidays/../tests/hr_holidays_test_helpers";
|
||||
|
||||
describe.current.tags("desktop");
|
||||
defineHrHolidaysModels();
|
||||
|
||||
test("out of office message on direct chat with out of office partner", async () => {
|
||||
const pyEnv = await startServer();
|
||||
const partnerId = pyEnv["res.partner"].create({ name: "Demo", im_status: "online" });
|
||||
const userId = pyEnv["res.users"].create({ partner_id: partnerId });
|
||||
const employee = pyEnv["hr.employee"].create({
|
||||
user_id: userId,
|
||||
leave_date_to: "2023-01-01",
|
||||
});
|
||||
pyEnv["res.users"].write([userId], {
|
||||
employee_ids: [Command.link(employee)],
|
||||
});
|
||||
const channelId = pyEnv["discuss.channel"].create({
|
||||
channel_member_ids: [
|
||||
Command.create({ partner_id: serverState.partnerId }),
|
||||
Command.create({ partner_id: partnerId }),
|
||||
],
|
||||
channel_type: "chat",
|
||||
});
|
||||
await start();
|
||||
await openDiscuss(channelId);
|
||||
await contains(".alert", { text: "Back on Jan 1, 2023" });
|
||||
});
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
import { describe, expect, test } from "@odoo/hoot";
|
||||
import { mockDate } from "@odoo/hoot-mock";
|
||||
import { defineModels, fields, getService, models, mountWebClient, onRpc } from "@web/../tests/web_test_helpers";
|
||||
import { defineHrHolidaysModels } from "./hr_holidays_test_helpers";
|
||||
|
||||
describe.current.tags("desktop");
|
||||
|
||||
class HrLeave extends models.Model {
|
||||
_views = {
|
||||
calendar: `
|
||||
<calendar js_class="time_off_calendar_dashboard"
|
||||
string="Time Off Request"
|
||||
form_view_id="%(hr_holidays.hr_leave_view_form_dashboard_new_time_off)d"
|
||||
event_open_popup="1"
|
||||
date_start="date_from"
|
||||
date_stop="date_to"
|
||||
quick_create="0"
|
||||
show_unusual_days="1"
|
||||
color="color"
|
||||
hide_time="1"
|
||||
mode="year"
|
||||
>
|
||||
<field name="name"/>
|
||||
<field name="holiday_status_id" filters="1" invisible="1" color="color"/>
|
||||
<field name="state" invisible="1"/>
|
||||
</calendar>
|
||||
`,
|
||||
};
|
||||
|
||||
color = fields.Integer({ related: "holiday_status_id.color" });
|
||||
date_from = fields.Datetime();
|
||||
date_to = fields.Datetime();
|
||||
department_id = fields.Many2one({ relation: "hr.department" });
|
||||
employee_id = fields.Many2one({ relation: "hr.employee" });
|
||||
holiday_status_id = fields.Many2one({ relation: "hr.leave.type" });
|
||||
holiday_type = fields.Char();
|
||||
name = fields.Char();
|
||||
number_of_days = fields.Integer();
|
||||
state = fields.Char();
|
||||
}
|
||||
|
||||
class HrLeaveType extends models.Model {
|
||||
name = fields.Char();
|
||||
color = fields.Integer();
|
||||
}
|
||||
|
||||
defineHrHolidaysModels();
|
||||
defineModels([HrLeave, HrLeaveType]);
|
||||
|
||||
onRpc("hr.employee", "get_time_off_dashboard_data", () => (
|
||||
{has_accrual_allocation: true, allocation_data: {}, allocation_request_amount: 0}
|
||||
));
|
||||
onRpc("hr.employee", "get_mandatory_days", () => ({}));
|
||||
onRpc("hr.employee", "get_special_days_data", () => ({ mandatoryDays: [], bankHolidays: [] }));
|
||||
onRpc("hr.leave", "get_unusual_days", () => ({}));
|
||||
onRpc("hr.leave", "has_access", () => true);
|
||||
onRpc("hr.leave.type", "has_accrual_allocation", () => true);
|
||||
|
||||
test(`test employee is passed to get_time_off_dashboard_data`, async () => {
|
||||
onRpc("hr.employee", "get_time_off_dashboard_data", ({ kwargs }) => {
|
||||
expect.step(kwargs.context.employee_id);
|
||||
});
|
||||
|
||||
await mountWebClient();
|
||||
await getService("action").doAction({
|
||||
id: 1,
|
||||
res_model: "hr.leave",
|
||||
type: "ir.actions.act_window",
|
||||
views: [[false, "calendar"]],
|
||||
context: { employee_id: [200] },
|
||||
domain: [["employee_id", "in", [200]]],
|
||||
});
|
||||
expect.verifySteps([200]);
|
||||
});
|
||||
|
||||
test(`test basic rendering`, async () => {
|
||||
mockDate("2025-03-18 08:00:00");
|
||||
onRpc("hr.employee", "get_mandatory_days", () => ({ "2025-03-17": 5 }));
|
||||
onRpc("hr.employee", "get_special_days_data", () => ({
|
||||
mandatoryDays: [
|
||||
{
|
||||
id: -2,
|
||||
colorIndex: 5,
|
||||
end: "2025-03-17T23:59:59.999999",
|
||||
endType: "datetime",
|
||||
isAllDay: true,
|
||||
start: "2025-03-17T00:00:00",
|
||||
startType: "datetime",
|
||||
title: "Test Mandatory Day",
|
||||
},
|
||||
],
|
||||
bankHolidays: [],
|
||||
}));
|
||||
|
||||
await mountWebClient();
|
||||
await getService("action").doAction({
|
||||
id: 1,
|
||||
res_model: "hr.leave",
|
||||
type: "ir.actions.act_window",
|
||||
views: [[false, "calendar"]],
|
||||
context: { employee_id: [200] },
|
||||
domain: [["employee_id", "in", [200]]],
|
||||
});
|
||||
expect(`.o_calendar_filter:contains("Legend")`).toHaveCount(1);
|
||||
expect(`.o_calendar_filter:contains("To Approve")`).toHaveCount(1);
|
||||
expect(`.o_calendar_filter:contains("Mar 17, 2025 : Test Mandatory Day")`).toHaveCount(1);
|
||||
expect(`.fc-day.hr_mandatory_day_5[data-date="2025-03-17"]`).toHaveCount(1);
|
||||
});
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
import { registry } from '@web/core/registry';
|
||||
import { stepUtils } from "@web_tour/tour_utils";
|
||||
|
||||
const today = luxon.DateTime.now();
|
||||
const pastDateFrom = today.minus({ days: 3 }).toFormat("MM/dd/yyyy");
|
||||
const pastDateTo = today.minus({ days: 2 }).toFormat("MM/dd/yyyy");
|
||||
const futureDateTo = today.plus({ days: 2 }).toFormat("MM/dd/yyyy");
|
||||
const warningText = "The allocated days cannot be used, because the allocation is set to finish in the past.";
|
||||
|
||||
registry.category("web_tour.tours").add("time_off_allocation_warning_tour", {
|
||||
url: "/odoo",
|
||||
steps: () => [
|
||||
stepUtils.showAppsMenuItem(),
|
||||
{
|
||||
content: "Click Time Off",
|
||||
trigger: ".o_app[data-menu-xmlid='hr_holidays.menu_hr_holidays_root']",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Open Management menu",
|
||||
trigger: ".o-dropdown[data-menu-xmlid='hr_holidays.menu_hr_holidays_management']",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Go to Allocations",
|
||||
trigger: ".o-dropdown-item[data-menu-xmlid='hr_holidays.hr_holidays_menu_manager_approve_allocations']",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Create a new allocation",
|
||||
trigger: ".o-kanban-button-new",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Click to select a leave type",
|
||||
trigger: ".o_field_widget[name='holiday_status_id'] input",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
trigger: ".o-autocomplete--dropdown-menu > li > a[id=holiday_status_id_0_0_0]",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Open the start date picker",
|
||||
trigger: ".o_field_widget[name='date_from'] button",
|
||||
// Past date to trigger the warning
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Edit the start date picker",
|
||||
trigger: ".o_field_widget[name='date_from'] input",
|
||||
// Past date to trigger the warning
|
||||
run: `click && edit ${pastDateFrom}`,
|
||||
},
|
||||
{
|
||||
content: "Edit the end date picker",
|
||||
trigger: ".o_field_widget[name='date_to'] input",
|
||||
// Past date to trigger the warning
|
||||
run: `click && edit ${pastDateTo} && click body`,
|
||||
},
|
||||
{
|
||||
content: "Error regarding allocation to be visible",
|
||||
trigger: `.o_cell:has(.o_row[name='validity']) + div span:contains(${warningText})`,
|
||||
},
|
||||
{
|
||||
content: "Open the end date picker",
|
||||
trigger: ".o_field_widget[name='date_to'] button",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Edit the end date picker",
|
||||
trigger: ".o_field_widget[name='date_to'] input",
|
||||
run: `click && edit ${futureDateTo} && click body`,
|
||||
},
|
||||
{
|
||||
content: "Error regarding allocation to be visible",
|
||||
trigger: `.o_cell:has(.o_row[name='validity']) + div:not(:has(span:not(:contains(${warningText}))))`,
|
||||
},
|
||||
...stepUtils.saveForm(),
|
||||
],
|
||||
});
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
import { registry } from "@web/core/registry";
|
||||
import { stepUtils } from "@web_tour/tour_utils";
|
||||
|
||||
registry.category("web_tour.tours").add("time_off_card_tour", {
|
||||
url: "/odoo",
|
||||
steps: () => [
|
||||
stepUtils.showAppsMenuItem(),
|
||||
{
|
||||
content: "Open Time Off app",
|
||||
trigger: '.o_app[data-menu-xmlid="hr_holidays.menu_hr_holidays_root"]',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Click on the Time Off name",
|
||||
trigger: '.o_timeoff_name:not(:contains("Pending Requests"))',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Ensure the list view for Time Off requests is displayed",
|
||||
trigger: ".o_list_view",
|
||||
},
|
||||
{
|
||||
content: "Navigate back to the previous view",
|
||||
trigger: ".o_back_button",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Click on the time off card to open the detailed popover.",
|
||||
trigger: "span.o_timeoff_details",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Verify that the popover is displayed after clicking on the time off details.",
|
||||
trigger: ".o_popover",
|
||||
},
|
||||
{
|
||||
content: "Click on the link containing 'Allocated'.",
|
||||
trigger: ".o_popover .btn-link:contains('Allocated')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Ensure the list view for Time Off requests is displayed",
|
||||
trigger: ".o_list_view",
|
||||
},
|
||||
{
|
||||
content: "Navigate back to the previous view",
|
||||
trigger: ".o_back_button",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Click on the time off card to open the detailed popover.",
|
||||
trigger: "span.o_timeoff_details",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Click on the link containing 'Approved'",
|
||||
trigger: ".o_popover .btn-link:contains('Approved')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Ensure the list view for Time Off requests is displayed",
|
||||
trigger: ".o_list_view",
|
||||
},
|
||||
{
|
||||
content: "Navigate back to the previous view",
|
||||
trigger: ".o_back_button",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Click on the time off card to open the detailed popover.",
|
||||
trigger: "span.o_timeoff_details",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Click on the link containing 'Planned'",
|
||||
trigger: ".o_popover .btn-link:contains('Planned')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Ensure the list view for Time Off requests is displayed",
|
||||
trigger: ".o_list_view",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
import { registry } from "@web/core/registry";
|
||||
import { stepUtils } from "@web_tour/tour_utils";
|
||||
|
||||
registry.category("web_tour.tours").add("time_off_graph_view_tour", {
|
||||
url: "/odoo",
|
||||
steps: () => [
|
||||
stepUtils.showAppsMenuItem(),
|
||||
{
|
||||
content: "Open Time Off app",
|
||||
trigger: ".o_app[data-menu-xmlid='hr_holidays.menu_hr_holidays_root']",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
trigger: ".fc-daygrid-day-top",
|
||||
},
|
||||
{
|
||||
content: "Open reporting menu",
|
||||
trigger: ".o-dropdown[data-menu-xmlid='hr_holidays.menu_hr_holidays_report']",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Open reporting by type",
|
||||
trigger: ".o-dropdown-item[data-menu-xmlid='hr_holidays.menu_hr_holidays_summary_all']",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
trigger: ".o_graph_canvas_container",
|
||||
},
|
||||
{
|
||||
content: "Open bar chart view",
|
||||
trigger: "button[data-mode='bar']",
|
||||
run: "click",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
@ -1,47 +1,24 @@
|
|||
odoo.define('hr_holidays.tour_time_off_request_calendar_view', function (require) {
|
||||
'use strict';
|
||||
import { registry } from "@web/core/registry";
|
||||
import { stepUtils } from "@web_tour/tour_utils";
|
||||
|
||||
var tour = require('web_tour.tour');
|
||||
|
||||
tour.register('time_off_request_calendar_view', {
|
||||
test: true,
|
||||
url: '/web',
|
||||
},
|
||||
[
|
||||
tour.stepUtils.showAppsMenuItem(),
|
||||
{
|
||||
content: "Open Time Off app",
|
||||
trigger: '.o_app[data-menu-xmlid="hr_holidays.menu_hr_holidays_root"]',
|
||||
},
|
||||
{
|
||||
content: "Click on the first Thursday of the year",
|
||||
trigger: '.fc-day-top.fc-thu',
|
||||
run: () => {
|
||||
const el = document.querySelector('.fc-day-top.fc-thu').firstChild;
|
||||
el.scrollIntoView();
|
||||
|
||||
const fromPosition = el.getBoundingClientRect();
|
||||
fromPosition.x += el.offsetWidth / 2;
|
||||
fromPosition.y += el.offsetHeight / 2;
|
||||
|
||||
el.dispatchEvent(new MouseEvent("mousedown", {
|
||||
bubbles: true,
|
||||
which: 1,
|
||||
button: 0,
|
||||
clientX: fromPosition.x,
|
||||
clientY: fromPosition.y}));
|
||||
el.dispatchEvent(new MouseEvent("mouseup", {
|
||||
bubbles: true,
|
||||
which: 1,
|
||||
button: 0,
|
||||
clientX: fromPosition.x,
|
||||
clientY: fromPosition.y }));
|
||||
}
|
||||
},
|
||||
{
|
||||
content: "Save the leave",
|
||||
trigger: '.btn:contains("Save")',
|
||||
run: 'click',
|
||||
}
|
||||
]);
|
||||
registry.category("web_tour.tours").add("time_off_request_calendar_view", {
|
||||
url: "/odoo",
|
||||
steps: () => [
|
||||
stepUtils.showAppsMenuItem(),
|
||||
{
|
||||
content: "Open Time Off app",
|
||||
trigger: '.o_app[data-menu-xmlid="hr_holidays.menu_hr_holidays_root"]',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Click on the first Thursday of the year",
|
||||
trigger: ".fc-daygrid-day.fc-day-thu:not(.fc-day-disabled)",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Save the leave",
|
||||
trigger: '.o_form_button_save',
|
||||
run: "click",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue