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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
|
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import date, datetime, timedelta
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 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'})
]
})
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 Time Off',
'date_from': date(2022, 3, 7),
'date_to': date(2022, 3, 7),
})
cls.calendar_leave = cls.env['resource.calendar.leaves'].create({
'name': 'Global Time Off',
'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 Time Off',
'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 Time Off',
'date_from': date(2022, 3, 7),
'date_to': date(2022, 3, 7),
})
def test_leave_on_calendar_leave(self):
self.env['resource.calendar.leaves'].create({
'name': 'Correct Time Off',
'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 Time Off',
'date_from': date(2022, 3, 8),
'date_to': date(2022, 3, 8),
})
with self.assertRaises(ValidationError):
self.env['resource.calendar.leaves'].create({
'name': 'Wrong Time Off',
'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
def test_global_leave_number_of_days_with_new(self):
"""
Check that leaves stored in memory (and not in the database)
take into account global leaves.
"""
global_leave = self.env['resource.calendar.leaves'].create({
'name': 'Global Time Off',
'date_from': datetime(2024, 1, 3, 6, 0, 0),
'date_to': datetime(2024, 1, 3, 19, 0, 0),
'calendar_id': self.calendar_1.id,
})
leave_type = self.env['hr.leave.type'].create({
'name': 'Paid Time Off',
'time_type': 'leave',
'requires_allocation': 'no',
})
self.employee_emp.resource_calendar_id = self.calendar_1.id
leave = self.env['hr.leave'].create({
'name': 'Test new leave',
'employee_id': self.employee_emp.id,
'holiday_status_id': leave_type.id,
'request_date_from': global_leave.date_from,
'request_date_to': global_leave.date_to,
})
self.assertEqual(leave.number_of_days, 0, 'It is a global leave')
leave = self.env['hr.leave'].new({
'name': 'Test new leave',
'employee_id': self.employee_emp.id,
'holiday_status_id': leave_type.id,
'request_date_from': global_leave.date_from,
'request_date_to': global_leave.date_to,
})
self.assertEqual(leave.number_of_days, 0, 'It is a global leave')
leave = self.env['hr.leave'].new({
'name': 'Test new leave',
'employee_id': self.employee_emp.id,
'holiday_status_id': leave_type.id,
'request_date_from': global_leave.date_from - timedelta(days=1),
'request_date_to': global_leave.date_to + timedelta(days=1),
})
self.assertEqual(leave.number_of_days, 2, 'There is a global leave')
|