Odoo18-Base/addons/hr_holidays/tests/test_leave_requests.py

1212 lines
56 KiB
Python
Raw Permalink Normal View History

2025-01-06 10:57:38 +07:00
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import datetime, date, timedelta
import time
from dateutil.relativedelta import relativedelta
from freezegun import freeze_time
from pytz import timezone
from odoo import fields, Command
from odoo.exceptions import UserError, ValidationError
from odoo.tools import date_utils, mute_logger
from odoo.tests import Form, tagged
from odoo.addons.hr_holidays.tests.common import TestHrHolidaysCommon
@tagged('leave_requests')
class TestLeaveRequests(TestHrHolidaysCommon):
def _check_holidays_status(self, holiday_status, employee, ml, lt, rl, vrl):
result = holiday_status.get_allocation_data(employee)[employee][0][1]
self.assertEqual(
result['max_leaves'], ml,
'hr_holidays: wrong type days computation')
self.assertEqual(
result['leaves_taken'], lt,
'hr_holidays: wrong type days computation')
self.assertEqual(
result['remaining_leaves'], rl,
'hr_holidays: wrong type days computation')
self.assertEqual(
result['virtual_remaining_leaves'], vrl,
'hr_holidays: wrong type days computation')
@classmethod
def setUpClass(cls):
super(TestLeaveRequests, cls).setUpClass()
# Make sure we have the rights to create, validate and delete the leaves, leave types and allocations
LeaveType = cls.env['hr.leave.type'].with_user(cls.user_hrmanager_id).with_context(tracking_disable=True)
cls.holidays_type_1 = LeaveType.create({
'name': 'NotLimitedHR',
'requires_allocation': 'no',
'leave_validation_type': 'hr',
})
cls.holidays_type_2 = LeaveType.create({
'name': 'Limited',
'requires_allocation': 'yes',
'employee_requests': 'yes',
'leave_validation_type': 'hr',
})
cls.holidays_type_3 = LeaveType.create({
'name': 'TimeNotLimited',
'requires_allocation': 'no',
'leave_validation_type': 'manager',
})
cls.holidays_type_4 = LeaveType.create({
'name': 'Limited with 2 approvals',
'requires_allocation': 'yes',
'employee_requests': 'yes',
'leave_validation_type': 'both',
})
cls.holidays_support_document = LeaveType.create({
'name': 'Time off with support document',
'support_document': True,
'requires_allocation': 'no',
'leave_validation_type': 'no_validation',
})
cls.set_employee_create_date(cls.employee_emp_id, '2010-02-03 00:00:00')
cls.set_employee_create_date(cls.employee_hruser_id, '2010-02-03 00:00:00')
def _check_holidays_count(self, holidays_count_result, ml, lt, rl, vrl, vlt):
self.assertEqual(holidays_count_result['max_leaves'], ml)
self.assertEqual(holidays_count_result['remaining_leaves'], rl)
self.assertEqual(holidays_count_result['virtual_remaining_leaves'], vrl)
self.assertEqual(holidays_count_result['leaves_taken'], lt)
self.assertEqual(holidays_count_result['virtual_leaves_taken'], vlt)
@classmethod
def set_employee_create_date(cls, _id, newdate):
""" This method is a hack in order to be able to define/redefine the create_date
of the employees.
This is done in SQL because ORM does not allow to write onto the create_date field.
"""
cls.env.cr.execute("""
UPDATE
hr_employee
SET create_date = '%s'
WHERE id = %s
""" % (newdate, _id))
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_overlapping_requests(self):
""" Employee cannot create a new leave request at the same time, avoid interlapping """
self.env['hr.leave'].with_user(self.user_employee_id).create({
'name': 'Hol11',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_1.id,
'request_date_from': (date.today() - relativedelta(days=1)),
'request_date_to': date.today(),
})
with self.assertRaises(ValidationError):
self.env['hr.leave'].with_user(self.user_employee_id).create({
'name': 'Hol21',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_1.id,
'request_date_from': (datetime.today() - relativedelta(days=1)),
'request_date_to': datetime.today(),
})
def test_limited_type_not_enough_days(self):
with freeze_time('2022-01-05'):
allocation = self.env['hr.leave.allocation'].with_user(self.user_hruser_id).create({
'name': 'Days for limited category',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_2.id,
'number_of_days': 2,
'state': 'confirm',
'date_from': time.strftime('%Y-1-1'),
'date_to': time.strftime('%Y-12-31'),
})
allocation.action_validate()
# Employee cannot take a leave longer than the allocation
with self.assertRaises(ValidationError):
self.env['hr.leave'].with_user(self.user_employee_id).create({
'name': 'Invalid Hol21',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_2.id,
'request_date_from': time.strftime('2022-02-01'),
'request_date_to': time.strftime('2022-02-04'),
})
# A leave cannot be modified so that it's longer than the allocation
valid_leave = self.env['hr.leave'].with_user(self.user_employee_id).create({
'name': 'Valid Hol21',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_2.id,
'request_date_from': time.strftime('2022-02-02'),
'request_date_to': time.strftime('2022-02-03'),
})
with self.assertRaises(ValidationError):
valid_leave.write({
'request_date_from': time.strftime('2022-02-01'),
'request_date_to': time.strftime('2022-02-05'),
})
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_limited_type_days_left(self):
""" Employee creates a leave request in a limited category and has enough days left """
with freeze_time('2022-01-05'):
allocation = self.env['hr.leave.allocation'].with_user(self.user_hruser_id).create({
'name': 'Days for limited category',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_2.id,
'number_of_days': 2,
'state': 'confirm',
'date_from': time.strftime('%Y-1-1'),
'date_to': time.strftime('%Y-12-31'),
})
allocation.action_validate()
holiday_status = self.holidays_type_2.with_user(self.user_employee_id)
self._check_holidays_status(holiday_status, self.employee_emp, 2.0, 0.0, 2.0, 2.0)
hol = self.env['hr.leave'].with_user(self.user_employee_id).create({
'name': 'Hol11',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_2.id,
'request_date_from': (datetime.today() - relativedelta(days=1)),
'request_date_to': datetime.today(),
})
holiday_status.invalidate_model()
self._check_holidays_status(holiday_status, self.employee_emp, 2.0, 0.0, 2.0, 0.0)
hol.with_user(self.user_hrmanager_id).action_approve()
holiday_status.invalidate_model(['max_leaves'])
self._check_holidays_status(holiday_status, self.employee_emp, 2.0, 2.0, 0.0, 0.0)
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_accrual_validity_time_valid(self):
""" Employee ask leave during a valid validity time """
allocation = self.env['hr.leave.allocation'].with_user(self.user_hrmanager_id).create({
'name': 'Sick Time Off',
'holiday_status_id': self.holidays_type_2.id,
'employee_id': self.employee_emp.id,
'date_from': fields.Datetime.from_string('2017-01-01 00:00:00'),
'date_to': fields.Datetime.from_string('2017-06-01 00:00:00'),
'number_of_days': 10,
})
allocation.action_validate()
self.env['hr.leave'].with_user(self.user_employee_id).create({
'name': 'Valid time period',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_2.id,
'request_date_from': fields.Date.from_string('2017-03-03'),
'request_date_to': fields.Date.from_string('2017-03-11'),
})
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_department_leave(self):
""" Create a department leave """
self.employee_hrmanager.write({'department_id': self.hr_dept.id})
self.assertFalse(self.env['hr.leave'].search([('employee_id', 'in', self.hr_dept.member_ids.ids)]))
leave_wizard_form = Form(self.env['hr.leave.generate.multi.wizard'].with_user(self.user_hrmanager))
leave_wizard_form.allocation_mode = 'department'
leave_wizard_form.department_id = self.hr_dept
leave_wizard_form.holiday_status_id = self.holidays_type_1
leave_wizard_form.date_from = date(2019, 5, 6)
leave_wizard_form.date_to = date(2019, 5, 6)
leave_wizard = leave_wizard_form.save()
leave_wizard.action_generate_time_off()
member_ids = self.hr_dept.member_ids.ids
self.assertEqual(self.env['hr.leave'].search_count([('employee_id', 'in', member_ids)]), len(member_ids), "Time Off should be created for members of department")
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_allocation_request(self):
""" Create an allocation request """
# employee should be set to current user
allocation_form = Form(self.env['hr.leave.allocation'].with_user(self.user_employee))
allocation_form.holiday_status_id = self.holidays_type_2
allocation_form.date_from = date(2019, 5, 6)
allocation_form.date_to = date(2019, 5, 6)
allocation_form.name = 'New Allocation Request'
allocation_form.save()
def test_allocation_constrain_dates_check(self):
with self.assertRaises(UserError):
self.env['hr.leave.allocation'].create({
'name': 'Test allocation',
'holiday_status_id': self.holidays_type_2.id,
'number_of_days': 1,
'employee_id': self.employee_emp_id,
'state': 'confirm',
'date_from': time.strftime('%Y-%m-10'),
'date_to': time.strftime('%Y-%m-01'),
})
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_employee_is_absent(self):
""" Only the concerned employee should be considered absent """
user_employee_leave = self.env['hr.leave'].with_user(self.user_employee_id).create({
'name': 'Hol11',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_1.id,
'request_date_from': (date.today() - relativedelta(days=1)),
'request_date_to': date.today() + relativedelta(days=1),
})
(self.employee_emp | self.employee_hrmanager).mapped('is_absent') # compute in batch
self.assertFalse(self.employee_emp.is_absent, "He should not be considered absent")
self.assertFalse(self.employee_hrmanager.is_absent, "He should not be considered absent")
user_employee_leave.sudo().write({
'state': 'validate',
})
(self.employee_emp | self.employee_hrmanager)._compute_leave_status()
self.assertTrue(self.employee_emp.is_absent, "He should be considered absent")
self.assertFalse(self.employee_hrmanager.is_absent, "He should not be considered absent")
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_timezone_employee_leave_request(self):
""" Create a leave request for an employee in another timezone """
self.employee_emp.tz = 'Pacific/Auckland' # GMT+12
leave = self.env['hr.leave'].new({
'employee_id': self.employee_emp.id,
'holiday_status_id': self.holidays_type_1.id,
'request_unit_hours': True,
'request_date_from': date(2019, 5, 6),
'request_date_to': date(2019, 5, 6),
'request_hour_from': 8, # 8:00 AM in the employee's timezone
'request_hour_to': 17, # 5:00 PM in the employee's timezone
})
self.assertEqual(leave.date_from, datetime(2019, 5, 5, 20, 0, 0), "It should have been localized before saving in UTC")
self.assertEqual(leave.date_to, datetime(2019, 5, 6, 5, 0, 0), "It should have been localized before saving in UTC")
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_timezone_company_leave_request(self):
""" Create a leave request for a company in another timezone """
company = self.env['res.company'].create({'name': "Hergé"})
company.resource_calendar_id.tz = 'Australia/Sydney' # GMT+12
leave = self.env['hr.leave'].new({
'employee_id': self.employee_emp.id,
'holiday_status_id': self.holidays_type_1.id,
'request_unit_hours': True,
'company_id': company.id,
'request_date_from': date(2019, 5, 6),
'request_date_to': date(2019, 5, 6),
'request_hour_from': 8, # 8:00 AM in the company's timezone
'request_hour_to': 17, # 5:00 PM in the company's timezone
})
self.assertEqual(leave.date_from, datetime(2019, 5, 6, 6, 0, 0), "It should have been localized in the Employee timezone")
self.assertEqual(leave.date_to, datetime(2019, 5, 6, 15, 0, 0), "It should have been localized in the Employee timezone")
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_timezone_company_validated(self):
""" Create a leave request for a company in another timezone and validate it """
self.env.user.tz = 'Australia/Sydney' # GMT+12
company = self.env['res.company'].create({'name': "Hergé"})
employee = self.env['hr.employee'].create({'name': "Remi", 'company_id': company.id})
leave_wizard_form = Form(self.env['hr.leave.generate.multi.wizard'])
leave_wizard_form.allocation_mode = 'company'
leave_wizard_form.company_id = company
leave_wizard_form.holiday_status_id = self.holidays_type_1
leave_wizard_form.date_from = date(2019, 5, 6)
leave_wizard_form.date_to = date(2019, 5, 6)
leave_wizard = leave_wizard_form.save()
leave_wizard.action_generate_time_off()
employee_leave = self.env['hr.leave'].search([('employee_id', '=', employee.id)])
self.assertEqual(
employee_leave.request_date_from, date(2019, 5, 6),
"Timezone should be be adapted on the employee leave"
)
def test_number_of_hours_display(self):
# Test that the field number_of_hours_dispay doesn't change
# after time off validation, as it takes the attendances
# minus the resource leaves to compute that field.
calendar = self.env['resource.calendar'].create({
'name': 'Monday Morning Else Full Time 38h/week',
'hours_per_day': 7.6,
'attendance_ids': [
(0, 0, {'name': 'Monday Morning', 'dayofweek': '0', 'hour_from': 8.5, 'hour_to': 12.5, 'day_period': 'morning'}),
(0, 0, {'name': 'Tuesday Morning', 'dayofweek': '1', 'hour_from': 8.5, 'hour_to': 12.5, 'day_period': 'morning'}),
(0, 0, {'name': 'Tuesday Lunch', 'dayofweek': '1', 'hour_from': 12.5, 'hour_to': 13, 'day_period': 'lunch'}),
(0, 0, {'name': 'Tuesday Afternoon', 'dayofweek': '1', 'hour_from': 13, 'hour_to': 17.5, 'day_period': 'afternoon'}),
(0, 0, {'name': 'Wednesday Morning', 'dayofweek': '2', 'hour_from': 8.5, 'hour_to': 12.5, 'day_period': 'morning'}),
(0, 0, {'name': 'Wednesday Lunch', 'dayofweek': '2', 'hour_from': 12.5, 'hour_to': 13, 'day_period': 'lunch'}),
(0, 0, {'name': 'Wednesday Afternoon', 'dayofweek': '2', 'hour_from': 13, 'hour_to': 17.5, 'day_period': 'afternoon'}),
(0, 0, {'name': 'Thursday Morning', 'dayofweek': '3', 'hour_from': 8.5, 'hour_to': 12.5, 'day_period': 'morning'}),
(0, 0, {'name': 'Thursday Lunch', 'dayofweek': '3', 'hour_from': 12.5, 'hour_to': 13, 'day_period': 'lunch'}),
(0, 0, {'name': 'Thursday Afternoon', 'dayofweek': '3', 'hour_from': 13, 'hour_to': 17.5, 'day_period': 'afternoon'}),
(0, 0, {'name': 'Friday Morning', 'dayofweek': '4', 'hour_from': 8.5, 'hour_to': 12.5, 'day_period': 'morning'}),
(0, 0, {'name': 'Friday Lunch', 'dayofweek': '4', 'hour_from': 12.5, 'hour_to': 13, 'day_period': 'lunch'}),
(0, 0, {'name': 'Friday Afternoon', 'dayofweek': '4', 'hour_from': 13, 'hour_to': 17.5, 'day_period': 'afternoon'})
],
})
employee = self.employee_emp
employee.resource_calendar_id = calendar
self.env.user.company_id.resource_calendar_id = calendar
leave_type = self.env['hr.leave.type'].create({
'name': 'Paid Time Off',
'request_unit': 'hour',
'leave_validation_type': 'both',
})
self.env['hr.leave.allocation'].create({
'name': '20 days allocation',
'holiday_status_id': leave_type.id,
'number_of_days': 20,
'employee_id': employee.id,
'state': 'confirm',
'date_from': time.strftime('2018-1-1'),
'date_to': time.strftime('%Y-1-1'),
})
leave1 = self.env['hr.leave'].create({
'name': 'Holiday 1 week',
'employee_id': employee.id,
'holiday_status_id': leave_type.id,
'request_date_from': fields.Date.from_string('2019-12-23'),
'request_date_to': fields.Date.from_string('2019-12-27'),
})
self.assertEqual(leave1.number_of_hours, 38)
leave1.action_approve()
self.assertEqual(leave1.number_of_hours, 38)
leave1.action_validate()
self.assertEqual(leave1.number_of_hours, 38)
leave2 = self.env['hr.leave'].create({
'name': 'Holiday 1 Day',
'employee_id': employee.id,
'holiday_status_id': leave_type.id,
'request_date_from': fields.Datetime.from_string('2019-12-30'),
'request_date_to': fields.Datetime.from_string('2019-12-30'),
})
self.assertEqual(leave2.number_of_hours, 4)
leave2.action_approve()
self.assertEqual(leave2.number_of_hours, 4)
leave2.action_validate()
self.assertEqual(leave2.number_of_hours, 4)
def test_number_of_hours_display_global_leave(self):
# Check that the field number_of_hours
# takes the global leaves into account, even
# after validation
calendar = self.env['resource.calendar'].create({
'name': 'Classic 40h/week',
'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 Lunch', 'dayofweek': '0', 'hour_from': 12, 'hour_to': 13, 'day_period': 'lunch'}),
(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 Lunch', 'dayofweek': '1', 'hour_from': 12, 'hour_to': 13, 'day_period': 'lunch'}),
(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 Lunch', 'dayofweek': '2', 'hour_from': 12, 'hour_to': 13, 'day_period': 'lunch'}),
(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 Lunch', 'dayofweek': '3', 'hour_from': 12, 'hour_to': 13, 'day_period': 'lunch'}),
(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 Lunch', 'dayofweek': '4', 'hour_from': 12, 'hour_to': 13, 'day_period': 'lunch'}),
(0, 0, {'name': 'Friday Afternoon', 'dayofweek': '4', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'})
],
'global_leave_ids': [(0, 0, {
'name': 'Christmas Time Off',
'date_from': fields.Datetime.from_string('2019-12-25 00:00:00'),
'date_to': fields.Datetime.from_string('2019-12-26 23:59:59'),
'resource_id': False,
'time_type': 'leave',
})]
})
employee = self.employee_emp
employee.resource_calendar_id = calendar
self.env.user.company_id.resource_calendar_id = calendar
leave_type = self.env['hr.leave.type'].create({
'name': 'Sick',
'request_unit': 'hour',
'leave_validation_type': 'both',
'requires_allocation': 'no',
})
leave1 = self.env['hr.leave'].create({
'name': 'Sick 1 week during christmas snif',
'employee_id': employee.id,
'holiday_status_id': leave_type.id,
'request_date_from': fields.Date.from_string('2019-12-23'),
'request_date_to': fields.Date.from_string('2019-12-27'),
})
self.assertEqual(leave1.number_of_hours, 24)
leave1.action_approve()
self.assertEqual(leave1.number_of_hours, 24)
leave1.action_validate()
self.assertEqual(leave1.number_of_hours, 24)
def _test_leave_with_tz(self, tz, local_date_from, local_date_to, number_of_days):
self.user_employee.tz = tz
tz = timezone(tz)
# We use new instead of create to avoid the leaves generated for the
# different timezones clashing with each other.
leave = self.env['hr.leave'].with_user(self.user_employee_id).new({
'name': 'Test',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_1.id,
'request_date_from': local_date_from,
'request_date_to': local_date_to,
})
self.assertEqual(leave.number_of_days, number_of_days)
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_leave_defaults_with_timezones(self):
""" Make sure that leaves start with correct defaults for non-UTC timezones """
timezones_to_test = ('UTC', 'Pacific/Midway', 'America/Los_Angeles', 'Asia/Taipei', 'Pacific/Kiritimati') # UTC, UTC -11, UTC -8, UTC +8, UTC +14
# January 2020
# Su Mo Tu We Th Fr Sa
# 1 2 3 4
# 5 6 7 8 9 10 11
# 12 13 14 15 16 17 18
# 19 20 21 22 23 24 25
# 26 27 28 29 30 31
local_date_from = date(2020, 1, 1)
local_date_to = date(2020, 1, 1)
for tz in timezones_to_test:
self._test_leave_with_tz(tz, local_date_from, local_date_to, 1)
# We, Th, Fr, Mo, Tu, We => 6 days
local_date_from = date(2020, 1, 2)
local_date_to = date(2020, 1, 9)
for tz in timezones_to_test:
self._test_leave_with_tz(tz, local_date_from, local_date_to, 6)
def test_expired_allocation(self):
allocation = self.env['hr.leave.allocation'].create({
'name': 'Expired Allocation',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_2.id,
'number_of_days': 20,
'state': 'confirm',
'date_from': '2020-01-01',
'date_to': '2020-12-31',
})
allocation.action_validate()
with self.assertRaises(ValidationError):
self.env['hr.leave'].with_user(self.user_employee_id).create({
'name': 'Holiday Request',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_2.id,
'request_date_from': '2021-09-01',
'request_date_to': '2021-09-01',
})
self.env['hr.leave'].with_user(self.user_employee_id).create({
'name': 'Holiday Request',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_2.id,
'request_date_from': '2020-09-01',
'request_date_to': '2020-09-01',
})
def test_no_days_expired(self):
# First expired allocation
allocation_one = self.env['hr.leave.allocation'].create({
'name': 'Expired Allocation',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_2.id,
'number_of_days': 20,
'state': 'confirm',
'date_from': '2020-01-01',
'date_to': '2020-12-31',
})
allocation_one.action_validate()
allocation_two = self.env['hr.leave.allocation'].create({
'name': 'Expired Allocation',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_2.id,
'number_of_days': 3,
'state': 'confirm',
'date_from': '2021-01-01',
'date_to': '2021-12-31',
})
allocation_two.action_validate()
# Try creating a request that could be validated if allocation1 was still valid
with self.assertRaises(ValidationError):
self.env['hr.leave'].with_user(self.user_employee_id).create({
'name': 'Holiday Request',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_2.id,
'request_date_from': '2021-09-06',
'request_date_to': '2021-09-10',
})
# This time we have enough days
self.env['hr.leave'].with_user(self.user_employee_id).create({
'name': 'Holiday Request',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_2.id,
'request_date_from': '2021-09-06',
'request_date_to': '2021-09-08',
})
def test_company_leaves(self):
# First expired allocation
self.env['hr.leave.allocation.generate.multi.wizard'].create({
'name': 'Allocation',
'company_id': self.env.company.id,
'holiday_status_id': self.holidays_type_1.id,
'duration': 20,
'date_from': '2021-01-01',
})
req1_form = Form(self.env['hr.leave'].sudo())
req1_form.employee_id = self.employee_emp
req1_form.holiday_status_id = self.holidays_type_1
req1_form.request_date_from = fields.Date.to_date('2021-12-06')
req1_form.request_date_to = fields.Date.to_date('2021-12-08')
self.assertEqual(req1_form.number_of_days, 3)
req1_form.save().action_approve()
def test_leave_with_public_holiday_other_company(self):
other_company = self.env['res.company'].create({
'name': 'Test Company 2',
})
# Create a public holiday for the second company
p_leave = self.env['resource.calendar.leaves'].create({
'date_from': datetime(2022, 3, 11),
'date_to': datetime(2022, 3, 11, 23, 59, 59),
})
p_leave.company_id = other_company
leave = self.env['hr.leave'].with_user(self.user_employee_id).create({
'name': 'Holiday Request',
'employee_id': self.employee_emp.id,
'holiday_status_id': self.holidays_type_1.id,
'request_date_from': date(2022, 3, 11),
'request_date_to': date(2022, 3, 11),
})
self.assertEqual(leave.number_of_days, 1)
def test_several_allocations(self):
allocation_vals = {
'name': 'Allocation',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_2.id,
'number_of_days': 5,
'state': 'confirm',
'date_from': '2022-01-01',
'date_to': '2022-12-31',
}
self.env['hr.leave.allocation'].create(allocation_vals)
self.env['hr.leave.allocation'].create(allocation_vals)
# Able to create a leave of 10 days with two allocations of 5 days
self.env['hr.leave'].with_user(self.user_employee_id).create({
'name': 'Holiday Request',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_2.id,
'request_date_from': '2022-01-01',
'request_date_to': '2022-01-15',
})
def test_several_allocations_split(self):
Allocation = self.env['hr.leave.allocation']
allocation_vals = {
'name': 'Allocation',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_2.id,
'state': 'confirm',
'date_from': '2022-01-01',
'date_to': '2022-12-31',
}
Leave = self.env['hr.leave'].with_user(self.user_employee_id).sudo()
leave_vals = {
'name': 'Holiday Request',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_2.id,
}
for unit in ['hour', 'day']:
self.holidays_type_2.request_unit = unit
allocation_vals.update({'number_of_days': 4})
allocation_4days = Allocation.create(allocation_vals)
allocation_4days.action_validate()
allocation_vals.update({'number_of_days': 1})
allocation_1day = Allocation.create(allocation_vals)
allocation_1day.action_validate()
allocations = (allocation_4days + allocation_1day)
leave_vals.update({
'request_date_from': '2022-01-03',
'request_date_to': '2022-01-06',
})
leave_confirm = Leave.create(leave_vals)
leave_confirm.action_refuse()
leave_vals.update({
'request_date_from': '2022-01-03',
'request_date_to': '2022-01-06',
})
leave_4days = Leave.create(leave_vals)
leave_vals.update({
'request_date_from': '2022-01-07',
'request_date_to': '2022-01-07',
})
leave_1day = Leave.create(leave_vals)
leaves = (leave_4days + leave_1day)
leaves.action_approve()
allocation_days = self.employee_emp._get_consumed_leaves(self.holidays_type_2)[0]
self.assertEqual(
allocation_days[self.employee_emp][self.holidays_type_2][allocation_4days]['leaves_taken'],
leave_4days['number_of_%ss' % unit],
'As 4 days were available in this allocation, they should have been taken')
self.assertEqual(
allocation_days[self.employee_emp][self.holidays_type_2][allocation_1day]['leaves_taken'],
leave_1day['number_of_%ss' % unit],
'As no days were available in previous allocation, they should have been taken in this one')
leaves.action_refuse()
allocations.action_refuse()
def test_time_off_recovery_on_create(self):
time_off = self.env['hr.leave'].create([
{
'name': 'Holiday Request',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_1.id,
'request_date_from': '2021-12-06',
'request_date_to': '2021-12-10',
},
{
'name': 'Holiday Request',
'employee_id': self.employee_hruser_id,
'holiday_status_id': self.holidays_type_1.id,
'request_date_from': '2021-12-06',
'request_date_to': '2021-12-10',
}
])
self.assertEqual(time_off[0].number_of_days, 5)
self.assertEqual(time_off[1].number_of_days, 5)
self.env['resource.calendar.leaves'].create({
'name': 'Global Time Off',
'date_from': '2021-12-07 00:00:00',
'date_to': '2021-12-07 23:59:59',
})
self.assertEqual(time_off[0].number_of_days, 4)
self.assertEqual(time_off[1].number_of_days, 4)
def test_time_off_recovery_on_write(self):
global_time_off = self.env['resource.calendar.leaves'].create({
'name': 'Global Time Off',
'date_from': '2021-12-07 00:00:00',
'date_to': '2021-12-07 23:59:59',
})
time_off_1 = self.env['hr.leave'].create({
'name': 'Holiday Request',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_1.id,
'request_date_from': '2021-12-06',
'request_date_to': '2021-12-10',
})
self.assertEqual(time_off_1.number_of_days, 4)
time_off_2 = self.env['hr.leave'].create({
'name': 'Holiday Request',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_1.id,
'request_date_from': '2021-12-13',
'request_date_to': '2021-12-17',
})
self.assertEqual(time_off_2.number_of_days, 5)
# adding 1 day to the global time off
global_time_off.write({
'date_to': '2021-12-08 23:59:59',
})
self.assertEqual(time_off_1.number_of_days, 3)
# moving the global time off to the next week
global_time_off.write({
'date_from': '2021-12-15 00:00:00',
'date_to': '2021-12-15 23:59:59',
})
self.assertEqual(time_off_1.number_of_days, 5)
self.assertEqual(time_off_2.number_of_days, 4)
def test_time_off_recovery_on_unlink(self):
global_time_off = self.env['resource.calendar.leaves'].create({
'name': 'Global Time Off',
'date_from': '2021-12-07 00:00:00',
'date_to': '2021-12-07 23:59:59',
})
time_off = self.env['hr.leave'].create({
'name': 'Holiday Request',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_1.id,
'request_date_from': '2021-12-06',
'request_date_to': '2021-12-10',
})
self.assertEqual(time_off.number_of_days, 4)
global_time_off.unlink()
self.assertEqual(time_off.number_of_days, 5)
def test_time_off_duration_zero(self):
time_off = self.env['hr.leave'].create({
'name': 'Holiday Request',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_1.id,
'request_date_from': '2021-11-15',
'request_date_to': '2021-11-19',
})
self.assertEqual(time_off.number_of_days, 5)
self.env['resource.calendar.leaves'].create({
'name': 'Global Time Off',
'date_from': '2021-11-15 00:00:00',
'date_to': '2021-11-19 23:59:59',
})
self.assertEqual(time_off.state, 'confirm')
self.assertEqual(time_off.number_of_days, 0)
def test_time_off_irregular_working_schedule(self):
# Test a specific case where `_get_attendances` bugged out when a
# very specific working schedule was used.
calendar = self.env['resource.calendar'].create({
'name': 'Irregular Working Schedule (monday morning - wednesday afternoon)',
'attendance_ids': [
(0, 0, {'name': 'Monday Morning', 'dayofweek': '0', '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'}),
],
})
self.employee_emp.resource_calendar_id = calendar
# Take a time off on the next tuesday (when the employee is not
# supposed to work) Previously this would raise a ValidationError.
next_tuesday = date_utils.start_of(fields.Date.today() + relativedelta(days=7), 'week') + relativedelta(days=1)
time_off = self.env['hr.leave'].create({
'name': 'Holiday Request',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_1.id,
'request_date_from': next_tuesday,
'request_date_to': next_tuesday,
})
self.assertEqual(time_off.number_of_days, 0)
def test_holiday_type_allocation(self):
with freeze_time('2020-09-15'):
allocation = self.env['hr.leave.allocation'].create({
'name': 'Expired Allocation',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_2.id,
'number_of_days': 5,
'state': 'confirm',
'date_from': '2020-01-01',
'date_to': '2020-12-31',
})
allocation.action_validate()
self.env['hr.leave'].with_user(self.user_employee_id).create({
'name': 'Holiday Request',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_2.id,
'request_date_from': '2020-09-07',
'request_date_to': '2020-09-09',
})
self._check_holidays_count(
self.employee_emp._get_consumed_leaves(self.holidays_type_2)[0][self.employee_emp][self.holidays_type_2][allocation],
ml=5, lt=0, rl=5, vrl=2, vlt=3,
)
def test_archived_allocation(self):
with freeze_time('2022-09-15'):
allocation_2021 = self.env['hr.leave.allocation'].create({
'name': 'Annual Time Off 2021',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_2.id,
'number_of_days': 10,
'state': 'confirm',
'date_from': '2021-06-01',
'date_to': '2021-12-31',
})
allocation_2021.action_validate()
allocation_2022 = self.env['hr.leave.allocation'].create({
'name': 'Annual Time Off 2022',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_2.id,
'number_of_days': 20,
'state': 'confirm',
'date_from': '2022-01-01',
'date_to': '2022-12-31',
})
allocation_2022.action_validate()
# Leave taken in 2021
leave_2021 = self.env['hr.leave'].with_user(self.user_employee_id).create({
'name': 'Holiday Request',
'employee_id': self.employee_emp.id,
'holiday_status_id': self.holidays_type_2.id,
'request_date_from': datetime(2021, 8, 9),
'request_date_to': datetime(2021, 8, 13),
})
leave_2021.with_user(self.user_hrmanager_id).action_approve()
# The holidays count only takes into account the valid allocations at that date
self._check_holidays_count(
self.holidays_type_2.get_allocation_data(self.employee_emp, target_date=date(2021, 12, 1))[self.employee_emp][0][1],
ml=10, lt=5, rl=5, vrl=5, vlt=5,
)
# Days remaining before the allocation ends is equal to 1 because there is only one day remaining in the allocation based on its validity
self.assertEqual(
self.holidays_type_2.get_allocation_data(self.employee_emp, target_date=date(2021, 12, 31))[self.employee_emp][0][1]['closest_allocation_duration'],
1,
"Only one day should remain before the allocation expires"
)
leave_2022 = self.env['hr.leave'].with_user(self.user_employee_id).create({
'name': 'Holiday Request',
'employee_id': self.employee_emp.id,
'holiday_status_id': self.holidays_type_2.id,
'request_date_from': datetime(2022, 8, 9),
'request_date_to': datetime(2022, 8, 13),
})
leave_2022.with_user(self.user_hrmanager_id).action_approve()
# The holidays count in 2022 is not affected by the first leave taken in 2021
self._check_holidays_count(
self.holidays_type_2.get_allocation_data(self.employee_emp)[self.employee_emp][0][1],
ml=20, lt=4, rl=16, vrl=16, vlt=4,
)
# The holidays count in 2021 is not affected by the leave taken in 2022
self._check_holidays_count(
self.holidays_type_2.get_allocation_data(self.employee_emp, target_date=date(2021, 12, 1))[self.employee_emp][0][1],
ml=10, lt=5, rl=5, vrl=5, vlt=5,
)
def test_cancel_leave(self):
with freeze_time('2020-09-15'):
self.env['hr.leave.allocation'].create({
'name': 'Annual Time Off',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_4.id,
'number_of_days': 20,
'state': 'confirm',
'date_from': '2020-01-01',
'date_to': '2020-12-31',
})
leave = self.env['hr.leave'].with_user(self.user_employee_id).create({
'name': 'Holiday Request',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_4.id,
'request_date_from': '2020-09-21',
'request_date_to': '2020-09-23',
})
# A meeting is only created once the leave is validated
self.assertFalse(leave.meeting_id)
leave.with_user(self.user_hrmanager_id).action_approve()
self.assertFalse(leave.meeting_id)
# A meeting is created in the user's calendar when a leave is validated
leave.with_user(self.user_hrmanager_id).action_validate()
self.assertTrue(leave.meeting_id.active)
# The meeting is archived when the leave is cancelled
leave.with_user(self.user_employee_id)._action_user_cancel('Cancel leave')
self.assertFalse(leave.meeting_id.active)
def test_create_support_document_in_the_past(self):
with freeze_time('2022-10-19'):
self.env['hr.leave'].with_user(self.user_employee_id).create({
'name': 'Holiday Request',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_support_document.id,
'request_date_from': '2022-10-17',
'request_date_to': '2022-10-17',
'supported_attachment_ids': [(6, 0, [])], # Sent by webclient
})
def test_prevent_misplacement_of_allocations_without_end_date(self):
"""
The objective is to check that it is not possible to place leaves
for which the interval does not correspond to the interval of allocations.
"""
leave_type_A = self.env['hr.leave.type'].with_user(self.user_hrmanager_id).with_context(tracking_disable=True).create({
'name': 'Type A',
'requires_allocation': 'yes',
'employee_requests': 'yes',
'leave_validation_type': 'hr',
})
# Create allocations with no end date
allocations = self.env['hr.leave.allocation'].create([
{
'name': 'Type A march 1 day without date to',
'employee_id': self.employee_emp_id,
'holiday_status_id': leave_type_A.id,
'number_of_days': 1,
'state': 'confirm',
'date_from': '2023-01-03',
},
{
'name': 'Type A april 5 day without date to',
'employee_id': self.employee_emp_id,
'holiday_status_id': leave_type_A.id,
'number_of_days': 5,
'state': 'confirm',
'date_from': '2023-04-01',
},
])
allocations.action_validate()
trigger_error_leave = {
'name': 'Holiday Request',
'employee_id': self.employee_emp_id,
'holiday_status_id': leave_type_A.id,
'request_date_from': '2023-03-14',
'request_date_to': '2023-03-16',
}
with self.assertRaises(ValidationError):
self.env['hr.leave'].with_user(self.user_employee_id).create(trigger_error_leave)
@freeze_time('2022-06-13 10:00:00')
def test_current_leave_status(self):
types = ('no_validation', 'manager', 'hr', 'both')
employee = self.employee_emp
def run_validation_flow(leave_validation_type):
LeaveType = self.env['hr.leave.type'].with_user(self.user_hrmanager_id)
leave_type = LeaveType.with_context(tracking_disable=True).create({
'name': leave_validation_type.capitalize(),
'leave_validation_type': leave_validation_type,
'requires_allocation': 'no',
'responsible_ids': [Command.link(self.env.ref('base.user_admin').id)],
})
current_leave = self.env['hr.leave'].with_user(self.user_employee_id).create({
'name': 'Holiday Request',
'employee_id': employee.id,
'holiday_status_id': leave_type.id,
'date_from': datetime.today() - timedelta(days=1),
'date_to': datetime.today() + timedelta(days=1),
})
if leave_validation_type in ('manager', 'both'):
self.assertFalse(employee.is_absent)
self.assertFalse(employee.current_leave_id)
self.assertEqual(employee.filtered_domain([('is_absent', '=', False)]), employee)
self.assertFalse(employee.filtered_domain([('is_absent', '=', True)]))
current_leave.with_user(self.user_hruser_id).action_approve()
if leave_validation_type in ('hr', 'both'):
self.assertFalse(employee.is_absent)
self.assertFalse(employee.current_leave_id)
self.assertEqual(employee.filtered_domain([('is_absent', '=', False)]), employee)
self.assertFalse(employee.filtered_domain([('is_absent', '=', True)]))
current_leave.with_user(self.user_hrmanager_id).action_validate()
self.assertTrue(employee.is_absent)
self.assertEqual(employee.current_leave_id, current_leave.holiday_status_id)
self.assertFalse(employee.filtered_domain([('is_absent', '=', False)]))
self.assertEqual(employee.filtered_domain([('is_absent', '=', True)]), employee)
raise RuntimeError()
for leave_validation_type in types:
with self.assertRaises(RuntimeError), self.env.cr.savepoint():
run_validation_flow(leave_validation_type)
@freeze_time('2019-11-01')
def test_duration_display_global_leave(self):
""" Ensure duration_display stays in sync with leave duration. """
employee = self.employee_emp
calendar = employee.resource_calendar_id
sick_leave_type = self.env['hr.leave.type'].create({
'name': 'Sick Leave (days)',
'request_unit': 'day',
'leave_validation_type': 'hr',
})
sick_leave = self.env['hr.leave'].create({
'name': 'Sick 3 days',
'employee_id': employee.id,
'holiday_status_id': sick_leave_type.id,
'request_date_from': '2019-12-23',
'request_date_to': '2019-12-25',
})
comp_leave_type = self.env['hr.leave.type'].create({
'name': 'OT Compensation (hours)',
'request_unit': 'hour',
'leave_validation_type': 'manager',
})
comp_leave = self.env['hr.leave'].create({
'name': 'OT Comp (4 hours)',
'employee_id': employee.id,
'holiday_status_id': comp_leave_type.id,
'request_unit_hours': True,
'request_date_from': '2019-12-26',
'request_date_to': '2019-12-26',
'request_hour_from': 8,
'request_hour_to': 12,
})
self.assertEqual(sick_leave.duration_display, '3 days')
self.assertEqual(comp_leave.duration_display, '4:00 hours')
calendar.global_leave_ids = [(0, 0, {
'name': 'Winter Holidays',
'date_from': '2019-12-25 00:00:00',
'date_to': '2019-12-26 23:59:59',
'time_type': 'leave',
})]
msg = "hr_holidays: duration_display should update after adding an overlapping holiday"
self.assertEqual(sick_leave.duration_display, '2 days', msg)
self.assertEqual(comp_leave.duration_display, '0:00 hours', msg)
def test_duration_display_public_leave_include(self):
"""
The purpose is to test whether the duration_display
computation considers public holidays when the
`include_public_holidays_in_duration` is set to True.
"""
employee = self.employee_emp
calendar = employee.resource_calendar_id
sick_leave_type = self.env['hr.leave.type'].create({
'name': 'Sick Leave (days)',
'request_unit': 'day',
'leave_validation_type': 'hr',
})
sick_leave = self.env['hr.leave'].create({
'name': 'Sick 3 days',
'employee_id': employee.id,
'holiday_status_id': sick_leave_type.id,
'request_date_from': '2021-11-15',
'request_date_to': '2021-11-17',
})
self.assertEqual(sick_leave.duration_display, '3 days')
calendar.global_leave_ids = [(0, 0, {
'name': 'Autumn Holidays',
'date_from': '2021-11-16 00:00:00',
'date_to': '2021-11-16 23:59:59',
'time_type': 'leave',
})]
self.assertEqual(sick_leave.duration_display, '2 days', "hr_holidays: duration_display should not count public holiday")
sick_leave_type.include_public_holidays_in_duration = True
sick_leave.unlink()
sick_leave = self.env['hr.leave'].create({
'name': 'Sick 3 days',
'employee_id': employee.id,
'holiday_status_id': sick_leave_type.id,
'request_date_from': '2021-11-15',
'request_date_to': '2021-11-17',
})
self.assertEqual(sick_leave.duration_display, '3 days', "hr_holidays: duration_display should not update after adding an overlapping holiday")
@freeze_time('2024-01-18')
def test_undefined_working_hours(self):
""" Ensure time-off can also be allocated without ResourceCalendar. """
employee = self.employee_emp
# set a flexible working schedule
calendar = self.env['resource.calendar'].create({
'name': 'Flexible 40h/week',
'hours_per_day': 8.0,
'flexible_hours': True,
})
employee.resource_calendar_id = calendar
allocation = self.env['hr.leave.allocation'].create({
'name': 'Annual Time Off',
'employee_id': employee.id,
'holiday_status_id': self.holidays_type_4.id,
'number_of_days': 20,
'state': 'confirm',
'date_from': '2024-01-01',
'date_to': '2024-12-31',
})
allocation.action_validate()
self.env['hr.leave'].with_user(self.user_employee_id).create({
'name': 'Holiday Request',
'employee_id': employee.id,
'holiday_status_id': self.holidays_type_4.id,
'request_date_from': '2024-01-23',
'request_date_to': '2024-01-27',
})
holiday_status = self.holidays_type_4.with_user(self.user_employee_id)
self._check_holidays_status(holiday_status, employee, 20.0, 0.0, 20.0, 16.0)
def test_default_request_date_timezone(self):
"""
The purpose is to test whether the timezone is
taken into account when requesting a leave.
"""
self.user_employee.tz = 'Asia/Hong_Kong' # UTC +08:00
context = {
# `date_from/to` in UTC to simulate client values
'default_date_from': '2024-03-27 23:00:00',
'default_date_to': '2024-03-28 08:00:00',
}
leave_form = Form(self.env['hr.leave'].with_user(self.user_employee).with_context(context))
leave_form.holiday_status_id = self.holidays_type_2
leave = leave_form.save()
self.assertEqual(leave.number_of_days, 1.0)
def test_filter_time_off_type_multiple_employees(self):
""" This test mimics the behavior of creating time off for multiple employees.
We check that the time off types that the user can select are correct.
In this example, we use a time off type that requires allocations.
Only the current user has an allocation for the time off type.
This time off type should not appear when multiple employees are select (user included or not).
"""
self.assertFalse(self.env['hr.leave.allocation'].search([['holiday_status_id', '=', self.holidays_type_2.id]]))
self.env.user.employee_id = self.employee_hruser_id
allocation = self.env['hr.leave.allocation'].create({
'employee_id': self.employee_hruser_id,
'holiday_status_id': self.holidays_type_2.id,
'allocation_type': 'regular'
})
allocation.action_validate()
self.assertEqual(allocation.state, 'validate')
search_domain = ['|',
['requires_allocation', '=', 'no'],
'&',
['has_valid_allocation', '=', True],
'&',
['max_leaves', '>', '0'],
'|',
['allows_negative', '=', True],
'&',
['virtual_remaining_leaves', '>', 0],
['allows_negative', '=', False]]
search_result = self.env['hr.leave.type'].with_context(employee_id=False).name_search(args=search_domain)
self.assertFalse(self.holidays_type_2.id in [alloc_id for (alloc_id, _) in search_result])
def test_holiday_type_allocation_requirement_edit(self):
# Does not raise an error since no leave of this type exists yet
self.holidays_type_2.requires_allocation = 'no'
self.assertEqual(self.holidays_type_2.requires_allocation, 'no', 'Allocations should no longer be required')
self.env['hr.leave'].create({
'name': 'Test leave',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_2.id,
'date_from': (datetime.today() - relativedelta(days=1)),
'date_to': datetime.today(),
'number_of_days': 1,
})
with self.assertRaises(UserError):
self.holidays_type_2.requires_allocation = 'yes'