Files
odoo_source/addons/hr_holidays/tests/test_leave_requests.py
T
Philippe Wauthy fdee8ab152 [IMP] hr_holidays: make duration field read only
In hr_holidays, the duration field is editable but doesn't bring any added value.
The field is errorprone and not editable if you are not HR Officer. It should be the same in every case.

The duration field should be read only on the dashboard and time off creation screens.

task-2901951

closes odoo/odoo#95534

Related: odoo/enterprise#29352
Signed-off-by: Kevin Baptiste <kba@odoo.com>
2022-07-12 08:39:58 +02:00

803 lines
38 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import datetime, date
import time
from dateutil.relativedelta import relativedelta
from freezegun import freeze_time
from pytz import timezone, UTC
from odoo import fields
from odoo.exceptions import ValidationError
from odoo.tools import mute_logger
from odoo.tests.common import Form
from odoo.tests import tagged
from odoo.addons.hr_holidays.tests.common import TestHrHolidaysCommon
@tagged('leave_requests')
class TestLeaveRequests(TestHrHolidaysCommon):
def _check_holidays_status(self, 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')
@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.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')
@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,
'date_from': (datetime.today() - relativedelta(days=1)),
'date_to': datetime.today(),
'number_of_days': 1,
})
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,
'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_limited_type_no_days(self):
""" Employee creates a leave request in a limited category but has not enough days left """
with self.assertRaises(ValidationError):
self.env['hr.leave'].with_user(self.user_employee_id).create({
'name': 'Hol22',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_2.id,
'date_from': (datetime.today() + relativedelta(days=1)).strftime('%Y-%m-%d %H:%M'),
'date_to': (datetime.today() + relativedelta(days=2)),
'number_of_days': 1,
})
@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'):
aloc1_user_group = 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'),
})
aloc1_user_group.action_validate()
holiday_status = self.holidays_type_2.with_user(self.user_employee_id)
self._check_holidays_status(holiday_status, 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,
'date_from': (datetime.today() - relativedelta(days=2)),
'date_to': datetime.today(),
'number_of_days': 2,
})
holiday_status.invalidate_model()
self._check_holidays_status(holiday_status, 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, 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 """
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,
'state': '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,
'date_from': fields.Datetime.from_string('2017-03-03 06:00:00'),
'date_to': fields.Datetime.from_string('2017-03-11 19:00:00'),
'number_of_days': 1,
})
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_accrual_validity_time_not_valid(self):
""" Employee ask leave when there's no valid allocation """
with self.assertRaises(ValidationError):
self.env['hr.leave'].with_user(self.user_employee).create({
'name': 'Sick Time Off',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_2.id,
'date_from': fields.Datetime.from_string('2017-07-03 06:00:00'),
'date_to': fields.Datetime.from_string('2017-07-11 19:00:00'),
'number_of_days': 1,
})
@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_form = Form(self.env['hr.leave'].with_user(self.user_hrmanager), view='hr_holidays.hr_leave_view_form_manager')
leave_form.holiday_type = 'department'
leave_form.department_id = self.hr_dept
leave_form.holiday_status_id = self.holidays_type_1
leave_form.request_date_from = date(2019, 5, 6)
leave_form.request_date_to = date(2019, 5, 6)
leave = leave_form.save()
leave.action_approve()
member_ids = self.hr_dept.member_ids.ids
self.assertEqual(self.env['hr.leave'].search_count([('employee_id', 'in', member_ids)]), len(member_ids), "Leave 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.name = 'New Allocation Request'
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 = allocation_form.save()
@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,
'date_from': (fields.Datetime.now() - relativedelta(days=1)),
'date_to': fields.Datetime.now() + relativedelta(days=1),
'number_of_days': 2,
})
(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 = 'NZ' # 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 = 'NZ' # 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,
'holiday_type': 'company',
'mode_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 = 'NZ' # GMT+12
company = self.env['res.company'].create({'name': "Hergé"})
employee = self.env['hr.employee'].create({'name': "Remi", 'company_id': company.id})
leave_form = Form(self.env['hr.leave'], view='hr_holidays.hr_leave_view_form_manager')
leave_form.holiday_type = 'company'
leave_form.mode_company_id = company
leave_form.holiday_status_id = self.holidays_type_1
leave_form.request_date_from = date(2019, 5, 6)
leave_form.request_date_to = date(2019, 5, 6)
# TODO: The test is wrong by modifying `date_from` and `date_to`, which are invisible
# It should edit only `request_date_from` and `request_date_to` instead
# And there is really a bug. Using the web client, when you put your PC in Auckland timezone,
# and the admin preferences in Auckland Timezone
# and create a time off for the current day, the computation is completely wrong
# and compute the date to before the date from *-)
# For instance, for a time-off from 06/16/2022 to 06/16/2022 (1 day) it computes
# 06/16/2022 08:00:00 as date_from and 06/15/2022 17:00:00 as date_to
# Bug reported to the rd-fun-vidange channel to the dev who introduced the bug
# https://discord.com/channels/678381219515465750/687337760452902925/986918361768263710
leave_form._view['modifiers']['date_from']['invisible'] = False
leave_form._view['modifiers']['date_to']['invisible'] = False
leave_form.date_from = datetime(2019, 5, 6, 0, 0, 0)
leave_form.date_to = datetime(2019, 5, 6, 23, 59, 59)
leave = leave_form.save()
leave.state = 'confirm'
leave.action_validate()
employee_leave = self.env['hr.leave'].search([('employee_id', '=', employee.id)])
self.assertEqual(
employee_leave.request_date_from, date(2019, 5, 5),
"Timezone should be be adapted on the employee leave"
)
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
def test_timezone_department_leave_request(self):
""" Create a leave request for a department in another timezone """
company = self.env['res.company'].create({'name': "Hergé"})
company.resource_calendar_id.tz = 'NZ' # GMT+12
department = self.env['hr.department'].create({'name': "Museum", 'company_id': company.id})
leave = self.env['hr.leave'].new({
'employee_id': self.employee_emp.id,
'holiday_status_id': self.holidays_type_1.id,
'request_unit_hours': True,
'holiday_type': 'department',
'department_id': department.id,
'request_date_from': date(2019, 5, 6),
'request_date_to': date(2019, 5, 6),
'request_hour_from': '8', # 8:00 AM in the department's timezone
'request_hour_to': '17', # 5:00 PM in the department'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")
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 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 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 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 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',
})
allocation = 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'),
})
allocation.action_validate()
leave1 = self.env['hr.leave'].create({
'name': 'Holiday 1 week',
'employee_id': employee.id,
'holiday_status_id': leave_type.id,
'date_from': fields.Datetime.from_string('2019-12-23 06:00:00'),
'date_to': fields.Datetime.from_string('2019-12-27 20:00:00'),
'number_of_days': 5,
})
self.assertEqual(leave1.number_of_hours_display, 38)
leave1.action_approve()
self.assertEqual(leave1.number_of_hours_display, 38)
leave1.action_validate()
self.assertEqual(leave1.number_of_hours_display, 38)
leave2 = self.env['hr.leave'].create({
'name': 'Holiday 1 Day',
'employee_id': employee.id,
'holiday_status_id': leave_type.id,
'date_from': fields.Datetime.from_string('2019-12-30 06:00:00'),
'date_to': fields.Datetime.from_string('2019-12-30 13:00:00'),
'number_of_days': 1,
})
self.assertEqual(leave2.number_of_hours_display, 4)
leave2.action_approve()
self.assertEqual(leave2.number_of_hours_display, 4)
leave2.action_validate()
self.assertEqual(leave2.number_of_hours_display, 4)
def test_number_of_hours_display_global_leave(self):
# Check that the field number_of_hours_display
# 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 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'})
],
'global_leave_ids': [(0, 0, {
'name': 'Christmas Leave',
'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,
'date_from': fields.Datetime.from_string('2019-12-23 06:00:00'),
'date_to': fields.Datetime.from_string('2019-12-27 20:00:00'),
'number_of_days': 5,
})
self.assertEqual(leave1.number_of_hours_display, 24)
leave1.action_approve()
self.assertEqual(leave1.number_of_hours_display, 24)
leave1.action_validate()
self.assertEqual(leave1.number_of_hours_display, 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)
# Mimic what is done by the calendar widget when clicking on a day. It
# will take the local datetime from 0:00 to 23:59
values = {
'date_from': local_date_from,
'date_to': local_date_to, # note that this can be the next day in UTC
}
values.update(self.env['hr.leave'].with_user(self.user_employee_id)._default_get_request_parameters(values))
# Dates should be local to the user
self.assertEqual(values['request_date_from'], local_date_from.date())
self.assertEqual(values['request_date_to'], local_date_to.date())
values.update({
'name': 'Test',
'employee_id': self.employee_emp_id,
'holiday_status_id': self.holidays_type_1.id,
})
leave = self.env['hr.leave'].with_user(self.user_employee_id).new(values)
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', 'US/Pacific', '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 = datetime(2020, 1, 1, 0, 0, 0)
local_date_to = datetime(2020, 1, 1, 23, 59, 59)
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 = datetime(2020, 1, 1, 0, 0, 0)
local_date_to = datetime(2020, 1, 8, 23, 59, 59)
for tz in timezones_to_test:
self._test_leave_with_tz(tz, local_date_from, local_date_to, 6)#TODO JUD check why this fails
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,
'date_from': '2021-09-01',
'date_to': '2021-09-02',
'number_of_days': 1,
})
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,
'date_from': '2020-09-01',
'date_to': '2020-09-02',
'number_of_days': 1,
})
def test_no_days_expired(self):
# First expired allocation
allocation1 = 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',
})
allocation2 = 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',
})
allocation1.action_validate()
allocation2.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,
'date_from': '2021-09-06',
'date_to': '2021-09-10',
'number_of_days': 5,
})
# 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,
'date_from': '2021-09-06',
'date_to': '2021-09-08',
'number_of_days': 3,
})
def test_company_leaves(self):
# First expired allocation
allocation = self.env['hr.leave.allocation'].create({
'name': 'Allocation',
'holiday_type': 'company',
'mode_company_id': self.env.company.id,
'holiday_status_id': self.holidays_type_1.id,
'number_of_days': 20,
'state': 'confirm',
'date_from': '2021-01-01',
})
allocation.action_validate()
req1_form = Form(self.env['hr.leave'].sudo())
req1_form.employee_ids.add(self.employee_emp)
req1_form.employee_ids.add(self.employee_hrmanager)
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_display, 3)
req1_form.save().action_approve()
req2_form = Form(self.env['hr.leave'].sudo())
req2_form.employee_ids.add(self.employee_hruser)
req2_form.holiday_status_id = self.holidays_type_1
req2_form.request_date_from = fields.Date.to_date('2021-12-06')
req2_form.request_date_to = fields.Date.to_date('2021-12-08')
self.assertEqual(req2_form.number_of_days_display, 3)
def test_leave_with_public_holiday_other_company(self):
other_company = self.env['res.company'].create({
'name': 'Test Company',
})
# 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',
'holiday_type': 'employee',
'employee_id': self.employee_emp.id,
'holiday_status_id': self.holidays_type_1.id,
'date_from': datetime(2022, 3, 11),
'date_to': datetime(2022, 3, 11, 23, 59, 59),
})
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',
}
allocation1 = self.env['hr.leave.allocation'].create(allocation_vals)
allocation2 = self.env['hr.leave.allocation'].create(allocation_vals)
allocation1.action_validate()
allocation2.action_validate()
# Neither allocation has enough days
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,
'date_from': '2022-01-01',
'date_to': '2022-01-15',
'number_of_days': 10,
})
allocation_vals.update({'number_of_days': 10})
allocation3 = self.env['hr.leave.allocation'].create(allocation_vals)
allocation3.action_validate()
# The 3rd allocation has enough days, so it should be picked
holiday = 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,
'date_from': '2022-01-01',
'date_to': '2022-01-15',
'number_of_days': 10,
})
holiday.sudo().action_validate()
self.assertEqual(allocation1.leaves_taken, 0.0, 'As this allocation does not have enough days, it should not be affected')
self.assertEqual(allocation2.leaves_taken, 0.0, 'As this allocation does not have enough days, it should not be affected')
self.assertEqual(allocation3.leaves_taken, 10.0, 'As this allocation has enough days, the leave days should be taken')
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_vals.update({'number_of_days': 1})
allocation_1day = Allocation.create(allocation_vals)
allocations = (allocation_4days + allocation_1day)
allocations.action_validate()
leave_vals.update({
'date_from': '2022-01-03 00:00:00',
'date_to': '2022-01-06 23:59:59',
'number_of_days': 4,
})
leave_draft = Leave.create(leave_vals)
leave_draft.action_refuse()
leave_vals.update({
'date_from': '2022-01-03 00:00:00',
'date_to': '2022-01-06 23:59:59',
'number_of_days': 4,
})
leave_4days = Leave.create(leave_vals)
leave_vals.update({
'date_from': '2022-01-07 00:00:00',
'date_to': '2022-01-07 23:59:59',
'number_of_days': 1,
})
leave_1day = Leave.create(leave_vals)
leaves = (leave_4days + leave_1day)
leaves.action_approve()
self.assertEqual(allocation_4days.leaves_taken, leave_4days['number_of_%ss_display' % unit], 'As 4 days were available in this allocation, they should have been taken')
self.assertEqual(allocation_1day.leaves_taken, leave_1day['number_of_%ss_display' % 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,
'date_from': '2021-12-06 00:00:00',
'date_to': '2021-12-10 23:59:59',
},
{
'name': 'Holiday Request',
'employee_id': self.employee_hruser_id,
'holiday_status_id': self.holidays_type_1.id,
'date_from': '2021-12-06 00:00:00',
'date_to': '2021-12-10 23:59:59',
}
])
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,
'date_from': '2021-12-06 00:00:00',
'date_to': '2021-12-10 23:59:59',
})
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,
'date_from': '2021-12-13 00:00:00',
'date_to': '2021-12-17 23:59:59',
})
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, 2)
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,
'date_from': '2021-12-06 00:00:00',
'date_to': '2021-12-10 23:59:59',
})
self.assertEqual(time_off.number_of_days, 4)
global_time_off.unlink()
self.assertEqual(time_off.number_of_days, 3)
def test_time_off_auto_cancel(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,
'date_from': '2021-11-15 00:00:00',
'date_to': '2021-11-19 23:59:59',
})
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.active, False)