mirror of
https://github.com/bringout/oca-ocb-hr.git
synced 2026-04-26 21:12:05 +02:00
Initial commit: Hr packages
This commit is contained in:
commit
62531cd146
2820 changed files with 1432848 additions and 0 deletions
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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")
|
||||
|
|
@ -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))
|
||||
|
|
@ -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')
|
||||
|
|
@ -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)
|
||||
|
|
@ -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")
|
||||
|
||||
|
|
@ -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.')
|
||||
|
|
@ -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")
|
||||
|
|
@ -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'),
|
||||
})
|
||||
|
|
@ -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})
|
||||
|
|
@ -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")
|
||||
|
|
@ -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
|
|
@ -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)
|
||||
|
|
@ -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',
|
||||
)
|
||||
|
|
@ -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,
|
||||
})
|
||||
|
|
@ -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'),
|
||||
]))
|
||||
Loading…
Add table
Add a link
Reference in a new issue