Initial commit: Hr packages

This commit is contained in:
Ernad Husremovic 2025-08-29 15:20:50 +02:00
commit 62531cd146
2820 changed files with 1432848 additions and 0 deletions

View file

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import test_access_rights
from . import test_automatic_leave_dates
from . import test_allocation_access_rights
from . import test_holidays_flow
from . import test_hr_holidays_cancel_leave
from . import test_hr_holidays_tour
from . import test_hr_leave_type
from . import test_accrual_allocations
from . import test_change_department
from . import test_leave_requests
from . import test_out_of_office
from . import test_company_leave
from . import test_res_partner
from . import test_stress_days
from . import test_global_leaves
from . import test_uninstall
from . import test_holidays_calendar
from . import test_dashboard

View file

@ -0,0 +1,60 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.mail.tests.common import mail_new_test_user
from odoo.tests import common
class TestHrHolidaysCommon(common.TransactionCase):
@classmethod
def setUpClass(cls):
super(TestHrHolidaysCommon, cls).setUpClass()
cls.env.user.tz = 'Europe/Brussels'
cls.env.user.company_id.resource_calendar_id.tz = "Europe/Brussels"
# Test users to use through the various tests
cls.user_hruser = mail_new_test_user(cls.env, login='armande', groups='base.group_user,hr_holidays.group_hr_holidays_user')
cls.user_hruser_id = cls.user_hruser.id
cls.user_hrmanager = mail_new_test_user(cls.env, login='bastien', groups='base.group_user,hr_holidays.group_hr_holidays_manager')
cls.user_hrmanager_id = cls.user_hrmanager.id
cls.user_hrmanager.tz = 'Europe/Brussels'
cls.user_employee = mail_new_test_user(cls.env, login='david', groups='base.group_user')
cls.user_employee_id = cls.user_employee.id
# Hr Data
Department = cls.env['hr.department'].with_context(tracking_disable=True)
cls.hr_dept = Department.create({
'name': 'Human Resources',
})
cls.rd_dept = Department.create({
'name': 'Research and devlopment',
})
cls.employee_emp = cls.env['hr.employee'].create({
'name': 'David Employee',
'user_id': cls.user_employee_id,
'department_id': cls.rd_dept.id,
})
cls.employee_emp_id = cls.employee_emp.id
cls.employee_hruser = cls.env['hr.employee'].create({
'name': 'Armande HrUser',
'user_id': cls.user_hruser_id,
'department_id': cls.rd_dept.id,
})
cls.employee_hruser_id = cls.employee_hruser.id
cls.employee_hrmanager = cls.env['hr.employee'].create({
'name': 'Bastien HrManager',
'user_id': cls.user_hrmanager_id,
'department_id': cls.hr_dept.id,
'parent_id': cls.employee_hruser_id,
})
cls.employee_hrmanager_id = cls.employee_hrmanager.id
cls.rd_dept.write({'manager_id': cls.employee_hruser_id})
cls.hours_per_day = cls.employee_emp.resource_id.calendar_id.hours_per_day or 8

View file

@ -0,0 +1,858 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import datetime
from dateutil.relativedelta import relativedelta
from freezegun import freeze_time
from odoo import tests
from odoo.addons.hr_holidays.tests.common import TestHrHolidaysCommon
from odoo.exceptions import AccessError, UserError, ValidationError
from odoo.tools import mute_logger
@tests.tagged('access_rights', 'post_install', '-at_install')
class TestHrHolidaysAccessRightsCommon(TestHrHolidaysCommon):
@classmethod
def setUpClass(cls):
super(TestHrHolidaysAccessRightsCommon, cls).setUpClass()
cls.leave_type = cls.env['hr.leave.type'].create({
'name': 'Unlimited',
'leave_validation_type': 'hr',
'requires_allocation': 'no',
})
cls.rd_dept.manager_id = False
cls.hr_dept.manager_id = False
cls.employee_emp.parent_id = False
cls.employee_leave = cls.env['hr.leave'].with_user(cls.user_employee_id).create({
'name': 'Test',
'holiday_status_id': cls.leave_type.id,
'department_id': cls.employee_emp.department_id.id,
'employee_id': cls.employee_emp.id,
'date_from': datetime.now() + relativedelta(days=30),
'date_to': datetime.now() + relativedelta(days=31),
'number_of_days': 1,
})
cls.lt_no_validation = cls.env['hr.leave.type'].create({
'name': 'Validation = no_validation',
'leave_validation_type': 'hr',
'requires_allocation': 'no',
})
cls.lt_validation_hr = cls.env['hr.leave.type'].create({
'name': 'Validation = HR',
'leave_validation_type': 'hr',
'requires_allocation': 'no',
})
cls.lt_validation_manager = cls.env['hr.leave.type'].create({
'name': 'Validation = manager',
'leave_validation_type': 'hr',
'requires_allocation': 'no',
})
cls.lt_validation_both = cls.env['hr.leave.type'].create({
'name': 'Validation = both',
'leave_validation_type': 'hr',
'requires_allocation': 'no',
})
cls.draft_status = [
cls.lt_validation_hr,
cls.lt_validation_manager,
cls.lt_validation_both
]
cls.confirm_status = [
cls.lt_no_validation,
cls.lt_validation_hr,
cls.lt_validation_manager,
cls.lt_validation_both
]
# Here we only test access rights, prevent any conflict with
# existing stress days - they are tested someplace else.
cls.env['hr.leave.stress.day'].search([]).unlink()
def request_leave(self, user_id, date_from, number_of_days, values=None):
values = dict(values or {}, **{
'date_from': date_from,
'request_date_from': date_from,
'date_to': date_from + relativedelta(days=number_of_days),
'request_date_to': date_from + relativedelta(days=number_of_days),
'number_of_days': number_of_days,
})
return self.env['hr.leave'].with_user(user_id).create(values)
@tests.tagged('access_rights', 'access_rights_states')
class TestAcessRightsStates(TestHrHolidaysAccessRightsCommon):
# ******************************************************
# Action draft
# ******************************************************
def test_draft_status(self):
"""
We should only be able to draft a leave that is
in confirm or refuse state
"""
for i, status in enumerate(self.draft_status):
values = {
'name': 'Ranoi',
'employee_id': self.employee_emp.id,
'holiday_status_id': status.id,
}
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
leave.action_draft()
values = {
'name': 'Ranoi',
'employee_id': self.employee_emp.id,
'holiday_status_id': status.id,
}
leave = self.request_leave(1, datetime.today() + relativedelta(days=20 + i), 1, values)
# the state has to be set to draft in a write because it is initialized to confirm if it has validation
leave.write({'state': 'draft'})
with self.assertRaises(UserError):
leave.action_draft()
def test_base_user_draft_his_leave(self):
"""
Should be able to draft his own leave
whatever the holiday_status_id
"""
for i, status in enumerate(self.draft_status):
values = {
'name': 'Random Leave',
'employee_id': self.employee_emp.id,
'holiday_status_id': status.id,
}
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
leave.with_user(self.user_employee.id).action_draft()
def test_base_user_draft_other_employee_leave(self):
"""
Should not be able to draft the leave of someone else
whatever the holiday_status_id
"""
for i, status in enumerate(self.draft_status):
values = {
'name': 'Random Leave',
'employee_id': self.employee_hruser.id,
'holiday_status_id': status.id,
}
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
with self.assertRaises(UserError):
leave.with_user(self.user_employee.id).action_draft()
def test_base_user_draft_other_employee_leave_and_is_leave_manager_id(self):
"""
Should not be able to draft the leave of someone else
even when being the leave manager id for this person
whatever the holiday_status_id
"""
self.employee_hruser.write({'leave_manager_id': self.user_employee.id})
for i, status in enumerate(self.draft_status):
values = {
'name': 'Random Leave',
'employee_id': self.employee_hruser.id,
'holiday_status_id': status.id,
}
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
with self.assertRaises(UserError):
leave.with_user(self.user_employee.id).action_draft()
def test_base_user_draft_self_and_is_leave_manager_id(self):
"""
Should be able to draft his own leave
even when being leave manager id
whatever the holiday_status_id
"""
self.employee_emp.write({'leave_manager_id': self.user_employee.id})
for i, status in enumerate(self.draft_status):
values = {
'name': 'Random Leave',
'employee_id': self.employee_emp.id,
'holiday_status_id': status.id,
}
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
leave.with_user(self.user_employee.id).action_draft()
def test_base_user_draft_refused_leave(self):
"""
Should not be able to draft a refused leave
"""
for i, status in enumerate(self.draft_status):
values = {
'name': 'Random Leave',
'employee_id': self.employee_emp.id,
'holiday_status_id': status.id,
}
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
leave.action_refuse()
with self.assertRaises(UserError):
leave.with_user(self.user_employee.id).action_draft()
def test_base_user_draft_current_leave(self):
"""
Should not be able to draft a passed leave
"""
for i, status in enumerate(self.draft_status):
values = {
'name': 'Random Leave',
'employee_id': self.employee_emp.id,
'holiday_status_id': status.id,
}
leave = self.request_leave(1, datetime.today() + relativedelta(days=-20 + i), 1, values)
with self.assertRaises(UserError):
leave.with_user(self.user_employee.id).action_draft()
def test_holiday_user_draft_his_leave(self):
"""
Should be able to draft his own leave
whatever the holiday_status_id
"""
for i, status in enumerate(self.draft_status):
values = {
'name': 'Random Leave',
'employee_id': self.employee_hruser.id,
'holiday_status_id': status.id,
}
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
leave.with_user(self.user_hruser.id).action_draft()
def test_holiday_user_draft_other_employee_leave(self):
"""
Should not be able to draft other employee leave
whatever the holiday_status_id
"""
for i, status in enumerate(self.draft_status):
values = {
'name': 'Random Leave',
'employee_id': self.employee_emp.id,
'holiday_status_id': status.id,
}
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
with self.assertRaises(UserError):
leave.with_user(self.user_hruser.id).action_draft()
def test_holiday_user_draft_other_employee_leave_and_is_leave_manager_id(self):
"""
Should not be able to draft other employee leave
even if he is the leave manager id
whatever the holiday_status_id
"""
self.employee_emp.write({'leave_manager_id': self.user_hruser.id})
for i, status in enumerate(self.draft_status):
values = {
'name': 'Random Leave',
'employee_id': self.employee_emp.id,
'holiday_status_id': status.id,
}
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
with self.assertRaises(UserError):
leave.with_user(self.user_hruser.id).action_draft()
def test_holiday_user_draft_self_and_is_manager_id(self):
"""
Should be able to draft his own leave
even if he is leave manager id
whatever the holiday_status_id
"""
self.employee_hruser.write({'leave_manager_id': self.user_hruser.id})
for i, status in enumerate(self.draft_status):
values = {
'name': 'Random Leave',
'employee_id': self.employee_hruser.id,
'holiday_status_id': status.id,
}
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
leave.with_user(self.user_hruser.id).action_draft()
def test_holiday_user_draft_refused_leave(self):
"""
Should not be able to draft a refused leave
"""
for i, status in enumerate(self.draft_status):
values = {
'name': 'Random Leave',
'employee_id': self.employee_hruser.id,
'holiday_status_id': status.id,
}
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
leave.action_refuse()
with self.assertRaises(UserError):
leave.with_user(self.user_hruser.id).action_draft()
def test_holiday_user_draft_current_leave(self):
"""
Should not be able to draft a passed leave
"""
for i, status in enumerate(self.draft_status):
values = {
'name': 'Random Leave',
'employee_id': self.employee_hruser.id,
'holiday_status_id': status.id,
}
leave = self.request_leave(1, datetime.today() + relativedelta(days=-20 + i), 1, values)
with self.assertRaises(UserError):
leave.with_user(self.user_hruser.id).action_draft()
def test_holiday_manager_draft_his_leave(self):
"""
The holiday manager should be able to do everything
"""
for i, status in enumerate(self.draft_status):
values = {
'name': 'Random Leave',
'employee_id': self.employee_hrmanager.id,
'holiday_status_id': status.id,
}
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
leave.with_user(self.user_hrmanager.id).action_draft()
def test_holiday_manager_draft_other_employee_leave(self):
"""
The holiday manager should be able to do everything
"""
for i, status in enumerate(self.draft_status):
values = {
'name': 'Random Leave',
'employee_id': self.employee_hruser.id,
'holiday_status_id': status.id,
}
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
leave.with_user(self.user_hrmanager.id).action_draft()
def test_holiday_manager_draft_other_employee_leave_and_is_leave_manager_id(self):
"""
The holiday manager should be able to do everything
"""
self.employee_hruser.write({'leave_manager_id': self.user_hrmanager.id})
for i, status in enumerate(self.draft_status):
values = {
'name': 'Random Leave',
'employee_id': self.employee_hruser.id,
'holiday_status_id': status.id,
}
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
leave.with_user(self.user_hrmanager.id).action_draft()
def test_holiday_manager_draft_self_and_is_manager_id(self):
"""
The holiday manager should be able to do everything
"""
self.employee_hrmanager.write({'leave_manager_id': self.user_hrmanager.id})
for i, status in enumerate(self.draft_status):
values = {
'name': 'Random Leave',
'employee_id': self.employee_hrmanager.id,
'holiday_status_id': status.id,
}
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
leave.with_user(self.user_hrmanager.id).action_draft()
def test_holiday_manager_draft_refused_leave(self):
"""
The holiday manager should be able to do everything
"""
for i, status in enumerate(self.draft_status):
values = {
'name': 'Random Leave',
'employee_id': self.employee_hruser.id,
'holiday_status_id': status.id,
}
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
leave.action_refuse()
leave.with_user(self.user_hrmanager.id).action_draft()
def test_holiday_manager_draft_current_leave(self):
"""
The holiday manager should be able to do everything
"""
for i, status in enumerate(self.draft_status):
values = {
'name': 'Random Leave',
'employee_id': self.employee_hruser.id,
'holiday_status_id': status.id,
}
leave = self.request_leave(1, datetime.today() + relativedelta(days=-20 + i), 1, values)
leave.with_user(self.user_hrmanager.id).action_draft()
@tests.tagged('access_rights', 'access_rights_create')
class TestAccessRightsCreate(TestHrHolidaysAccessRightsCommon):
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_base_user_create_self(self):
""" A simple user can create a leave for himself """
values = {
'name': 'Hol10',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.leave_type.id,
}
self.request_leave(self.user_employee_id, datetime.today() + relativedelta(days=5), 1, values)
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_base_user_create_other(self):
""" A simple user cannot create a leave for someone else """
values = {
'name': 'Hol10',
'employee_id': self.employee_hruser_id,
'holiday_status_id': self.leave_type.id,
}
with self.assertRaises(AccessError):
self.request_leave(self.user_employee_id, datetime.today() + relativedelta(days=5), 1, values)
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_base_user_create_batch(self):
""" A simple user cannot create a leave in bacth mode (by company, by department, by tag)"""
values = {
'name': 'Hol10',
'holiday_status_id': self.leave_type.id,
'holiday_type': 'company',
'mode_company_id': 1,
}
with self.assertRaises(AccessError):
self.request_leave(self.user_employee_id, datetime.today() + relativedelta(days=5), 1, values)
# hr_holidays.group_hr_holidays_user
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_holidays_user_create_self(self):
""" A holidays user can create a leave for himself """
values = {
'name': 'Hol10',
'employee_id': self.employee_hruser_id,
'holiday_status_id': self.leave_type.id,
}
self.request_leave(self.user_hruser_id, datetime.today() + relativedelta(days=5), 1, values)
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_holidays_user_create_other(self):
""" A holidays user can create a leave for someone else """
values = {
'name': 'Hol10',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.leave_type.id,
}
self.request_leave(self.user_hruser_id, datetime.today() + relativedelta(days=5), 1, values)
# hr_holidays.group_hr_holidays_manager
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_holidays_manager_create_self(self):
""" A holidays manager can create a leave for himself """
values = {
'name': 'Hol10',
'employee_id': self.employee_hrmanager_id,
'holiday_status_id': self.leave_type.id,
}
self.request_leave(self.user_hrmanager_id, datetime.today() + relativedelta(days=5), 1, values)
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_holidays_manager_create_other(self):
""" A holidays manager can create a leave for someone else """
values = {
'name': 'Hol10',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.leave_type.id,
}
self.request_leave(self.user_hrmanager_id, datetime.today() + relativedelta(days=5), 1, values)
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_holidays_manager_create_batch(self):
""" A holidays manager can create a leave in bacth mode (by company, by department, by tag)"""
values = {
'name': 'Hol10',
'holiday_status_id': self.leave_type.id,
'holiday_type': 'company',
'mode_company_id': 1,
}
self.request_leave(self.user_hrmanager_id, datetime.today() + relativedelta(days=5), 1, values)
@tests.tagged('access_rights', 'access_rights_read')
class TestAccessRightsRead(TestHrHolidaysAccessRightsCommon):
# base.group_user
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_leave_read_by_user_other(self):
""" Users should not be able to read other people requests """
other_leave = self.env['hr.leave'].with_user(self.user_hruser).create({
'name': 'Test',
'holiday_status_id': self.leave_type.id,
'department_id': self.employee_hruser.department_id.id,
'employee_id': self.employee_hruser.id,
'date_from': datetime.now(),
'date_to': datetime.now() + relativedelta(days=1),
'number_of_days': 1,
})
with self.assertRaises(AccessError), self.cr.savepoint():
res = other_leave.with_user(self.user_employee_id).read(['number_of_days', 'state', 'name'])
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_leave_read_by_user_other_browse(self):
""" Users should not be able to browse other people requests """
other_leave = self.env['hr.leave'].with_user(self.user_hruser).create({
'name': 'Test',
'holiday_status_id': self.leave_type.id,
'department_id': self.employee_hruser.department_id.id,
'employee_id': self.employee_hruser.id,
'date_from': datetime.now(),
'date_to': datetime.now() + relativedelta(days=1),
'number_of_days': 1,
})
with self.assertRaises(AccessError), self.cr.savepoint():
other_leave.invalidate_model(['name'])
name = other_leave.with_user(self.user_employee_id).name
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_leave_read_by_user_own(self):
""" Users should be able to read name field of own requests """
res = self.employee_leave.read(['name', 'number_of_days', 'state'])
self.assertEqual(res[0]['name'], 'Test')
@tests.tagged('access_rights', 'access_rights_write')
class TestAccessRightsWrite(TestHrHolidaysAccessRightsCommon):
# base.group_user
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_leave_update_by_user(self):
""" User may update its leave """
self.employee_leave.with_user(self.user_employee_id).write({'name': 'Crocodile Dundee is my man'})
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_leave_update_by_user_other(self):
""" User cannot update other people leaves """
other_leave = self.env['hr.leave'].with_user(self.user_hruser).create({
'name': 'Test',
'holiday_status_id': self.leave_type.id,
'department_id': self.employee_hruser.department_id.id,
'employee_id': self.employee_hruser.id,
'date_from': datetime.now(),
'date_to': datetime.now() + relativedelta(days=1),
'number_of_days': 1,
})
with self.assertRaises(AccessError):
other_leave.with_user(self.user_employee_id).write({'name': 'Crocodile Dundee is my man'})
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_leave_creation_for_other_user(self):
""" Employee cannot creates a leave request for another employee """
HolidaysEmployeeGroup = self.env['hr.leave'].with_user(self.user_employee_id)
with self.assertRaises(AccessError):
HolidaysEmployeeGroup.create({
'name': 'Hol10',
'employee_id': self.employee_hruser_id,
'holiday_status_id': self.leave_type.id,
'date_from': (datetime.today() - relativedelta(days=1)),
'date_to': datetime.today(),
'number_of_days': 1,
})
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_leave_messaging_by_user(self):
""" User may communicate on its own leaves, even if validated """
self.employee_leave.with_user(self.user_employee_id).message_post(
body='I haz messaging',
subtype_xmlid='mail.mt_comment',
message_type='comment'
)
self.employee_leave.with_user(self.user_hrmanager_id).action_approve()
self.employee_leave.with_user(self.user_employee_id).message_post(
body='I still haz messaging',
subtype_xmlid='mail.mt_comment',
message_type='comment'
)
# ----------------------------------------
# Validation: one validation, HR
# ----------------------------------------
# base.group_user
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_leave_hr_to_validate_by_user(self):
""" User may not validate any leaves in HR mode """
with self.assertRaises(UserError):
self.employee_leave.with_user(self.user_employee_id).action_approve()
with self.assertRaises(UserError):
self.employee_leave.with_user(self.user_employee_id).write({'state': 'validate'})
# hr_holidays.group_hr_holidays_user
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_leave_hr_to_validate_by_holiday_user(self):
""" Manager can validate leaves in HR mode """
self.assertEqual(self.employee_leave.state, 'confirm')
self.employee_leave.with_user(self.user_hrmanager_id).action_approve()
self.assertEqual(self.employee_leave.state, 'validate')
# hr_holidays.group_hr_holidays_manager
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_leave_hr_to_validate_by_manager(self):
""" Manager validate its own leaves """
manager_leave = self.env['hr.leave'].with_user(self.user_hrmanager_id).create({
'name': 'Hol manager',
'holiday_status_id': self.leave_type.id,
'employee_id': self.employee_hrmanager_id,
'date_from': (datetime.today() + relativedelta(days=15)),
'date_to': (datetime.today() + relativedelta(days=16)),
'number_of_days': 1,
})
self.assertEqual(manager_leave.state, 'confirm')
manager_leave.action_approve()
self.assertEqual(manager_leave.state, 'validate')
# ----------------------------------------
# Validation: one validation, manager
# ----------------------------------------
# base.group_user
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_leave_manager_to_validate_by_user(self):
""" A simple user can validate in manager mode if he is leave_manager_id """
self.leave_type.write({'leave_validation_type': 'manager'})
values = {
'name': 'Hol HrUser',
'employee_id': self.employee_hruser_id,
'holiday_status_id': self.leave_type.id,
'state': 'confirm',
}
hr_leave = self.request_leave(self.user_hruser_id, datetime.now() + relativedelta(days=2), 1, values)
with self.assertRaises(AccessError):
hr_leave.with_user(self.user_employee_id).action_approve()
self.employee_hruser.write({'leave_manager_id': self.user_employee_id})
hr_leave.with_user(self.user_employee_id).action_approve()
# hr_holidays.group_hr_holidays_user
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_leave_manager_to_validate_by_holiday_user(self):
""" A holiday user can validate in manager mode """
self.leave_type.write({'leave_validation_type': 'manager'})
values = {
'name': 'Hol HrUser',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.leave_type.id,
'state': 'confirm',
}
hr_leave = self.request_leave(self.user_hruser_id, datetime.now() + relativedelta(days=2), 1, values)
hr_leave.with_user(self.user_hruser_id).action_approve()
# ----------------------------------------
# Validation: double
# ----------------------------------------
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_leave_double_validate(self):
self.leave_type.write({'leave_validation_type': 'both'})
values = {
'name': 'double HrManager',
'employee_id': self.employee_hrmanager_id,
'holiday_status_id': self.leave_type.id,
'state': 'confirm',
}
self.employee_hrmanager.leave_manager_id = self.env['res.users'].browse(1)
hr_leave = self.request_leave(self.user_hruser_id, datetime.now() + relativedelta(days=6), 1, values)
with self.assertRaises(AccessError):
hr_leave.with_user(self.user_employee_id).action_approve()
self.employee_hrmanager.leave_manager_id = self.user_hruser
hr_leave.with_user(self.user_hruser_id).action_approve()
with self.assertRaises(AccessError):
hr_leave.with_user(self.user_employee_id).action_validate()
hr_leave.with_user(self.user_hruser_id).action_validate()
# hr_holidays.group_hr_holidays_manager
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_leave_double_validate_holiday_manager(self):
self.leave_type.write({'leave_validation_type': 'both'})
values = {
'name': 'double HrManager',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.leave_type.id,
'state': 'confirm',
}
hr_leave = self.request_leave(self.user_hrmanager_id, datetime.now() + relativedelta(days=4), 1, values).with_user(self.user_hrmanager_id)
hr_leave.action_approve()
hr_leave.action_validate()
# ----------------------------------------
# State = Refuse
# ----------------------------------------
# base.group_user
# hr_holidays.group_hr_holidays_user
# TODO Can refuse
# hr_holidays.group_hr_holidays_manager
# TODO Can refuse
# ----------------------------------------
# State = Cancel
# ----------------------------------------
# base.group_user
# TODO Can Cancel if start_date in the future
# hr_holidays.group_hr_holidays_user
# TODO Can Cancel if not in validate
# hr_holidays.group_hr_holidays_manager
# TODO Can always cancel with great powers comes great responbilities
class TestAccessRightsUnlink(TestHrHolidaysAccessRightsCommon):
# base.group_user
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_leave_unlink_draft_by_user(self):
""" A simple user may delete its leave in draft state in the future"""
values = {
'name': 'Random Leave',
'employee_id': self.employee_emp.id,
'holiday_status_id': self.leave_type.id,
'state': 'draft',
}
leave = self.request_leave(self.user_employee_id, datetime.now() + relativedelta(days=5), 1, values)
leave.with_user(self.user_employee.id).unlink()
def test_leave_unlink_confirm_by_user(self):
""" A simple user may delete its leave in confirm state in the future"""
values = {
'name': 'Random Leave',
'employee_id': self.employee_emp.id,
'holiday_status_id': self.leave_type.id,
'state': 'confirm',
}
leave = self.request_leave(self.user_employee_id, datetime.now() + relativedelta(days=5), 1, values)
leave.with_user(self.user_employee.id).unlink()
def test_leave_unlink_confirm_in_past_by_user(self):
""" A simple user cannot delete past leaves, but can delete today's leave"""
values = {
'name': 'Random Leave',
'employee_id': self.employee_emp.id,
'holiday_status_id': self.leave_type.id,
'state': 'confirm',
}
with freeze_time('2024-5-23 13:00:00'):
other_leave = self.request_leave(self.user_employee_id, datetime.now() + relativedelta(hours=-4), 1, values)
other_leave.with_user(self.user_employee.id).unlink()
leave = self.request_leave(self.user_employee_id, datetime.now() + relativedelta(days=-4), 1, values)
with self.assertRaises(UserError), self.cr.savepoint():
leave.with_user(self.user_employee.id).unlink()
def test_leave_unlink_validate_by_user(self):
""" A simple user cannot delete its leave in validate state"""
values = {
'name': 'Random Leave',
'employee_id': self.employee_emp.id,
'holiday_status_id': self.leave_type.id,
}
leave = self.request_leave(self.user_employee_id, datetime.now() + relativedelta(days=5), 1, values)
leave.with_user(self.user_hrmanager_id).write({'state': 'validate'})
with self.assertRaises(UserError), self.cr.savepoint():
leave.with_user(self.user_employee.id).unlink()
class TestMultiCompany(TestHrHolidaysCommon):
@classmethod
def setUpClass(cls):
super(TestMultiCompany, cls).setUpClass()
cls.new_company = cls.env['res.company'].create({
'name': 'Crocodile Dundee Company',
})
cls.leave_type = cls.env['hr.leave.type'].create({
'name': 'Unlimited - Company New',
'company_id': cls.new_company.id,
'leave_validation_type': 'hr',
'requires_allocation': 'no',
})
cls.rd_dept.manager_id = False
cls.hr_dept.manager_id = False
cls.employee_leave = cls.env['hr.leave'].create({
'name': 'Test',
'holiday_status_id': cls.leave_type.id,
'department_id': cls.employee_emp.department_id.id,
'employee_id': cls.employee_emp.id,
'date_from': datetime.now(),
'date_to': datetime.now() + relativedelta(days=1),
'number_of_days': 1,
})
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_leave_access_other_company_user(self):
employee_leave = self.employee_leave.with_user(self.user_employee)
employee_leave.invalidate_model(['name'])
with self.assertRaises(AccessError):
employee_leave.name
with self.assertRaises(AccessError):
employee_leave.action_approve()
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_leave_access_other_company_officer(self):
employee_leave_hruser = self.employee_leave.with_user(self.user_hruser)
employee_leave_hruser.invalidate_model(['name'])
with self.assertRaises(AccessError):
employee_leave_hruser.name
with self.assertRaises(AccessError):
employee_leave_hruser.action_approve()
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_leave_access_other_company_manager(self):
employee_leave_hrmanager = self.employee_leave.with_user(self.user_hrmanager)
employee_leave_hrmanager.invalidate_model(['name'])
with self.assertRaises(AccessError):
employee_leave_hrmanager.name
with self.assertRaises(AccessError):
employee_leave_hrmanager.action_approve()
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_leave_access_no_company_user(self):
self.leave_type.write({'company_id': False})
employee_leave = self.employee_leave.with_user(self.user_employee)
employee_leave.name
with self.assertRaises(UserError):
employee_leave.action_approve()
self.assertEqual(employee_leave.state, 'confirm')
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_leave_access_no_company_officer(self):
self.leave_type.write({'company_id': False})
employee_leave_hruser = self.employee_leave.with_user(self.user_hruser)
employee_leave_hruser.name
employee_leave_hruser.action_approve()
self.assertEqual(employee_leave_hruser.state, 'validate')
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_leave_access_no_company_manager(self):
self.leave_type.write({'company_id': False})
employee_leave_hrmanager = self.employee_leave.with_user(self.user_hrmanager)
employee_leave_hrmanager.name
employee_leave_hrmanager.action_approve()
self.assertEqual(employee_leave_hrmanager.state, 'validate')

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,215 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import tests
from odoo.addons.hr_holidays.tests.common import TestHrHolidaysCommon
from odoo.exceptions import AccessError, UserError
import time
class TestAllocationRights(TestHrHolidaysCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.rd_dept.manager_id = False
cls.hr_dept.manager_id = False
cls.employee_emp.parent_id = False
cls.employee_emp.leave_manager_id = False
cls.lt_no_allocation = cls.env['hr.leave.type'].create({
'name': 'Validation = HR',
'allocation_validation_type': 'officer',
'requires_allocation': 'no',
'employee_requests': 'yes',
})
cls.lt_validation_manager = cls.env['hr.leave.type'].create({
'name': 'Validation = manager',
'allocation_validation_type': 'officer',
'requires_allocation': 'yes',
'employee_requests': 'yes',
})
cls.lt_allocation_no_validation = cls.env['hr.leave.type'].create({
'name': 'Validation = user',
'allocation_validation_type': 'no',
'requires_allocation': 'yes',
'employee_requests': 'yes',
})
def request_allocation(self, user, values={}):
values = dict(values, **{
'name': 'Allocation',
'number_of_days': 1,
'date_from': time.strftime('%Y-01-01'),
'date_to': time.strftime('%Y-12-31'),
})
return self.env['hr.leave.allocation'].with_user(user).create(values)
class TestAccessRightsSimpleUser(TestAllocationRights):
def test_simple_user_request_allocation(self):
""" A simple user can request an allocation but not approve it """
values = {
'employee_id': self.employee_emp.id,
'holiday_status_id': self.lt_validation_manager.id,
}
allocation = self.request_allocation(self.user_employee.id, values)
with self.assertRaises(UserError):
allocation.action_validate()
def test_simple_user_request_allocation_no_validation(self):
""" A simple user can request and automatically validate an allocation with no validation """
values = {
'employee_id': self.employee_emp.id,
'holiday_status_id': self.lt_allocation_no_validation.id,
}
allocation = self.request_allocation(self.user_employee.id, values)
self.assertEqual(allocation.state, 'validate', "It should be validated")
def test_simple_user_request_allocation_no_validation_other(self):
""" A simple user cannot request an other user's allocation with no validation """
values = {
'employee_id': self.employee_hruser.id,
'holiday_status_id': self.lt_allocation_no_validation.id,
}
with self.assertRaises(AccessError):
self.request_allocation(self.user_employee.id, values)
def test_simple_user_reset_to_draft(self):
""" A simple user can reset to draft only his own allocation """
values = {
'employee_id': self.employee_emp.id,
'holiday_status_id': self.lt_validation_manager.id,
}
allocation = self.request_allocation(self.user_employee.id, values)
self.assertEqual(allocation.state, 'draft')
allocation.action_confirm()
self.assertEqual(allocation.state, 'confirm', "It should be confirmed")
allocation.action_draft()
self.assertEqual(allocation.state, 'draft', "It should have been reset to draft")
class TestAccessRightsEmployeeManager(TestAllocationRights):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.managed_employee = cls.env['hr.employee'].create({
'name': 'Jolly Jumper',
'leave_manager_id': cls.user_employee.id,
})
def test_manager_request_allocation_other(self):
""" A manager cannot request and approve an allocation for employees he doesn't manage """
values = {
'employee_id': self.employee_hruser.id,
'holiday_status_id': self.lt_validation_manager.id,
}
with self.assertRaises(AccessError):
self.request_allocation(self.user_employee.id, values) # user is not the employee's manager
def test_manager_approve_request_allocation(self):
""" A manager can request and approve an allocation for managed employees """
values = {
'employee_id': self.managed_employee.id,
'holiday_status_id': self.lt_validation_manager.id,
}
allocation = self.request_allocation(self.user_employee.id, values)
allocation.action_confirm()
allocation.action_validate()
self.assertEqual(allocation.state, 'validate', "The allocation should be validated")
def test_manager_refuse_request_allocation(self):
""" A manager can request and refuse an allocation for managed employees """
values = {
'employee_id': self.managed_employee.id,
'holiday_status_id': self.lt_validation_manager.id,
}
allocation = self.request_allocation(self.user_employee.id, values)
allocation.action_confirm()
allocation.action_refuse()
self.assertEqual(allocation.state, 'refuse', "The allocation should be validated")
def test_manager_batch_allocation(self):
""" A manager cannot create batch allocation """
values = {
'holiday_status_id': self.lt_validation_manager.id,
'holiday_type': 'company',
'mode_company_id': self.user_employee.company_id.id,
}
with self.assertRaises(AccessError):
self.request_allocation(self.user_employee.id, values)
def test_manager_approve_own(self):
""" A manager cannot approve his own allocation """
values = {
'employee_id': self.user_employee.employee_id.id,
'holiday_status_id': self.lt_validation_manager.id,
}
allocation = self.request_allocation(self.user_employee.id, values)
with self.assertRaises(UserError):
allocation.action_validate()
class TestAccessRightsHolidayUser(TestAllocationRights):
def test_holiday_user_request_allocation(self):
""" A holiday user can request and approve an allocation for any employee """
values = {
'employee_id': self.employee_emp.id,
'holiday_status_id': self.lt_validation_manager.id,
}
allocation = self.request_allocation(self.user_hruser.id, values)
allocation.action_confirm()
allocation.action_validate()
self.assertEqual(allocation.state, 'validate', "It should have been validated")
def test_holiday_user_batch_allocation(self):
""" A holiday user cannot create a batch allocation """
values = {
'holiday_status_id': self.lt_validation_manager.id,
'holiday_type': 'company',
'mode_company_id': self.user_employee.company_id.id,
}
with self.assertRaises(AccessError):
self.request_allocation(self.user_hruser.id, values)
def test_holiday_user_cannot_approve_own(self):
""" A holiday user cannot approve his own allocation """
values = {
'employee_id': self.employee_hruser.id,
'holiday_status_id': self.lt_validation_manager.id,
}
allocation = self.request_allocation(self.user_hruser.id, values)
allocation.action_confirm()
with self.assertRaises(UserError):
allocation.action_validate()
class TestAccessRightsHolidayManager(TestAllocationRights):
def test_holiday_manager_can_approve_own(self):
""" A holiday manager can approve his own allocation """
values = {
'employee_id': self.employee_hrmanager.id,
'holiday_status_id': self.lt_validation_manager.id,
}
allocation = self.request_allocation(self.user_hrmanager.id, values)
allocation.action_confirm()
allocation.action_validate()
self.assertEqual(allocation.state, 'validate', "It should have been validated")
def test_holiday_manager_refuse_validated(self):
""" A holiday manager can refuse a validated allocation """
values = {
'employee_id': self.employee_emp.id,
'holiday_status_id': self.lt_validation_manager.id,
}
allocation = self.request_allocation(self.user_hrmanager.id, values)
allocation.action_confirm()
allocation.action_validate()
self.assertEqual(allocation.state, 'validate', "It should have been validated")
allocation.action_refuse()
self.assertEqual(allocation.state, 'refuse', "It should have been refused")

View file

@ -0,0 +1,294 @@
# -*- coding: utf-8 -*-
from datetime import date, datetime
from odoo.tests.common import Form
from odoo.addons.hr_holidays.tests.common import TestHrHolidaysCommon
from odoo.exceptions import ValidationError
class TestAutomaticLeaveDates(TestHrHolidaysCommon):
@classmethod
def setUpClass(cls):
super(TestAutomaticLeaveDates, cls).setUpClass()
cls.leave_type = cls.env['hr.leave.type'].create({
'name': 'Automatic Test',
'time_type': 'leave',
'requires_allocation': 'no',
# Required for `request_unit_half` to be visible in the view
'request_unit': 'half_day',
})
def test_no_attendances(self):
calendar = self.env['resource.calendar'].create({
'name': 'No Attendances',
'attendance_ids': [(5, 0, 0)],
})
employee = self.employee_emp
employee.resource_calendar_id = calendar
with Form(self.env['hr.leave'].with_context(default_employee_id=employee.id)) as leave_form:
leave_form.holiday_status_id = self.leave_type
leave_form.request_date_from = date(2019, 9, 2)
leave_form.request_date_to = date(2019, 9, 2)
leave_form.request_unit_half = True
leave_form.request_date_from_period = 'am'
self.assertEqual(leave_form.number_of_days_display, 0)
self.assertEqual(leave_form.number_of_hours_text, '0 Hours')
def test_single_attendance_on_morning_and_afternoon(self):
calendar = self.env['resource.calendar'].create({
'name': 'simple morning + afternoon',
'attendance_ids': [(5, 0, 0),
(0, 0, {
'name': 'monday morning',
'hour_from': 8,
'hour_to': 12,
'day_period': 'morning',
'dayofweek': '0',
}),
(0, 0, {
'name': 'monday afternoon',
'hour_from': 13,
'hour_to': 17,
'day_period': 'afternoon',
'dayofweek': '0',
})]
})
employee = self.employee_emp
employee.resource_calendar_id = calendar
with Form(self.env['hr.leave'].with_context(default_employee_id=employee.id)) as leave_form:
leave_form.holiday_status_id = self.leave_type
leave_form.request_date_from = date(2019, 9, 2)
leave_form.request_date_to = date(2019, 9, 2)
leave_form.request_unit_half = True
leave_form.request_date_from_period = 'am'
self.assertEqual(leave_form.number_of_days_display, .5)
self.assertEqual(leave_form.number_of_hours_text, '4 Hours')
leave_form.request_date_from_period = 'pm'
self.assertEqual(leave_form.number_of_days_display, .5)
self.assertEqual(leave_form.number_of_hours_text, '4 Hours')
def test_multiple_attendance_on_morning(self):
calendar = self.env['resource.calendar'].create({
'name': 'multi morning',
'attendance_ids': [(5, 0, 0),
(0, 0, {
'name': 'monday morning 1',
'hour_from': 8,
'hour_to': 10,
'day_period': 'morning',
'dayofweek': '0',
}),
(0, 0, {
'name': 'monday morning 2',
'hour_from': 10.25,
'hour_to': 12.25,
'day_period': 'morning',
'dayofweek': '0',
}),
(0, 0, {
'name': 'monday afternoon',
'hour_from': 13,
'hour_to': 17,
'day_period': 'afternoon',
'dayofweek': '0',
})]
})
employee = self.employee_emp
employee.resource_calendar_id = calendar
with Form(self.env['hr.leave'].with_context(default_employee_id=employee.id)) as leave_form:
leave_form.holiday_status_id = self.leave_type
leave_form.request_date_from = date(2019, 9, 2)
leave_form.request_date_to = date(2019, 9, 2)
leave_form.request_unit_half = True
leave_form.request_date_from_period = 'am'
self.assertEqual(leave_form.number_of_days_display, .5)
self.assertEqual(leave_form.number_of_hours_text, '4 Hours')
leave_form.request_date_from_period = 'pm'
self.assertEqual(leave_form.number_of_days_display, .5)
self.assertEqual(leave_form.number_of_hours_text, '4 Hours')
def test_attendance_on_morning(self):
calendar = self.env['resource.calendar'].create({
'name': 'Morning only',
'attendance_ids': [(5, 0, 0),
(0, 0, {
'name': 'Monday All day',
'hour_from': 8,
'hour_to': 16,
'day_period': 'morning',
'dayofweek': '0',
})],
})
employee = self.employee_emp
employee.resource_calendar_id = calendar
with Form(self.env['hr.leave'].with_context(default_employee_id=employee.id)) as leave_form:
leave_form.holiday_status_id = self.leave_type
leave_form.request_date_from = date(2019, 9, 2)
leave_form.request_date_to = date(2019, 9, 2)
leave_form.request_unit_half = True
# Ask for morning
leave_form.request_date_from_period = 'am'
self.assertEqual(leave_form.number_of_days_display, 0.5)
self.assertEqual(leave_form.number_of_hours_text, '8 Hours')
# Ask for afternoon
leave_form.request_date_from_period = 'pm'
self.assertEqual(leave_form.number_of_days_display, 0.5)
self.assertEqual(leave_form.number_of_hours_text, '8 Hours')
def test_attendance_next_day(self):
self.env.user.tz = 'Europe/Brussels'
calendar = self.env['resource.calendar'].create({
'name': 'auto next day',
'attendance_ids': [(5, 0, 0),
(0, 0, {
'name': 'tuesday morning',
'hour_from': 8,
'hour_to': 12,
'day_period': 'morning',
'dayofweek': '1',
})]
})
employee = self.employee_emp
employee.resource_calendar_id = calendar
with Form(self.env['hr.leave'].with_context(default_employee_id=employee.id)) as leave_form:
leave_form.holiday_status_id = self.leave_type
# does not work on mondays
leave_form.request_date_from = date(2019, 9, 2)
leave_form.request_date_to = date(2019, 9, 2)
leave_form.request_unit_half = True
leave_form.request_date_from_period = 'am'
self.assertEqual(leave_form.number_of_days_display, 0)
self.assertEqual(leave_form.number_of_hours_text, '0 Hours')
self.assertEqual(leave_form.date_from, datetime(2019, 9, 2, 6, 0, 0))
self.assertEqual(leave_form.date_to, datetime(2019, 9, 2, 10, 0, 0))
def test_attendance_previous_day(self):
self.env.user.tz = 'Europe/Brussels'
calendar = self.env['resource.calendar'].create({
'name': 'auto next day',
'attendance_ids': [(5, 0, 0),
(0, 0, {
'name': 'monday morning',
'hour_from': 8,
'hour_to': 12,
'day_period': 'morning',
'dayofweek': '0',
})]
})
employee = self.employee_emp
employee.resource_calendar_id = calendar
with Form(self.env['hr.leave'].with_context(default_employee_id=employee.id)) as leave_form:
leave_form.holiday_status_id = self.leave_type
# does not work on tuesdays
leave_form.request_date_from = date(2019, 9, 3)
leave_form.request_date_to = date(2019, 9, 3)
leave_form.request_unit_half = True
leave_form.request_date_from_period = 'am'
self.assertEqual(leave_form.number_of_days_display, 0)
self.assertEqual(leave_form.number_of_hours_text, '0 Hours')
self.assertEqual(leave_form.date_from, datetime(2019, 9, 3, 6, 0, 0))
self.assertEqual(leave_form.date_to, datetime(2019, 9, 3, 10, 0, 0))
def test_2weeks_calendar(self):
self.env.user.tz = 'Europe/Brussels'
calendar = self.env['resource.calendar'].create({
'name': 'auto next day',
'two_weeks_calendar': True,
'attendance_ids': [(5, 0, 0),
(0, 0, {
'name': 'monday morning odd week',
'hour_from': 8,
'hour_to': 12,
'day_period': 'morning',
'dayofweek': '0',
'week_type': '0',
}),
(0, 0, {
'name': 'monday morning even week',
'hour_from': 10,
'hour_to': 12,
'day_period': 'morning',
'dayofweek': '0',
'week_type': '1',
})]
})
employee = self.employee_emp
employee.resource_calendar_id = calendar
with Form(self.env['hr.leave'].with_context(default_employee_id=employee.id)) as leave_form:
leave_form.holiday_status_id = self.leave_type
# even week, works 2 hours
leave_form.request_date_from = date(2019, 9, 2)
leave_form.request_date_to = date(2019, 9, 2)
leave_form.request_unit_half = True
leave_form.request_date_from_period = 'am'
self.assertEqual(leave_form.number_of_days_display, 0.5)
self.assertEqual(leave_form.number_of_hours_text, '2 Hours')
self.assertEqual(leave_form.date_from, datetime(2019, 9, 2, 8, 0, 0))
self.assertEqual(leave_form.date_to, datetime(2019, 9, 2, 10, 0, 0))
with Form(self.env['hr.leave'].with_context(default_employee_id=employee.id)) as leave_form:
leave_form.holiday_status_id = self.leave_type
# odd week, works 4 hours
leave_form.request_date_from = date(2019, 9, 9)
leave_form.request_date_to = date(2019, 9, 9)
leave_form.request_unit_half = True
leave_form.request_date_from_period = 'am'
self.assertEqual(leave_form.number_of_days_display, 0.5)
self.assertEqual(leave_form.number_of_hours_text, '4 Hours')
self.assertEqual(leave_form.date_from, datetime(2019, 9, 9, 6, 0, 0))
self.assertEqual(leave_form.date_to, datetime(2019, 9, 9, 10, 0, 0))
def test_2weeks_calendar_next_week(self):
self.env.user.tz = 'Europe/Brussels'
calendar = self.env['resource.calendar'].create({
'name': 'auto next day',
'two_weeks_calendar': True,
'attendance_ids': [(5, 0, 0),
(0, 0, {
'name': 'monday morning odd week',
'hour_from': 8,
'hour_to': 12,
'day_period': 'morning',
'dayofweek': '0',
'week_type': '0',
})]
})
employee = self.employee_emp
employee.resource_calendar_id = calendar
with Form(self.env['hr.leave'].with_context(default_employee_id=employee.id)) as leave_form:
leave_form.holiday_status_id = self.leave_type
# even week, does not work
leave_form.request_date_from = date(2019, 9, 2)
leave_form.request_date_to = date(2019, 9, 2)
leave_form.request_unit_half = True
leave_form.request_date_from_period = 'am'
self.assertEqual(leave_form.number_of_days_display, 0)
self.assertEqual(leave_form.number_of_hours_text, '0 Hours')
self.assertEqual(leave_form.date_from, datetime(2019, 9, 2, 6, 0, 0))
self.assertEqual(leave_form.date_to, datetime(2019, 9, 2, 10, 0, 0))

View file

@ -0,0 +1,66 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import datetime
from dateutil.relativedelta import relativedelta
from odoo.addons.hr_holidays.tests.common import TestHrHolidaysCommon
class TestChangeDepartment(TestHrHolidaysCommon):
def test_employee_change_department_request_change_department(self):
self.HolidaysEmployeeGroup = self.env['hr.leave'].with_user(self.user_employee_id)
HolidayStatusManagerGroup = self.env['hr.leave.type'].with_user(self.user_hrmanager_id)
self.holidays_status_1 = HolidayStatusManagerGroup.create({
'name': 'NotLimitedHR',
'requires_allocation': 'no',
})
def create_holiday(name, start, end):
return self.HolidaysEmployeeGroup.create({
'name': name,
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_status_1.id,
'date_from': (datetime.today() + relativedelta(days=start)).strftime('%Y-%m-%d %H:%M'),
'date_to': datetime.today() + relativedelta(days=end),
'number_of_days': end-start,
})
# Non approved leave request change department
self.employee_emp.department_id = self.rd_dept
hol1_employee_group = create_holiday("hol1", 1, 2)
self.employee_emp.department_id = self.hr_dept
self.assertEqual(hol1_employee_group.department_id, self.hr_dept, 'hr_holidays: non approved leave request should change department if employee change department')
# Approved passed leave request change department
self.employee_emp.department_id = self.hr_dept
hol2_employee_group = create_holiday("hol2", -4, -3)
hol2_user_group = hol2_employee_group.with_user(self.user_hruser_id)
hol2_user_group.action_approve()
self.employee_emp.department_id = self.rd_dept
self.assertEqual(hol2_employee_group.department_id, self.hr_dept, 'hr_holidays: approved passed leave request should stay in previous department if employee change department')
# Approved futur leave request change department
self.employee_emp.department_id = self.hr_dept
hol22_employee_group = create_holiday("hol22", 3, 4)
hol22_user_group = hol22_employee_group.with_user(self.user_hruser_id)
hol22_user_group.action_approve()
self.employee_emp.department_id = self.rd_dept
self.assertEqual(hol22_employee_group.department_id, self.rd_dept, 'hr_holidays: approved futur leave request should change department if employee change department')
# Refused passed leave request change department
self.employee_emp.department_id = self.rd_dept
hol3_employee_group = create_holiday("hol3", -6, -5)
hol3_user_group = hol3_employee_group.with_user(self.user_hruser_id)
hol3_user_group.action_refuse()
self.employee_emp.department_id = self.hr_dept # Change department
self.assertEqual(hol3_employee_group.department_id, self.rd_dept, 'hr_holidays: refused passed leave request should stay in previous department if employee change department')
# Refused futur leave request change department
self.employee_emp.department_id = self.rd_dept
hol32_employee_group = create_holiday("hol32", 5, 6)
hol32_user_group = hol32_employee_group.with_user(self.user_hruser_id)
hol32_user_group.action_refuse()
self.employee_emp.department_id = self.hr_dept # Change department
self.assertEqual(hol32_employee_group.department_id, self.hr_dept, 'hr_holidays: refused futur leave request should change department if employee change department')

View file

@ -0,0 +1,514 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import date, datetime
from odoo.tests import tagged
from odoo.tests.common import TransactionCase, warmup
@tagged('company_leave')
class TestCompanyLeave(TransactionCase):
""" Test leaves for a whole company, conflict resolutions """
@classmethod
def setUpClass(cls):
super(TestCompanyLeave, cls).setUpClass()
cls.company = cls.env['res.company'].create({'name': 'A company'})
cls.company.resource_calendar_id.tz = "Europe/Brussels"
cls.bank_holiday = cls.env['hr.leave.type'].create({
'name': 'Bank Holiday',
'responsible_id': cls.env.user.id,
'company_id': cls.company.id,
'requires_allocation': 'no',
})
cls.paid_time_off = cls.env['hr.leave.type'].create({
'name': 'Paid Time Off',
'request_unit': 'day',
'leave_validation_type': 'both',
'company_id': cls.company.id,
'requires_allocation': 'no',
})
cls.employee = cls.env['hr.employee'].create({
'name': 'My Employee',
'company_id': cls.company.id,
'tz': "Europe/Brussels",
})
cls.paid_time_off_hours = cls.env['hr.leave.type'].create({
'name': 'Paid Time Off in Hours',
'request_unit': 'hour',
'leave_validation_type': 'no_validation',
'company_id': cls.company.id,
'time_type': 'other',
'requires_allocation': 'yes',
})
def test_leave_whole_company_01(self):
# TEST CASE 1: Leaves taken in days. Take a 3 days leave
# Add a company leave on the second day.
# Check that leave is split into 2.
leave = self.env['hr.leave'].create({
'name': 'Hol11',
'employee_id': self.employee.id,
'holiday_status_id': self.paid_time_off.id,
'request_date_from': date(2020, 1, 7),
'date_from': date(2020, 1, 7),
'request_date_to': date(2020, 1, 9),
'date_to': date(2020, 1, 9),
'number_of_days': 3,
})
leave._compute_date_from_to()
company_leave = self.env['hr.leave'].create({
'name': 'Bank Holiday',
'holiday_type': 'company',
'mode_company_id': self.company.id,
'holiday_status_id': self.bank_holiday.id,
'date_from': date(2020, 1, 8),
'request_date_from': date(2020, 1, 8),
'date_to': date(2020, 1, 8),
'request_date_to': date(2020, 1, 8),
'number_of_days': 1,
})
company_leave._compute_date_from_to()
company_leave.action_validate()
all_leaves = self.env['hr.leave'].search([('employee_id', '=', self.employee.id)], order='id')
self.assertEqual(len(all_leaves), 4)
# Original Leave
self.assertEqual(leave.state, 'refuse')
# before leave
self.assertEqual(all_leaves[1].date_from, datetime(2020, 1, 7, 7, 0))
self.assertEqual(all_leaves[1].date_to, datetime(2020, 1, 7, 16, 0))
self.assertEqual(all_leaves[1].number_of_days, 1)
self.assertEqual(all_leaves[1].state, 'confirm')
# After leave
self.assertEqual(all_leaves[2].date_from, datetime(2020, 1, 9, 7, 0))
self.assertEqual(all_leaves[2].date_to, datetime(2020, 1, 9, 16, 0))
self.assertEqual(all_leaves[2].number_of_days, 1)
self.assertEqual(all_leaves[2].state, 'confirm')
# Company Leave
self.assertEqual(all_leaves[3].date_from, datetime(2020, 1, 8, 7, 0))
self.assertEqual(all_leaves[3].date_to, datetime(2020, 1, 8, 16, 0))
self.assertEqual(all_leaves[3].number_of_days, 1)
self.assertEqual(all_leaves[3].state, 'validate')
def test_leave_whole_company_02(self):
# TEST CASE 2: Leaves taken in half-days. Take a 3 days leave
# Add a company leave on the second day
# Check that leave is split into 2
self.paid_time_off.request_unit = 'half_day'
leave = self.env['hr.leave'].create({
'name': 'Hol11',
'employee_id': self.employee.id,
'holiday_status_id': self.paid_time_off.id,
'request_date_from': date(2020, 1, 7),
'date_from': date(2020, 1, 7),
'request_date_to': date(2020, 1, 9),
'date_to': date(2020, 1, 9),
'number_of_days': 3,
})
leave._compute_date_from_to()
company_leave = self.env['hr.leave'].create({
'name': 'Bank Holiday',
'holiday_type': 'company',
'mode_company_id': self.company.id,
'holiday_status_id': self.bank_holiday.id,
'date_from': date(2020, 1, 8),
'request_date_from': date(2020, 1, 8),
'date_to': date(2020, 1, 8),
'request_date_to': date(2020, 1, 8),
'number_of_days': 1,
})
company_leave._compute_date_from_to()
company_leave.action_validate()
all_leaves = self.env['hr.leave'].search([('employee_id', '=', self.employee.id)], order='id')
self.assertEqual(len(all_leaves), 4)
# Original Leave
self.assertEqual(leave.state, 'refuse')
# before leave
self.assertEqual(all_leaves[1].date_from, datetime(2020, 1, 7, 7, 0))
self.assertEqual(all_leaves[1].date_to, datetime(2020, 1, 7, 16, 0))
self.assertEqual(all_leaves[1].number_of_days, 1)
self.assertEqual(all_leaves[1].state, 'confirm')
# After leave
self.assertEqual(all_leaves[2].date_from, datetime(2020, 1, 9, 7, 0))
self.assertEqual(all_leaves[2].date_to, datetime(2020, 1, 9, 16, 0))
self.assertEqual(all_leaves[2].number_of_days, 1)
self.assertEqual(all_leaves[2].state, 'confirm')
# Company Leave
self.assertEqual(all_leaves[3].date_from, datetime(2020, 1, 8, 7, 0))
self.assertEqual(all_leaves[3].date_to, datetime(2020, 1, 8, 16, 0))
self.assertEqual(all_leaves[3].number_of_days, 1)
self.assertEqual(all_leaves[3].state, 'validate')
def test_leave_whole_company_03(self):
# TEST CASE 3: Leaves taken in half-days. Take a 0.5 days leave
# Add a company leave on the same day
# Check that leave refused
self.paid_time_off.request_unit = 'half_day'
leave = self.env['hr.leave'].create({
'name': 'Hol11',
'employee_id': self.employee.id,
'holiday_status_id': self.paid_time_off.id,
'date_from': date(2020, 1, 7),
'request_date_from': date(2020, 1, 7),
'date_to': date(2020, 1, 7),
'request_date_to': date(2020, 1, 7),
'number_of_days': 0.5,
'request_unit_half': True,
'request_date_from_period': 'am',
})
leave._compute_date_from_to()
company_leave = self.env['hr.leave'].create({
'name': 'Bank Holiday',
'holiday_type': 'company',
'mode_company_id': self.company.id,
'holiday_status_id': self.bank_holiday.id,
'date_from': date(2020, 1, 7),
'request_date_from': date(2020, 1, 7),
'date_to': date(2020, 1, 7),
'request_date_to': date(2020, 1, 7),
'number_of_days': 1,
})
company_leave._compute_date_from_to()
company_leave.action_validate()
all_leaves = self.env['hr.leave'].search([('employee_id', '=', self.employee.id)], order='id')
self.assertEqual(len(all_leaves), 2)
# Original Leave
self.assertEqual(leave.state, 'refuse')
# Company Leave
self.assertEqual(all_leaves[1].date_from, datetime(2020, 1, 7, 7, 0))
self.assertEqual(all_leaves[1].date_to, datetime(2020, 1, 7, 16, 0))
self.assertEqual(all_leaves[1].number_of_days, 1)
self.assertEqual(all_leaves[1].state, 'validate')
def test_leave_whole_company_04(self):
# TEST CASE 4: Leaves taken in days. Take a 1 days leave
# Add a company leave on the same day
# Check that leave is refused
self.paid_time_off.request_unit = 'day'
leave = self.env['hr.leave'].create({
'name': 'Hol11',
'employee_id': self.employee.id,
'holiday_status_id': self.paid_time_off.id,
'date_from': datetime.now(),
'request_date_from': date(2020, 1, 9),
'date_to': datetime.now(),
'request_date_to': date(2020, 1, 9),
'number_of_days': 1,
})
leave._compute_date_from_to()
company_leave = self.env['hr.leave'].create({
'name': 'Bank Holiday',
'holiday_type': 'company',
'mode_company_id': self.company.id,
'holiday_status_id': self.bank_holiday.id,
'date_from': date(2020, 1, 9),
'request_date_from': date(2020, 1, 9),
'date_to': date(2020, 1, 9),
'request_date_to': date(2020, 1, 9),
'number_of_days': 1,
})
company_leave._compute_date_from_to()
company_leave.action_validate()
all_leaves = self.env['hr.leave'].search([('employee_id', '=', self.employee.id)], order='id')
self.assertEqual(len(all_leaves), 2)
# Original Leave
self.assertEqual(leave.state, 'refuse')
# Company Leave
self.assertEqual(all_leaves[1].date_from, datetime(2020, 1, 9, 7, 0))
self.assertEqual(all_leaves[1].date_to, datetime(2020, 1, 9, 16, 0))
self.assertEqual(all_leaves[1].number_of_days, 1)
self.assertEqual(all_leaves[1].state, 'validate')
def test_leave_whole_company_06(self):
# Test case 6: Leaves taken in days. But the employee
# only works on Monday, Wednesday and Friday
# Takes a time off for all the week (3 days), should be split
self.employee.resource_calendar_id.write({'attendance_ids': [
(5, 0, 0),
(0, 0, {'name': 'Monday Morning', 'dayofweek': '0', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Monday Afternoon', 'dayofweek': '0', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'}),
(0, 0, {'name': 'Wednesday Morning', 'dayofweek': '2', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Wednesday Afternoon', 'dayofweek': '2', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'}),
(0, 0, {'name': 'Friday Morning', 'dayofweek': '4', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Friday Afternoon', 'dayofweek': '4', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'})
]})
leave = self.env['hr.leave'].create({
'name': 'Hol11',
'employee_id': self.employee.id,
'holiday_status_id': self.paid_time_off.id,
'date_from': date(2020, 1, 6),
'request_date_from': date(2020, 1, 6),
'date_to': date(2020, 1, 10),
'request_date_to': date(2020, 1, 10),
'number_of_days': 3,
})
leave._compute_date_from_to()
company_leave = self.env['hr.leave'].create({
'name': 'Bank Holiday',
'holiday_type': 'company',
'mode_company_id': self.company.id,
'holiday_status_id': self.bank_holiday.id,
'date_from': date(2020, 1, 10),
'request_date_from': date(2020, 1, 10),
'date_to': date(2020, 1, 10),
'request_date_to': date(2020, 1, 10),
'number_of_days': 1,
})
company_leave._compute_date_from_to()
company_leave.action_validate()
all_leaves = self.env['hr.leave'].search([('employee_id', '=', self.employee.id)], order='id')
self.assertEqual(len(all_leaves), 3)
# Original Leave
self.assertEqual(leave.state, 'refuse')
# before leave
self.assertEqual(all_leaves[1].date_from, datetime(2020, 1, 6, 7, 0))
self.assertEqual(all_leaves[1].date_to, datetime(2020, 1, 9, 16, 0))
self.assertEqual(all_leaves[1].number_of_days, 2)
self.assertEqual(all_leaves[1].state, 'confirm')
# Company Leave
self.assertEqual(all_leaves[2].date_from, datetime(2020, 1, 10, 7, 0))
self.assertEqual(all_leaves[2].date_to, datetime(2020, 1, 10, 16, 0))
self.assertEqual(all_leaves[2].number_of_days, 1)
self.assertEqual(all_leaves[2].state, 'validate')
@warmup
def test_leave_whole_company_07(self):
# Test Case 7: Try to create a bank holidays for a lot of
# employees, and check the performances
# 100 employees - 15 already on holidays that day
employees = self.env['hr.employee'].create([{
'name': 'Employee %s' % i,
'company_id': self.company.id
} for i in range(100)])
leaves = self.env['hr.leave'].create([{
'name': 'Holiday - %s' % employee.name,
'employee_id': employee.id,
'holiday_status_id': self.paid_time_off.id,
'request_date_from': date(2020, 3, 29),
'date_from': datetime(2020, 3, 29, 7, 0, 0),
'request_date_to': date(2020, 4, 1),
'date_to': datetime(2020, 4, 1, 19, 0, 0),
'number_of_days': 3,
} for employee in employees[0:15]])
leaves._compute_date_from_to()
company_leave = self.env['hr.leave'].create({
'name': 'Bank Holiday',
'holiday_type': 'company',
'mode_company_id': self.company.id,
'holiday_status_id': self.bank_holiday.id,
'date_from': date(2020, 4, 1),
'request_date_from': date(2020, 4, 1),
'date_to': date(2020, 4, 1),
'request_date_to': date(2020, 4, 1),
'number_of_days': 1,
})
company_leave._compute_date_from_to()
with self.assertQueryCount(__system__=830): # 770 community
# Original query count: 1987
# Without tracking/activity context keys: 5154
company_leave.action_validate()
leaves = self.env['hr.leave'].search([('holiday_status_id', '=', self.bank_holiday.id)])
self.assertEqual(len(leaves), 102)
def test_leave_whole_company_08(self):
"""
Give a company leave with employees on different schedules.
"""
# employee on different schedule
calendar = self.env['resource.calendar'].create({
'name': 'Different schedule',
'attendance_ids': [(5, 0, 0),
(0, 0, {
'name': 'monday morning, earlier start',
'hour_from': 7.5,
'hour_to': 9.75,
'day_period': 'morning',
'dayofweek': '0',
}),
(0, 0, {
'name': 'monday morning, second attendance',
'hour_from': 10,
'hour_to': 12,
'day_period': 'morning',
'dayofweek': '0',
}),
(0, 0, {
'name': 'monday afternoon',
'hour_from': 13,
'hour_to': 17,
'day_period': 'afternoon',
'dayofweek': '0',
}),
]
})
self.employee.resource_calendar_id = calendar
# employee on default schedule
employee2 = self.env['hr.employee'].create({
'name': 'Employee2',
'company_id': self.company.id,
'tz': "Europe/Brussels",
})
company_leave = self.env['hr.leave'].create({
'name': 'Bank Holiday',
'holiday_type': 'company',
'mode_company_id': self.company.id,
'holiday_status_id': self.bank_holiday.id,
'date_from': date(2020, 1, 6),
'request_date_from': date(2020, 1, 6),
'date_to': date(2020, 1, 6),
'request_date_to': date(2020, 1, 6),
'number_of_days': 1,
})
company_leave._compute_date_from_to()
company_leave.action_validate()
half_day_company_leave = self.env['hr.leave'].create({
'name': 'Bank Holiday',
'holiday_type': 'company',
'mode_company_id': self.company.id,
'holiday_status_id': self.bank_holiday.id,
'date_from': date(2020, 1, 13),
'request_date_from': date(2020, 1, 13),
'date_to': date(2020, 1, 13),
'request_date_to': date(2020, 1, 13),
'number_of_days': 0.5,
'request_unit_half': True,
'request_date_from_period': 'am',
})
half_day_company_leave._compute_date_from_to()
half_day_company_leave.action_validate()
employee_leaves = self.env['hr.leave'].search([('employee_id', '=', self.employee.id)], order='id')
self.assertEqual(employee_leaves[0].date_from, datetime(2020, 1, 6, 6, 30))
self.assertEqual(employee_leaves[0].date_to, datetime(2020, 1, 6, 16, 0))
self.assertEqual(employee_leaves[0].number_of_days, 1)
self.assertEqual(employee_leaves[0].number_of_hours_display, 8.25)
self.assertEqual(employee_leaves[1].date_from, datetime(2020, 1, 13, 6, 30))
self.assertEqual(employee_leaves[1].date_to, datetime(2020, 1, 13, 11, 0))
self.assertEqual(employee_leaves[1].number_of_days, 0.5)
self.assertEqual(employee_leaves[1].number_of_hours_display, 4.25)
employee2_leaves = self.env['hr.leave'].search([('employee_id', '=', employee2.id)], order='id')
self.assertEqual(employee2_leaves[0].date_from, datetime(2020, 1, 6, 7, 0))
self.assertEqual(employee2_leaves[0].number_of_days, 1)
self.assertEqual(employee2_leaves[1].date_from, datetime(2020, 1, 13, 7, 0))
self.assertEqual(employee2_leaves[1].date_to, datetime(2020, 1, 13, 11, 0))
self.assertEqual(employee2_leaves[1].number_of_days, 0.5)
def test_leave_whole_company_09(self):
"""
Check leaves given in half days and in hours for a company.
"""
half_day_leave = self.env['hr.leave'].create({
'name': 'Bank Holiday (full day)',
'holiday_type': 'company',
'mode_company_id': self.company.id,
'holiday_status_id': self.bank_holiday.id,
'date_from': date(2020, 1, 6),
'request_date_from': date(2020, 1, 6),
'date_to': date(2020, 1, 6),
'request_date_to': date(2020, 1, 6),
'number_of_days': 0.5,
'request_unit_half': True,
'request_date_from_period': 'am',
})
hours_leave = self.env['hr.leave'].create({
'name': 'Bank Holiday (half day)',
'holiday_type': 'company',
'mode_company_id': self.company.id,
'holiday_status_id': self.bank_holiday.id,
'date_from': date(2020, 1, 7),
'request_date_from': date(2020, 1, 7),
'date_to': date(2020, 1, 7),
'request_date_to': date(2020, 1, 7),
'request_unit_hours': True,
'request_hour_from': '5.5',
'request_hour_to': '9',
})
half_day_leave._compute_date_from_to()
half_day_leave.action_validate()
hours_leave._compute_date_from_to()
hours_leave.action_validate()
employee_leaves = self.env['hr.leave'].search([('employee_id', '=', self.employee.id)], order='id')
# half days leave
self.assertEqual(employee_leaves[0].date_from, datetime(2020, 1, 6, 7, 0))
self.assertEqual(employee_leaves[0].date_to, datetime(2020, 1, 6, 11, 0))
self.assertEqual(employee_leaves[0].number_of_days, 0.5)
# leave given in hours
self.assertEqual(employee_leaves[1].date_from, datetime(2020, 1, 7, 3, 30))
self.assertEqual(employee_leaves[1].date_to, datetime(2020, 1, 7, 7, 0))
self.assertEqual(employee_leaves[1].number_of_hours_display, 1.0)
def test_leave_whole_company_10(self):
"""
Check leaves given in hours for a company,
Making sure no leaves are given for 0 Hours / Week employee(i.e. Contractors billed for hours).
"""
employee_0_test_10, employee_1_test_10, employee_2_test_10 = self.env['hr.employee'].create([{
'name': 'My Employee 0',
'company_id': self.company.id,
'tz': "Europe/Brussels",
},{
'name': 'My Employee 1',
'company_id': self.company.id,
'tz': "Europe/Brussels",
},{
'name': 'My Employee 2',
'company_id': self.company.id,
'tz': "Europe/Brussels",
}])
zero_hours_working_schedule = self.env['resource.calendar'].create({
'name': 'Standard - Hours/Week',
'hours_per_day': 0,
'tz': "Europe/Brussels",
})
employee_0_test_10.resource_calendar_id = zero_hours_working_schedule
self.env['hr.leave.allocation'].create({
'name': 'Holiday (8 Hours)',
'holiday_status_id': self.paid_time_off_hours.id,
'holiday_type': 'company',
'mode_company_id': self.company.id,
'number_of_days': 1,
})
employee_leaves = self.env['hr.leave.allocation'].search([
('name', '=', 'Holiday (8 Hours)'),
('employee_id', 'in', [employee_0_test_10.id, employee_1_test_10.id, employee_2_test_10.id])])
self.assertEqual(len(employee_leaves), 2)

View file

@ -0,0 +1,92 @@
from datetime import date, datetime
from freezegun import freeze_time
from odoo.addons.hr_holidays.tests.common import TestHrHolidaysCommon
class TestDashboard(TestHrHolidaysCommon):
def test_dashboard_special_days(self):
self.env.user = self.user_hrmanager
employee = self.env.user.employee_id
other_calendar = employee.company_id.resource_calendar_ids[1]
stress_day_vals = [
{
'name': 'Super Event (employee schedule)',
'company_id': employee.company_id.id,
'start_date': datetime(2021, 6, 12),
'end_date': datetime(2021, 6, 12),
'resource_calendar_id': employee.resource_calendar_id.id,
},
{
'name': 'Super Event (no schedule)',
'company_id': employee.company_id.id,
'start_date': datetime(2021, 6, 12),
'end_date': datetime(2021, 6, 12),
},
{
'name': 'Super Event (other schedule)',
'company_id': employee.company_id.id,
'start_date': datetime(2021, 6, 12),
'end_date': datetime(2021, 6, 12),
'resource_calendar_id': other_calendar.id,
}
]
self.env['hr.leave.stress.day'].create(stress_day_vals)
public_holiday_vals = [
{
'name': 'Public holiday (employee schedule)',
'date_from': "2021-06-15 06:00:00",
'date_to': "2021-06-15 15:00:00",
'calendar_id': employee.resource_calendar_id.id,
},
{
'name': 'Public holiday (no schedule)',
'date_from': "2021-06-16 06:00:00",
'date_to': "2021-06-16 15:00:00",
},
{
'name': 'Public holiday (other schedule)',
'date_from': "2021-06-17 06:00:00",
'date_to': "2021-06-17 15:00:00",
'calendar_id': other_calendar.id,
},
]
self.env['resource.calendar.leaves'].create(public_holiday_vals)
dashboard_data = self.env['hr.employee'].get_special_days_data("2021/06/01", "2021/07/01")
self.assertEqual({d["title"] for d in dashboard_data["stressDays"]}, {'Super Event (employee schedule)', 'Super Event (no schedule)'})
self.assertEqual({d["title"] for d in dashboard_data["bankHolidays"]}, {'Public holiday (employee schedule)', 'Public holiday (no schedule)'})
def test_dashboard_max_near_accrual_validity_end(self):
emp_id = self.employee_emp_id
leave_type = self.env['hr.leave.type'].create({
'name': 'Test Time Off',
'requires_allocation': 'yes',
'employee_requests': 'no',
'allocation_validation_type': 'no',
'leave_validation_type': 'both',
'responsible_id': self.user_hrmanager_id,
})
self.env['hr.leave.allocation'].create([{
'employee_id': emp_id,
'name': '10 days allocation',
'holiday_status_id': leave_type.id,
'number_of_days': 10,
'date_from': date(2024, 1, 1),
'date_to': date(2024, 12, 30),
}, {
'employee_id': emp_id,
'name': '2 days allocation starting later',
'holiday_status_id': leave_type.id,
'number_of_days': 2,
'date_from': date(2024, 2, 1),
'date_to': date(2024, 12, 30),
}])
with freeze_time('2024-12-27'):
employee_max_leaves = leave_type.get_employees_days([emp_id])[emp_id][leave_type.id]['max_leaves']
self.assertEqual(employee_max_leaves, 12, "All 12 leaves should be seen from the dashboard")

View file

@ -0,0 +1,232 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import date, datetime
from odoo.addons.hr_holidays.tests.common import TestHrHolidaysCommon
from odoo.exceptions import ValidationError
from freezegun import freeze_time
from odoo.tests import tagged
@tagged('global_leaves')
class TestGlobalLeaves(TestHrHolidaysCommon):
""" Test global leaves for a whole company, conflict resolutions """
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.calendar_1 = cls.env['resource.calendar'].create({
'name': 'Classic 40h/week',
'tz': 'UTC',
'hours_per_day': 8.0,
'attendance_ids': [
(0, 0, {'name': 'Monday Morning', 'dayofweek': '0', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Monday Afternoon', 'dayofweek': '0', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'}),
(0, 0, {'name': 'Tuesday Morning', 'dayofweek': '1', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Tuesday Afternoon', 'dayofweek': '1', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'}),
(0, 0, {'name': 'Wednesday Morning', 'dayofweek': '2', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Wednesday Afternoon', 'dayofweek': '2', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'}),
(0, 0, {'name': 'Thursday Morning', 'dayofweek': '3', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Thursday Afternoon', 'dayofweek': '3', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'}),
(0, 0, {'name': 'Friday Morning', 'dayofweek': '4', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Friday Afternoon', 'dayofweek': '4', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'})
]
})
cls.calendar_2 = cls.env['resource.calendar'].create({
'name': 'Classic 20h/week',
'tz': 'UTC',
'hours_per_day': 4.0,
'attendance_ids': [
(0, 0, {'name': 'Monday Morning', 'dayofweek': '0', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Tuesday Morning', 'dayofweek': '1', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Wednesday Morning', 'dayofweek': '2', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Thursday Morning', 'dayofweek': '3', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Friday Morning', 'dayofweek': '4', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
]
})
cls.global_leave = cls.env['resource.calendar.leaves'].create({
'name': 'Global Leave',
'date_from': date(2022, 3, 7),
'date_to': date(2022, 3, 7),
})
cls.calendar_leave = cls.env['resource.calendar.leaves'].create({
'name': 'Global Leave',
'date_from': date(2022, 3, 8),
'date_to': date(2022, 3, 8),
'calendar_id': cls.calendar_1.id,
})
def test_leave_on_global_leave(self):
with self.assertRaises(ValidationError):
self.env['resource.calendar.leaves'].create({
'name': 'Wrong Leave',
'date_from': date(2022, 3, 7),
'date_to': date(2022, 3, 7),
'calendar_id': self.calendar_1.id,
})
with self.assertRaises(ValidationError):
self.env['resource.calendar.leaves'].create({
'name': 'Wrong Leave',
'date_from': date(2022, 3, 7),
'date_to': date(2022, 3, 7),
})
def test_leave_on_deleted_global_leave(self):
public_leave = self.env['resource.calendar.leaves'].create({
'name': 'Public Time Off',
'date_from': datetime(2024, 2, 20, 0, 0),
'date_to': datetime(2024, 2, 22, 23, 59),
'company_id': self.employee_emp.company_id.id,
})
leave_type = self.env['hr.leave.type'].create({
'name': 'Paid Time Off',
'requires_allocation': 'yes',
'employee_requests': 'no',
'allocation_validation_type': 'no',
'leave_validation_type': 'both',
'responsible_id': self.user_hrmanager_id,
})
allocation = self.env['hr.leave.allocation'].create({
'employee_id': self.employee_emp_id,
'name': '2 days allocation',
'holiday_status_id': leave_type.id,
'number_of_days': 2,
'state': 'confirm',
'date_from': date(2024, 2, 1),
'date_to': date(2024, 2, 29),
})
allocation.action_validate()
covered_leave_1 = self.env['hr.leave'].create({
'name': 'Covered Leave',
'employee_id': self.employee_emp_id,
'holiday_status_id': leave_type.id,
'date_from': datetime(2024, 2, 19, 7, 0),
'date_to': datetime(2024, 2, 20, 18, 0),
})
self.assertEqual(covered_leave_1.number_of_days, 1, 'The leave should have a duration of 1 day.')
covered_leave_2 = self.env['hr.leave'].create({
'name': 'Covered Leave',
'employee_id': self.employee_emp_id,
'holiday_status_id': leave_type.id,
'date_from': datetime(2024, 2, 21, 7, 0),
'date_to': datetime(2024, 2, 21, 18, 0),
})
self.assertEqual(covered_leave_2.number_of_days, 0, 'The leave should have a duration of 0 days.')
covered_leave_3 = self.env['hr.leave'].create({
'name': 'Covered Leave',
'employee_id': self.employee_emp_id,
'holiday_status_id': leave_type.id,
'date_from': datetime(2024, 2, 22, 7, 0),
'date_to': datetime(2024, 2, 23, 18, 0),
})
self.assertEqual(covered_leave_3.number_of_days, 1, 'The leave should have a duration of 1 day.')
public_leave.unlink()
self.assertEqual(covered_leave_1.active, True, 'The partially covered leave should still be active.')
self.assertEqual(covered_leave_1.number_of_days, 1, 'The leave should have a duration of 1 day.')
self.assertEqual(covered_leave_2.active, False, 'The covered leave should be archived.')
self.assertEqual(covered_leave_3.active, True, 'The partially covered leave should still be active.')
self.assertEqual(covered_leave_3.number_of_days, 1, 'The leave should have a duration of 1 day.')
def test_leave_on_calendar_leave(self):
self.env['resource.calendar.leaves'].create({
'name': 'Correct Leave',
'date_from': date(2022, 3, 8),
'date_to': date(2022, 3, 8),
'calendar_id': self.calendar_2.id,
})
with self.assertRaises(ValidationError):
self.env['resource.calendar.leaves'].create({
'name': 'Wrong Leave',
'date_from': date(2022, 3, 8),
'date_to': date(2022, 3, 8),
})
with self.assertRaises(ValidationError):
self.env['resource.calendar.leaves'].create({
'name': 'Wrong Leave',
'date_from': date(2022, 3, 8),
'date_to': date(2022, 3, 8),
'calendar_id': self.calendar_1.id,
})
@freeze_time('2023-05-12')
def test_global_leave_timezone(self):
"""
It is necessary to use the timezone of the calendar
for the global leaves (without resource).
"""
calendar_asia = self.env['resource.calendar'].create({
'name': 'Asia calendar',
'tz': 'Asia/Kolkata', # UTC +05:30
'hours_per_day': 8.0,
'attendance_ids': []
})
self.env.user.tz = 'Europe/Brussels'
global_leave = self.env['resource.calendar.leaves'].with_user(self.env.user).create({
'name': 'Public holiday',
'date_from': "2023-05-15 06:00:00", # utc from 8:00:00 for Europe/Brussels (UTC +02:00)
'date_to': "2023-05-15 15:00:00", # utc from 17:00:00 for Europe/Brussels (UTC +02:00)
'calendar_id': calendar_asia.id,
})
# Expectation:
# 6:00:00 in UTC (data from the browser) --> 8:00:00 for Europe/Brussel (UTC +02:00)
# 8:00:00 for Asia/Kolkata (UTC +05:30) --> 2:30:00 in UTC
self.assertEqual(global_leave.date_from, datetime(2023, 5, 15, 2, 30))
self.assertEqual(global_leave.date_to, datetime(2023, 5, 15, 11, 30))
# Note:
# The user in Europe/Brussels timezone see 4:30 and not 2:30 because he is in UTC +02:00.
# The user in Asia/Kolkata timezone (determined via the browser) see 8:00 because he is in UTC +05:30
@freeze_time('2024-12-01')
def test_global_leave_keeps_employee_resource_leave(self):
"""
When a global leave is created, and it happens during a leave period of an employee,
if the employee's leave is not fully covered by the global leave, the employee's leave
should still have resource leaves linked to it.
"""
leave_type = self.env['hr.leave.type'].create({
'name': 'Paid Time Off',
'requires_allocation': 'yes',
'employee_requests': 'no',
'allocation_validation_type': 'no',
'leave_validation_type': 'both',
'responsible_id': self.user_hrmanager_id,
})
allocation = self.env['hr.leave.allocation'].create({
'employee_id': self.employee_emp_id,
'name': '5 days allocation',
'holiday_status_id': leave_type.id,
'number_of_days': 5,
'state': 'confirm',
'date_from': date(2024, 12, 1),
'date_to': date(2024, 12, 30),
})
allocation.action_validate()
partially_covered_leave = self.env['hr.leave'].create({
'name': 'Covered Leave',
'employee_id': self.employee_emp_id,
'holiday_status_id': leave_type.id,
'date_from': datetime(2024, 12, 3, 7, 0),
'date_to': datetime(2024, 12, 5, 18, 0),
})
partially_covered_leave.action_validate()
global_leave = self.env['resource.calendar.leaves'].with_user(self.env.user).create({
'name': 'Public holiday',
'date_from': "2024-12-4 06:00:00",
'date_to': "2024-12-4 23:00:00",
'calendar_id': self.calendar_1.id,
})
# retrieve resource leaves linked to the employee's leave
resource_leaves = self.env['resource.calendar.leaves'].search([
('holiday_id', '=', partially_covered_leave.id)
])
self.assertTrue(resource_leaves, 'Resource leaves linked to the employee leave should exist.')

View file

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.base.tests.common import HttpCase
from odoo.tests.common import tagged
from odoo.tests.common import users
from odoo.addons.hr_holidays.tests.common import TestHrHolidaysCommon
@tagged('post_install', '-at_install')
class TestHolidaysCalendar(HttpCase, TestHrHolidaysCommon):
@users('admin')
def test_hours_time_off_request_calendar_view(self):
"""
Testing the flow of clicking on a day, save the leave request directly
and verify that the start/end time are correctly set
"""
self.env.user.tz = 'UTC'
calendar = self.env.user.employee_id.resource_calendar_id.attendance_ids
expected_start_thursday = calendar[6].hour_from
expected_end_thursday = calendar[7].hour_to
self.start_tour('/', 'time_off_request_calendar_view', login='admin')
last_leave = self.env['hr.leave'].search([('employee_id.id', '=', self.env.user.employee_id.id)]).sorted(lambda leave: leave.create_date)[-1]
self.assertEqual(last_leave.date_from.weekday(), 3, "It should be Thursday")
self.assertEqual(last_leave.date_from.hour, expected_start_thursday, "Wrong start of the day")
self.assertEqual(last_leave.date_to.hour, expected_end_thursday, "Wrong end of the day")

View file

@ -0,0 +1,288 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import time
from datetime import datetime
from dateutil.relativedelta import relativedelta
from freezegun import freeze_time
from psycopg2 import IntegrityError
from odoo import fields
from odoo.exceptions import AccessError, ValidationError, UserError
from odoo.tools import mute_logger, test_reports
from odoo.addons.hr_holidays.tests.common import TestHrHolidaysCommon
class TestHolidaysFlow(TestHrHolidaysCommon):
@mute_logger('odoo.addons.base.models.ir_model', 'odoo.models')
def test_00_leave_request_flow_unlimited(self):
""" Testing leave request flow: unlimited type of leave request """
Requests = self.env['hr.leave']
HolidaysStatus = self.env['hr.leave.type']
# HrManager creates some holiday statuses
HolidayStatusManagerGroup = HolidaysStatus.with_user(self.user_hrmanager_id)
HolidayStatusManagerGroup.create({
'name': 'WithMeetingType',
'requires_allocation': 'no',
})
self.holidays_status_hr = HolidayStatusManagerGroup.create({
'name': 'NotLimitedHR',
'requires_allocation': 'no',
'leave_validation_type': 'hr',
})
self.holidays_status_manager = HolidayStatusManagerGroup.create({
'name': 'NotLimitedManager',
'requires_allocation': 'no',
'leave_validation_type': 'manager',
})
HolidaysEmployeeGroup = Requests.with_user(self.user_employee_id)
# Employee creates a leave request in a no-limit category hr manager only
hol1_employee_group = HolidaysEmployeeGroup.create({
'name': 'Hol11',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_status_hr.id,
'date_from': (datetime.today() - relativedelta(days=1)),
'date_to': datetime.today(),
'number_of_days': 1,
})
hol1_user_group = hol1_employee_group.with_user(self.user_hruser_id)
hol1_manager_group = hol1_employee_group.with_user(self.user_hrmanager_id)
self.assertEqual(hol1_user_group.state, 'confirm', 'hr_holidays: newly created leave request should be in confirm state')
# HrUser validates the employee leave request -> should work
hol1_user_group.action_approve()
self.assertEqual(hol1_manager_group.state, 'validate', 'hr_holidays: validated leave request should be in validate state')
# Employee creates a leave request in a no-limit category department manager only
hol12_employee_group = HolidaysEmployeeGroup.create({
'name': 'Hol12',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_status_manager.id,
'date_from': (datetime.today() + relativedelta(days=12)),
'date_to': (datetime.today() + relativedelta(days=13)),
'number_of_days': 1,
})
hol12_user_group = hol12_employee_group.with_user(self.user_hruser_id)
hol12_manager_group = hol12_employee_group.with_user(self.user_hrmanager_id)
self.assertEqual(hol12_user_group.state, 'confirm', 'hr_holidays: newly created leave request should be in confirm state')
# HrManager validate the employee leave request
hol12_manager_group.action_approve()
self.assertEqual(hol1_user_group.state, 'validate', 'hr_holidays: validates leave request should be in validate state')
@mute_logger('odoo.addons.base.models.ir_model', 'odoo.models')
def test_01_leave_request_flow_limited(self):
""" Testing leave request flow: limited type of leave request """
with freeze_time('2022-01-15'):
Requests = self.env['hr.leave']
Allocations = self.env['hr.leave.allocation']
HolidaysStatus = self.env['hr.leave.type']
holiday_status_paid_time_off = self.env['hr.leave.type'].create({
'name': 'Paid Time Off',
'requires_allocation': 'yes',
'employee_requests': 'no',
'allocation_validation_type': 'officer',
'leave_validation_type': 'both',
'responsible_id': self.env.ref('base.user_admin').id,
})
self.env['hr.leave.allocation'].create([
{
'name': 'Paid Time off for David',
'holiday_status_id': holiday_status_paid_time_off.id,
'number_of_days': 20,
'employee_id': self.employee_emp_id,
'state': 'confirm',
'date_from': time.strftime('%Y-%m-01'),
}, {
'name': 'Paid Time off for David',
'holiday_status_id': holiday_status_paid_time_off.id,
'number_of_days': 20,
'employee_id': self.ref('hr.employee_admin'),
'state': 'confirm',
'date_from': time.strftime('%Y-%m-01'),
}
]).action_validate()
def _check_holidays_status(holiday_status, ml, lt, rl, vrl):
self.assertEqual(holiday_status.max_leaves, ml,
'hr_holidays: wrong type days computation')
self.assertEqual(holiday_status.leaves_taken, lt,
'hr_holidays: wrong type days computation')
self.assertEqual(holiday_status.remaining_leaves, rl,
'hr_holidays: wrong type days computation')
self.assertEqual(holiday_status.virtual_remaining_leaves, vrl,
'hr_holidays: wrong type days computation')
# HrManager creates some holiday statuses
HolidayStatusManagerGroup = HolidaysStatus.with_user(self.user_hrmanager_id)
HolidayStatusManagerGroup.create({
'name': 'WithMeetingType',
'requires_allocation': 'no',
})
self.holidays_status_limited = HolidayStatusManagerGroup.create({
'name': 'Limited',
'requires_allocation': 'yes',
'employee_requests': 'no',
'allocation_validation_type': 'officer',
'leave_validation_type': 'both',
})
HolidaysEmployeeGroup = Requests.with_user(self.user_employee_id)
# HrUser allocates some leaves to the employee
aloc1_user_group = Allocations.with_user(self.user_hruser_id).create({
'name': 'Days for limited category',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_status_limited.id,
'number_of_days': 2,
'state': 'confirm',
'date_from': time.strftime('%Y-%m-01'),
})
# HrUser validates the first step
# HrManager validates the second step
aloc1_user_group.with_user(self.user_hrmanager_id).action_validate()
# Checks Employee has effectively some days left
hol_status_2_employee_group = self.holidays_status_limited.with_user(self.user_employee_id)
_check_holidays_status(hol_status_2_employee_group, 2.0, 0.0, 2.0, 2.0)
# Employee creates a leave request in the limited category, now that he has some days left
hol2 = HolidaysEmployeeGroup.create({
'name': 'Hol22',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_status_limited.id,
'date_from': (datetime.today() + relativedelta(days=2)).strftime('%Y-%m-%d %H:%M'),
'date_to': (datetime.today() + relativedelta(days=3)),
'number_of_days': 1,
})
hol2_user_group = hol2.with_user(self.user_hruser_id)
# Check left days: - 1 virtual remaining day
hol_status_2_employee_group.invalidate_model()
_check_holidays_status(hol_status_2_employee_group, 2.0, 0.0, 2.0, 1.0)
# HrManager validates the second step
hol2_user_group.with_user(self.user_hrmanager_id).action_validate()
self.assertEqual(hol2.state, 'validate',
'hr_holidays: second validation should lead to validate state')
# Check left days: - 1 day taken
_check_holidays_status(hol_status_2_employee_group, 2.0, 1.0, 1.0, 1.0)
# HrManager finds an error: he refuses the leave request
hol2.with_user(self.user_hrmanager_id).action_refuse()
self.assertEqual(hol2.state, 'refuse',
'hr_holidays: refuse should lead to refuse state')
# Check left days: 2 days left again
hol_status_2_employee_group.invalidate_model(['max_leaves'])
_check_holidays_status(hol_status_2_employee_group, 2.0, 0.0, 2.0, 2.0)
self.assertEqual(hol2.state, 'refuse',
'hr_holidays: hr_user should not be able to reset a refused leave request')
# HrManager resets the request
hol2_manager_group = hol2.with_user(self.user_hrmanager_id)
hol2_manager_group.action_draft()
self.assertEqual(hol2.state, 'draft',
'hr_holidays: resetting should lead to draft state')
employee_id = self.ref('hr.employee_admin')
# cl can be of maximum 20 days for employee_admin
hol3_status = holiday_status_paid_time_off.with_context(employee_id=employee_id)
# I assign the dates in the holiday request for 1 day
hol3 = Requests.create({
'name': 'Sick Time Off',
'holiday_status_id': hol3_status.id,
'date_from': datetime.today().strftime('%Y-%m-10 10:00:00'),
'date_to': datetime.today().strftime('%Y-%m-11 19:00:00'),
'employee_id': employee_id,
'number_of_days': 1,
})
# I find a small mistake on my leave request to I click on "Refuse" button to correct a mistake.
hol3.action_refuse()
self.assertEqual(hol3.state, 'refuse', 'hr_holidays: refuse should lead to refuse state')
# I again set to draft and then confirm.
hol3.action_draft()
self.assertEqual(hol3.state, 'draft', 'hr_holidays: resetting should lead to draft state')
hol3.action_confirm()
self.assertEqual(hol3.state, 'confirm', 'hr_holidays: confirming should lead to confirm state')
# I validate the holiday request by clicking on "To Approve" button.
hol3.action_validate()
self.assertEqual(hol3.state, 'validate', 'hr_holidays: validation should lead to validate state')
# Check left days for casual leave: 19 days left
_check_holidays_status(hol3_status, 20.0, 1.0, 19.0, 19.0)
def test_10_leave_summary_reports(self):
# Print the HR Holidays(Summary Employee) Report through the wizard
ctx = {
'model': 'hr.employee',
'active_ids': [self.ref('hr.employee_admin')]
}
data_dict = {
'date_from': datetime.today().strftime('%Y-%m-01'),
'emp': [(6, 0, [self.ref('hr.employee_admin')])],
'holiday_type': 'Approved'
}
self.env.company.external_report_layout_id = self.env.ref('web.external_layout_standard').id
test_reports.try_report_action(self.env.cr, self.env.uid, 'action_hr_holidays_summary_employee', wiz_data=data_dict, context=ctx, our_module='hr_holidays')
def test_sql_constraint_dates(self):
# The goal is mainly to verify that a human friendly
# error message is triggered if the date_from is after
# date_to. Coming from a bug due to the new ORM 13.0
holiday_status_paid_time_off = self.env['hr.leave.type'].create({
'name': 'Paid Time Off',
'requires_allocation': 'yes',
'employee_requests': 'no',
'allocation_validation_type': 'officer',
'leave_validation_type': 'both',
'responsible_id': self.env.ref('base.user_admin').id,
})
self.env['hr.leave.allocation'].create({
'name': 'Paid Time off for David',
'holiday_status_id': holiday_status_paid_time_off.id,
'number_of_days': 20,
'employee_id': self.ref('hr.employee_admin'),
'state': 'confirm',
'date_from': time.strftime('%Y-%m-01'),
'date_to': time.strftime('%Y-12-31'),
}).action_validate()
leave_vals = {
'name': 'Sick Time Off',
'holiday_status_id': holiday_status_paid_time_off.id,
'date_from': datetime.today().strftime('%Y-%m-11 19:00:00'),
'date_to': datetime.today().strftime('%Y-%m-10 10:00:00'),
'employee_id': self.ref('hr.employee_admin'),
'number_of_days': 1,
}
with mute_logger('odoo.sql_db'):
with self.assertRaises(IntegrityError):
with self.cr.savepoint():
self.env['hr.leave'].create(leave_vals)
leave_vals = {
'name': 'Sick Time Off',
'holiday_status_id': holiday_status_paid_time_off.id,
'date_from': datetime.today().strftime('%Y-%m-10 10:00:00'),
'date_to': datetime.today().strftime('%Y-%m-11 19:00:00'),
'employee_id': self.ref('hr.employee_admin'),
'number_of_days': 1,
}
leave = self.env['hr.leave'].create(leave_vals)
with mute_logger('odoo.sql_db'):
with self.assertRaises(IntegrityError): # No ValidationError
with self.cr.savepoint():
leave.write({
'date_from': datetime.today().strftime('%Y-%m-11 19:00:00'),
'date_to': datetime.today().strftime('%Y-%m-10 10:00:00'),
})

View file

@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import datetime
from dateutil.relativedelta import relativedelta
from freezegun import freeze_time
from odoo.exceptions import UserError, ValidationError
from .common import TestHrHolidaysCommon
class TestHrHolidaysCancelLeave(TestHrHolidaysCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
leave_start_datetime = datetime(2018, 2, 5, 7, 0, 0, 0) # this is monday
leave_end_datetime = leave_start_datetime + relativedelta(days=3)
cls.hr_leave_type = cls.env['hr.leave.type'].with_user(cls.user_hrmanager).create({
'name': 'Leave Type',
'requires_allocation': 'no',
})
cls.holiday = cls.env['hr.leave'].with_context(mail_create_nolog=True, mail_notrack=True).with_user(cls.user_employee).create({
'name': 'Leave 1',
'employee_id': cls.employee_emp.id,
'holiday_status_id': cls.hr_leave_type.id,
'date_from': leave_start_datetime,
'date_to': leave_end_datetime,
'number_of_days': (leave_end_datetime - leave_start_datetime).days,
})
cls.holiday.with_user(cls.user_hrmanager).action_validate()
@freeze_time('2018-02-05') # useful to be able to cancel the validated time off
def test_action_cancel_leave(self):
self.assertTrue(self.holiday.with_user(self.user_employee).can_cancel)
self.env['hr.holidays.cancel.leave'].with_user(self.user_employee).with_context(default_leave_id=self.holiday.id) \
.new({'reason': 'Test remove holiday'}) \
.action_cancel_leave()
self.assertFalse(self.holiday.active, 'The validated leave should be canceled, that is archived.')
def test_action_cancel_leave_in_past(self):
""" Test if the user may cancel a validated leave in the past. """
with self.assertRaises(ValidationError, msg='The leave could not be cancel since it is leave in the past.'):
self.env['hr.holidays.cancel.leave'].with_user(self.user_employee).with_context(default_leave_id=self.holiday.id) \
.new({'reason': 'Test remove holiday'}) \
.action_cancel_leave()
def test_action_cancel_leave_from_another_person(self):
""" Test if the user may cancel a validated leave from another person. """
self.assertFalse(self.holiday.with_user(self.user_hruser).can_cancel, 'The user should not be able to cancel the leave from another one.')
with self.assertRaises(ValidationError, msg='The leave could not be cancel since it is leave in the past.'):
self.env['hr.holidays.cancel.leave'].with_user(self.user_hruser).with_context(default_leave_id=self.holiday.id) \
.new({'reason': 'Test remove holiday'}) \
.action_cancel_leave()
@freeze_time('2018-02-05') # useful to be able to cancel the validated time off
def test_user_cannot_unarchive_leave(self):
""" Test the user cannot manually unarchive a canceled leave """
self.env['hr.holidays.cancel.leave'].with_user(self.user_employee).with_context(default_leave_id=self.holiday.id) \
.new({'reason': 'Test remove holiday'}) \
.action_cancel_leave()
with self.assertRaises(UserError, msg='The user should not be able to manually unarchive the leave.'):
self.holiday.with_user(self.user_employee).write({'active': False})

View file

@ -0,0 +1,43 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.tests import HttpCase
from odoo.tests.common import tagged
from datetime import date
@tagged('post_install', '-at_install')
class TestHrHolidaysTour(HttpCase):
def test_hr_holidays_tour(self):
admin_user = self.env.ref('base.user_admin')
admin_employee = admin_user.employee_id
HRLeave = self.env['hr.leave']
date_from = date(2022, 1, 17)
date_to = date(2022, 1, 18)
leaves_on_freeze_date = HRLeave.search([
('date_from', '>=', date_from),
('date_to', "<=", date_to),
('employee_id', '=', admin_employee.id)
])
leaves_on_freeze_date.sudo().unlink()
LeaveType = self.env['hr.leave.type'].with_user(admin_user)
holidays_type_1 = LeaveType.create({
'name': 'NotLimitedHR',
'requires_allocation': 'no',
'leave_validation_type': 'hr',
})
# add allocation
allocation = self.env['hr.leave.allocation'].create({
'name': 'Expired Allocation',
'employee_id': admin_employee.id,
'holiday_status_id': holidays_type_1.id,
'number_of_days': 1,
'state': 'confirm',
'date_from': '2022-01-01',
'date_to': '2022-12-31',
})
allocation.action_validate()
self.start_tour('/web', 'hr_holidays_tour', login="admin")

View file

@ -0,0 +1,73 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import datetime
from dateutil.relativedelta import relativedelta
from odoo.exceptions import AccessError
from odoo.addons.hr_holidays.tests.common import TestHrHolidaysCommon
class TestHrLeaveType(TestHrHolidaysCommon):
def test_time_type(self):
leave_type = self.env['hr.leave.type'].create({
'name': 'Paid Time Off',
'time_type': 'leave',
'requires_allocation': 'no',
})
leave_1 = self.env['hr.leave'].create({
'name': 'Doctor Appointment',
'employee_id': self.employee_hruser_id,
'holiday_status_id': leave_type.id,
'date_from': (datetime.today() - relativedelta(days=1)),
'date_to': datetime.today(),
'number_of_days': 1,
})
leave_1.action_approve()
self.assertEqual(
self.env['resource.calendar.leaves'].search([('holiday_id', '=', leave_1.id)]).time_type,
'leave'
)
def test_type_creation_right(self):
# HrUser creates some holiday statuses -> crash because only HrManagers should do this
with self.assertRaises(AccessError):
self.env['hr.leave.type'].with_user(self.user_hruser_id).create({
'name': 'UserCheats',
'requires_allocation': 'no',
})
def test_users_tz_shift_back(self):
"""This test follows closely related bug report and simulates its situation.
We're located in Saipan (GMT+10) and we allocate some employee a leave from 19Aug-20Aug.
Then we simulate opening the employee's calendar and attempting to allocate 21August.
We should not get any valid allocation there as is it outsite of valid alocation period.
2024-08-19 2024-08-20 2024-08-21
requested
Valid allocation period day
"""
employee = self.env['hr.employee'].create({'name': 'Test Employee'})
leave_type = self.env['hr.leave.type'].create({'name': 'Test Leave'})
self.env['hr.leave.allocation'].sudo().create({
'state': 'confirm',
'holiday_status_id': leave_type.id,
'employee_id': employee.id,
'date_from': '2024-08-19',
'date_to': '2024-08-20',
}).action_validate()
leave_types = self.env['hr.leave.type'].with_context(
default_date_from='2024-08-20 21:00:00',
default_date_to='2024-08-21 09:00:00',
tz='Pacific/Saipan',
employee_id=employee.id,
).search([('has_valid_allocation', '=', True)], limit=1)
self.assertFalse(leave_types, "Got valid leaves outside vaild period")

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,120 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import datetime
from dateutil.relativedelta import relativedelta
from odoo.addons.base.tests.common import TransactionCaseWithUserDemo
from odoo.tests.common import tagged, users, warmup
from odoo.tools.misc import DEFAULT_SERVER_DATE_FORMAT
from odoo.addons.hr_holidays.tests.common import TestHrHolidaysCommon
@tagged('out_of_office')
class TestOutOfOffice(TestHrHolidaysCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.leave_type = cls.env['hr.leave.type'].create({
'name': 'Legal Leaves',
'time_type': 'leave',
'requires_allocation': 'no',
})
def test_leave_ooo(self):
self.assertNotEqual(self.employee_hruser.user_id.im_status, 'leave_offline', 'user should not be on leave')
self.assertNotEqual(self.employee_hruser.user_id.partner_id.im_status, 'leave_offline', 'user should not be on leave')
leave_date_end = (datetime.today() + relativedelta(days=3))
leave = self.env['hr.leave'].create({
'name': 'Christmas',
'employee_id': self.employee_hruser.id,
'holiday_status_id': self.leave_type.id,
'date_from': (datetime.today() - relativedelta(days=1)),
'date_to': leave_date_end,
'number_of_days': 4,
})
leave.action_approve()
self.assertEqual(self.employee_hruser.user_id.im_status, 'leave_offline', 'user should be out (leave_offline)')
self.assertEqual(self.employee_hruser.user_id.partner_id.im_status, 'leave_offline', 'user should be out (leave_offline)')
partner = self.employee_hruser.user_id.partner_id
partner2 = self.user_employee.partner_id
channel = self.env['mail.channel'].with_user(self.user_employee).with_context({
'mail_create_nolog': True,
'mail_create_nosubscribe': True,
}).create({
'channel_partner_ids': [(4, partner.id), (4, partner2.id)],
'channel_type': 'chat',
'name': 'test'
})
channel_info = channel.channel_info()[0]
# shape of channelMembers is [('insert', data...)], [0][1] accesses the data
members_data = channel_info['channel']['channelMembers'][0][1]
self.assertEqual(len(members_data), 2, "Channel info should get info for the 2 members")
partner_info = next(member for member in members_data if member['persona']['partner']['email'] == partner.email)
partner2_info = next(member for member in members_data if member['persona']['partner']['email'] == partner2.email)
self.assertFalse(partner2_info['persona']['partner']['out_of_office_date_end'], "current user should not be out of office")
self.assertEqual(partner_info['persona']['partner']['out_of_office_date_end'], leave_date_end.strftime(DEFAULT_SERVER_DATE_FORMAT), "correspondent should be out of office")
@tagged('out_of_office')
class TestOutOfOfficePerformance(TestHrHolidaysCommon, TransactionCaseWithUserDemo):
@classmethod
def setUpClass(cls):
super(TestOutOfOfficePerformance, cls).setUpClass()
cls.leave_type = cls.env['hr.leave.type'].create({
'name': 'Legal Leaves',
'time_type': 'leave',
'requires_allocation': 'no',
})
cls.leave_date_end = (datetime.today() + relativedelta(days=3))
cls.leave = cls.env['hr.leave'].create({
'name': 'Christmas',
'employee_id': cls.employee_hruser_id,
'holiday_status_id': cls.leave_type.id,
'date_from': (datetime.today() - relativedelta(days=1)),
'date_to': (datetime.today() + relativedelta(days=3)),
'number_of_days': 4,
})
cls.hr_user = cls.employee_hruser.user_id
cls.hr_partner = cls.employee_hruser.user_id.partner_id
cls.employer_partner = cls.user_employee.partner_id
@users('__system__', 'demo')
@warmup
def test_leave_im_status_performance_partner_offline(self):
with self.assertQueryCount(__system__=2, demo=2):
self.assertEqual(self.employer_partner.im_status, 'offline')
@users('__system__', 'demo')
@warmup
def test_leave_im_status_performance_user_leave_offline(self):
self.leave.write({'state': 'validate'})
with self.assertQueryCount(__system__=2, demo=2):
self.assertEqual(self.hr_user.im_status, 'leave_offline')
@users('__system__', 'demo')
@warmup
def test_leave_im_status_performance_partner_leave_offline(self):
self.leave.write({'state': 'validate'})
with self.assertQueryCount(__system__=2, demo=2):
self.assertEqual(self.hr_partner.im_status, 'leave_offline')
def test_search_absent_employee(self):
present_employees = self.env['hr.employee'].search([('is_absent', '!=', True)])
absent_employees = self.env['hr.employee'].search([('is_absent', '=', True)])
today_date = datetime.utcnow().date()
holidays = self.env['hr.leave'].sudo().search([
('employee_id', '!=', False),
('state', '=', 'validate'),
('date_from', '<=', today_date),
('date_to', '>=', today_date),
])
for employee in present_employees:
self.assertFalse(employee in holidays.employee_id)
for employee in absent_employees:
self.assertFalse(employee not in holidays.employee_id)

View file

@ -0,0 +1,67 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import date
from dateutil.relativedelta import relativedelta
from odoo import Command
from odoo.tests.common import tagged, TransactionCase
from odoo.tools.misc import DEFAULT_SERVER_DATE_FORMAT
@tagged('post_install', '-at_install')
class TestPartner(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
# use a single value for today throughout the tests to avoid weird scenarios around midnight
cls.today = date.today()
baseUser = cls.env['res.users'].create({
'email': 'e.e@example.com',
'groups_id': [Command.link(cls.env.ref('base.group_user').id)],
'login': 'emp',
'name': 'Ernest Employee',
'notification_type': 'inbox',
'signature': '--\nErnest',
})
cls.partner = baseUser.partner_id
cls.users = baseUser + cls.env['res.users'].create({
'name': 'test1',
'login': 'test1',
'email': 'test1@example.com',
'partner_id': cls.partner.id,
})
cls.employees = cls.env['hr.employee'].create([{
'user_id': user.id,
} for user in cls.users])
cls.leave_type = cls.env['hr.leave.type'].create({
'requires_allocation': 'no',
'name': 'Legal Leaves',
'time_type': 'leave',
})
cls.leaves = cls.env['hr.leave'].create([{
'date_from': cls.today + relativedelta(days=-2),
'date_to': cls.today + relativedelta(days=2),
'employee_id': cls.employees[0].id,
'holiday_status_id': cls.leave_type.id,
}, {
'date_from': cls.today + relativedelta(days=-2),
'date_to': cls.today + relativedelta(days=3),
'employee_id': cls.employees[1].id,
'holiday_status_id': cls.leave_type.id,
}])
def test_res_partner_mail_partner_format(self):
self.leaves.write({'state': 'validate'})
self.assertEqual(
self.partner.mail_partner_format()[self.partner]['out_of_office_date_end'],
(self.today + relativedelta(days=2)).strftime(DEFAULT_SERVER_DATE_FORMAT),
'Return date is the first return date of all users associated with a partner',
)
self.leaves[1].action_refuse()
self.assertEqual(
self.partner.mail_partner_format()[self.partner]['out_of_office_date_end'],
False,
'Partner is not considered out of office if one of their users is not on holiday',
)

View file

@ -0,0 +1,208 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import datetime
from freezegun import freeze_time
from odoo import tests
from odoo.tests import new_test_user
from odoo.tests.common import Form, TransactionCase
from odoo.exceptions import ValidationError
@tests.tagged('access_rights', 'post_install', '-at_install')
class TestHrLeaveStressDays(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.default_calendar = cls.env['resource.calendar'].create({
'name': 'moon calendar',
})
cls.company = cls.env['res.company'].create({
'name': 'super company',
'resource_calendar_id': cls.default_calendar.id,
})
cls.employee_user = new_test_user(cls.env, login='user', groups='base.group_user', company_ids=[(6, 0, cls.company.ids)], company_id=cls.company.id)
cls.manager_user = new_test_user(cls.env, login='manager', groups='base.group_user,hr_holidays.group_hr_holidays_manager', company_ids=[(6, 0, cls.company.ids)], company_id=cls.company.id)
cls.employee_emp = cls.env['hr.employee'].create({
'name': 'Toto Employee',
'company_id': cls.company.id,
'user_id': cls.employee_user.id,
'resource_calendar_id': cls.default_calendar.id,
})
cls.manager_emp = cls.env['hr.employee'].create({
'name': 'Toto Mananger',
'company_id': cls.company.id,
'user_id': cls.manager_user.id,
})
cls.leave_type = cls.env['hr.leave.type'].create({
'name': 'Unlimited',
'leave_validation_type': 'hr',
'requires_allocation': 'no',
'company_id': cls.company.id,
})
cls.stress_day = cls.env['hr.leave.stress.day'].create({
'name': 'Super Event',
'company_id': cls.company.id,
'start_date': datetime(2021, 11, 2),
'end_date': datetime(2021, 11, 2),
'color': 1,
'resource_calendar_id': cls.default_calendar.id,
})
cls.stress_week = cls.env['hr.leave.stress.day'].create({
'name': 'Super Event End Of Week',
'company_id': cls.company.id,
'start_date': datetime(2021, 11, 8),
'end_date': datetime(2021, 11, 12),
'color': 2,
'resource_calendar_id': cls.default_calendar.id,
})
@freeze_time('2021-10-15')
def test_request_stress_days(self):
# An employee can request time off outside stress days
self.env['hr.leave'].with_user(self.employee_user.id).create({
'name': 'coucou',
'holiday_status_id': self.leave_type.id,
'employee_id': self.employee_emp.id,
'date_from': datetime(2021, 11, 3),
'date_to': datetime(2021, 11, 3),
'number_of_days': 1,
})
# Taking a time off during a Stress Day is not allowed for a simple employee...
with self.assertRaises(ValidationError):
self.env['hr.leave'].with_user(self.employee_user.id).create({
'name': 'coucou',
'holiday_status_id': self.leave_type.id,
'employee_id': self.employee_emp.id,
'date_from': datetime(2021, 11, 3),
'date_to': datetime(2021, 11, 17),
'number_of_days': 1,
})
with self.assertRaises(ValidationError):
self.env['hr.leave'].with_user(self.employee_user.id).create({
'name': 'coucou',
'holiday_status_id': self.leave_type.id,
'employee_id': self.employee_emp.id,
'date_from': datetime(2021, 11, 9),
'date_to': datetime(2021, 11, 9),
'number_of_days': 1,
})
# ... but is allowed for a Time Off Officer
self.env['hr.leave'].with_user(self.manager_user.id).create({
'name': 'coucou',
'holiday_status_id': self.leave_type.id,
'employee_id': self.employee_emp.id,
'date_from': datetime(2021, 11, 2),
'date_to': datetime(2021, 11, 2),
'number_of_days': 1,
})
@freeze_time('2021-10-15')
def test_get_stress_days(self):
stress_days = self.employee_emp.get_stress_days('2021-11-01', '2021-11-30')
# Stress Days spanning multiple days should be split in single days
expected_data = {'2021-11-02': 1, '2021-11-08': 2, '2021-11-09': 2, '2021-11-10': 2, '2021-11-11': 2, '2021-11-12': 2}
self.assertEqual(len(stress_days), len(expected_data))
for day, color in expected_data.items():
self.assertTrue(day in stress_days)
self.assertEqual(color, stress_days[day])
with self.assertRaises(ValidationError), Form(self.env['hr.leave'].with_user(self.employee_user.id).with_context(default_employee_id=self.employee_emp.id)) as leave_form:
leave_form.holiday_status_id = self.leave_type
leave_form.request_date_from = datetime(2021, 11, 1)
leave_form.request_date_to = datetime(2021, 11, 1)
self.assertFalse(leave_form.has_stress_day)
leave_form.request_date_to = datetime(2021, 11, 5)
self.assertTrue(leave_form.has_stress_day)
@freeze_time('2021-10-15')
def test_department_stress_days(self):
production_department = self.env['hr.department'].create({
'name': 'Production Department',
'company_id': self.company.id,
})
post_production_department = self.env['hr.department'].create({
'name': 'Post-Production Department',
'company_id': self.company.id,
'parent_id': production_department.id,
})
deployment_department = self.env['hr.department'].create({
'name': 'Deployment Department',
'company_id': self.company.id,
'parent_id': production_department.id,
})
self.employee_emp.write({
'department_id': post_production_department.id
})
# Create one stress day for each department
self.env['hr.leave.stress.day'].create({
'name': 'Last Rush Before Launch (production)',
'company_id': self.company.id,
'start_date': datetime(2021, 11, 3),
'end_date': datetime(2021, 11, 3),
'color': 1,
'resource_calendar_id': self.default_calendar.id,
'department_ids': [production_department.id],
})
self.env['hr.leave.stress.day'].create({
'name': 'Last Rush Before Launch (post-production)',
'company_id': self.company.id,
'start_date': datetime(2021, 11, 4),
'end_date': datetime(2021, 11, 4),
'color': 1,
'resource_calendar_id': self.default_calendar.id,
'department_ids': [post_production_department.id],
})
self.env['hr.leave.stress.day'].create({
'name': 'Last Rush Before Launch (deployment)',
'company_id': self.company.id,
'start_date': datetime(2021, 11, 5),
'end_date': datetime(2021, 11, 5),
'color': 1,
'resource_calendar_id': self.default_calendar.id,
'department_ids': [deployment_department.id],
})
# The employee should only be able to create a time off on stress days
# that do not include his department
with self.assertRaises(ValidationError):
self.env['hr.leave'].with_user(self.employee_user.id).create({
'name': 'have been given the black spot',
'holiday_status_id': self.leave_type.id,
'employee_id': self.employee_emp.id,
'date_from': datetime(2021, 11, 3),
'date_to': datetime(2021, 11, 3),
'number_of_days': 1,
})
with self.assertRaises(ValidationError):
self.env['hr.leave'].with_user(self.employee_user.id).create({
'name': 'have been given the black spot',
'holiday_status_id': self.leave_type.id,
'employee_id': self.employee_emp.id,
'date_from': datetime(2021, 11, 4),
'date_to': datetime(2021, 11, 4),
'number_of_days': 1,
})
self.env['hr.leave'].with_user(self.employee_user.id).create({
'name': 'have been given the black spot',
'holiday_status_id': self.leave_type.id,
'employee_id': self.employee_emp.id,
'date_from': datetime(2021, 11, 5),
'date_to': datetime(2021, 11, 5),
'number_of_days': 1,
})

View file

@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import date
from odoo.addons.base.models.ir_model import MODULE_UNINSTALL_FLAG
from odoo.tests import tagged, TransactionCase
@tagged('-at_install', 'post_install')
class TestHrLeaveUninstall(TransactionCase):
def test_unlink_model(self):
employee = self.env['hr.employee'].create({
'name': 'Test Employee'
})
holiday = self.env['hr.leave'].create({
'name': 'Time Off',
'employee_id': employee.id,
'holiday_status_id': self.env.ref('hr_holidays.holiday_status_sl').id,
'request_date_from': date(2020, 1, 7),
'date_from': date(2020, 1, 7),
'request_date_to': date(2020, 1, 9),
'date_to': date(2020, 1, 9),
'number_of_days': 3,
})
holiday.activity_schedule(
'hr_holidays.mail_act_leave_approval',
note='Test Note',
user_id=self.env.user.id)
model = self.env['ir.model'].search([('model', '=', 'hr.leave')])
activity_type = self.env['mail.activity'].search([
('res_model', '=', 'hr.leave')
]).activity_type_id
self.assertTrue(activity_type)
self.assertIn('hr.leave', activity_type.mapped('res_model'))
model.sudo().with_context(**{MODULE_UNINSTALL_FLAG: True}).unlink()
self.assertFalse(model.exists())
domain = [('res_model', '=', 'hr.leave')]
self.assertFalse(self.env['mail.activity'].search(domain))
self.assertFalse(self.env['mail.activity.type'].search(domain))
self.assertFalse(self.env['mail.followers'].search(domain))
self.assertFalse(self.env['mail.message'].search([
('model', '=', 'hr.leave'),
]))