[FIX]l10n_fr_hr_holidays:fix bug in part-time employee duleaves duration calculation

This commit is contained in:
2026-06-25 18:55:22 +02:00
parent 2f73c1b3a7
commit ecba73e832
5 changed files with 352 additions and 26 deletions

View File

@@ -15,7 +15,13 @@ class TestFrenchLeaves(TransactionCase):
'country_id': country_fr.id,
})
cls.employee = cls.env['hr.employee'].create({
cls.base_calendar = cls.env['resource.calendar'].create({
'name': 'default calendar',
'company_id': cls.company.id,
})
cls.company.resource_calendar_id = cls.base_calendar
cls.employee = cls.env['hr.employee'].with_company(cls.company).create({
'name': 'Camille',
'gender': 'other',
'birthday': '1973-03-29',
@@ -32,14 +38,29 @@ class TestFrenchLeaves(TransactionCase):
'l10n_fr_reference_leave_type': cls.time_off_type.id,
})
cls.base_calendar = cls.env['resource.calendar'].create({
'name': 'default calendar',
})
def _set_employee_calendar(self, calendar):
"""Set employee resource calendar and update hr.employee.calendar
planning record if hr_employee_calendar_planning is installed.
The planning module overrides resource_calendar_id on hr.leave via
_compute_resource_calendar_id, so we must keep the planning record
in sync with the test's intended employee calendar.
"""
self.employee.resource_calendar_id = calendar
if 'hr.employee.calendar' in self.env:
planning = self.env['hr.employee.calendar'].search(
[('employee_id', '=', self.employee.id)], limit=1)
if planning:
planning.calendar_id = calendar
else:
self.env['hr.employee.calendar'].create({
'employee_id': self.employee.id,
'calendar_id': calendar.id,
})
def test_no_differences(self):
# Base case that should not have a different behaviour
self.company.resource_calendar_id = self.base_calendar
self.employee.resource_calendar_id = self.base_calendar
self._set_employee_calendar(self.base_calendar)
leave = self.env['hr.leave'].create({
'name': 'Test',
@@ -57,6 +78,7 @@ class TestFrenchLeaves(TransactionCase):
def test_end_of_week(self):
employee_calendar = self.env['resource.calendar'].create({
'name': 'Employee Calendar',
'company_id': self.company.id,
'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'}),
@@ -67,7 +89,7 @@ class TestFrenchLeaves(TransactionCase):
],
})
self.company.resource_calendar_id = self.base_calendar
self.employee.resource_calendar_id = employee_calendar
self._set_employee_calendar(employee_calendar)
leave = self.env['hr.leave'].create({
'name': 'Test',
@@ -85,6 +107,7 @@ class TestFrenchLeaves(TransactionCase):
def test_start_of_week(self):
employee_calendar = self.env['resource.calendar'].create({
'name': 'Employee Calendar',
'company_id': self.company.id,
'attendance_ids': [
(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'}),
@@ -95,7 +118,7 @@ class TestFrenchLeaves(TransactionCase):
],
})
self.company.resource_calendar_id = self.base_calendar
self.employee.resource_calendar_id = employee_calendar
self._set_employee_calendar(employee_calendar)
leave = self.env['hr.leave'].create({
'name': 'Test',
@@ -106,7 +129,7 @@ class TestFrenchLeaves(TransactionCase):
'employee_company_id': self.company.id,
'resource_calendar_id': self.employee.resource_calendar_id.id,
})
leave._compute_date_from_to()
self.assertEqual(leave.number_of_days, 5, 'The number of days should be equal to 5.')
leave.unlink()
@@ -114,6 +137,7 @@ class TestFrenchLeaves(TransactionCase):
def test_last_day_half(self):
employee_calendar = self.env['resource.calendar'].create({
'name': 'Employee Calendar',
'company_id': self.company.id,
'attendance_ids': [
(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'}),
@@ -124,7 +148,7 @@ class TestFrenchLeaves(TransactionCase):
],
})
self.company.resource_calendar_id = self.base_calendar
self.employee.resource_calendar_id = employee_calendar
self._set_employee_calendar(employee_calendar)
leave = self.env['hr.leave'].create({
'name': 'Test',
@@ -150,6 +174,7 @@ class TestFrenchLeaves(TransactionCase):
def test_full_time_am_day_half(self):
employee_calendar = self.env['resource.calendar'].create({
'name': 'Employee Calendar',
'company_id': self.company.id,
'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'}),
@@ -163,7 +188,7 @@ class TestFrenchLeaves(TransactionCase):
],
})
self.company.resource_calendar_id = self.base_calendar
self.employee.resource_calendar_id = employee_calendar
self._set_employee_calendar(employee_calendar)
leave = self.env['hr.leave'].create({
'name': 'Test',
@@ -184,6 +209,7 @@ class TestFrenchLeaves(TransactionCase):
def test_am_day_half(self):
employee_calendar = self.env['resource.calendar'].create({
'name': 'Employee Calendar',
'company_id': self.company.id,
'attendance_ids': [
(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'}),
@@ -193,7 +219,7 @@ class TestFrenchLeaves(TransactionCase):
],
})
self.company.resource_calendar_id = self.base_calendar
self.employee.resource_calendar_id = employee_calendar
self._set_employee_calendar(employee_calendar)
leave = self.env['hr.leave'].create({
'name': 'Test',
@@ -214,6 +240,7 @@ class TestFrenchLeaves(TransactionCase):
def test_calendar_with_holes(self):
employee_calendar = self.env['resource.calendar'].create({
'name': 'Employee Calendar',
'company_id': self.company.id,
'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'}),
@@ -224,7 +251,7 @@ class TestFrenchLeaves(TransactionCase):
],
})
self.company.resource_calendar_id = self.base_calendar
self.employee.resource_calendar_id = employee_calendar
self._set_employee_calendar(employee_calendar)
leave = self.env['hr.leave'].create({
'name': 'Test',
@@ -242,6 +269,7 @@ class TestFrenchLeaves(TransactionCase):
def test_calendar_end_week_hole(self):
employee_calendar = self.env['resource.calendar'].create({
'name': 'Employee Calendar',
'company_id': self.company.id,
'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'}),
@@ -250,7 +278,7 @@ class TestFrenchLeaves(TransactionCase):
],
})
self.company.resource_calendar_id = self.base_calendar
self.employee.resource_calendar_id = employee_calendar
self._set_employee_calendar(employee_calendar)
leave = self.env['hr.leave'].create({
'name': 'Test',
@@ -268,6 +296,7 @@ class TestFrenchLeaves(TransactionCase):
def test_2_weeks_calendar(self):
company_calendar = self.env['resource.calendar'].create({
'name': 'Company Calendar',
'company_id': self.company.id,
'two_weeks_calendar': True,
'attendance_ids': [
(0, 0, {'week_type': '0', 'name': 'Monday Morning', 'dayofweek': '0', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
@@ -291,6 +320,7 @@ class TestFrenchLeaves(TransactionCase):
})
employee_calendar = self.env['resource.calendar'].create({
'name': 'Employee Calendar',
'company_id': self.company.id,
'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'}),
@@ -301,7 +331,7 @@ class TestFrenchLeaves(TransactionCase):
],
})
self.company.resource_calendar_id = company_calendar
self.employee.resource_calendar_id = employee_calendar
self._set_employee_calendar(employee_calendar)
# Week type 0
leave = self.env['hr.leave'].create({
@@ -351,9 +381,241 @@ class TestFrenchLeaves(TransactionCase):
'employee_id': self.employee.id,
'request_date_from': '2021-09-13',
'request_date_to': '2021-09-22',
'company_id': self.company.id,
'employee_company_id': self.company.id,
'resource_calendar_id': self.employee.resource_calendar_id.id,
})
leave._compute_date_from_to()
self.assertEqual(leave.number_of_days, 8, 'The number of days should be equal to 3.')
leave.unlink()
def test_part_time_different_hours(self):
# Regression test: when the employee's working hours differ from the
# company's on the boundary day, the hourly-ratio computation used to
# return a fractional number of days (e.g. 12.86 instead of 13).
# French legal rule: paid leaves are counted in company working days
# (jours ouvrables) as full days.
# Company works 6 days/week (Mon-Sat), 9-12 + 13-17 = 7h/day.
company_calendar = self.env['resource.calendar'].create({
'name': 'Company Calendar 6d/week',
'company_id': self.company.id,
'attendance_ids': [
(0, 0, {'name': 'Monday Morning', 'dayofweek': '0', 'hour_from': 9, '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': 9, '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': 9, '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': 9, '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': 9, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Friday Afternoon', 'dayofweek': '4', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'}),
(0, 0, {'name': 'Saturday Morning', 'dayofweek': '5', 'hour_from': 9, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Saturday Afternoon', 'dayofweek': '5', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'}),
],
})
# Employee works Mon, Tue, Thu (part-time), 8-12 + 13-16 = 7h/day but
# with shifted hours vs the company, so the boundary day is fractional
# under the old hourly-ratio computation.
employee_calendar = self.env['resource.calendar'].create({
'name': 'Employee Calendar Part Time',
'company_id': self.company.id,
'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': 16, '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': 16, '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': 16, 'day_period': 'afternoon'}),
],
})
self.company.resource_calendar_id = company_calendar
self._set_employee_calendar(employee_calendar)
self.employee.tz = 'Europe/Paris'
# Leave from 12/01/2026 (Monday) to 26/01/2026 (Monday) inclusive.
# Period: 15 calendar days, 2 Sundays -> 13 company working days.
# Dates must be in the past: default_get sets date_to to today if
# request_date_to is not in defaults, and the SQL constraint
# CHECK(date_from <= date_to) fails if date_from > today during
# the intermediate flush in _compute_date_from_to.
leave = self.env['hr.leave'].create({
'name': 'Test part-time bug',
'holiday_status_id': self.time_off_type.id,
'employee_id': self.employee.id,
'request_date_from': '2026-01-12',
'request_date_to': '2026-01-26',
'employee_company_id': self.company.id,
'resource_calendar_id': self.employee.resource_calendar_id.id,
})
leave._compute_date_from_to()
self.assertEqual(leave.number_of_days, 13.0,
'The number of days should be 13 (jours ouvrables), not 12.86.')
leave.unlink()
def test_part_time_half_day_different_hours(self):
# Regression test for French part-time half-day leave counting.
# Employee works: Mon, Tue, Wed(AM only), Thu, Fri(AM only).
# Company works 6 days/week (Mon-Sat), 9-17h.
# French rule: count company working days (jours ouvrables) from
# first day of absence to return day (exclusive).
company_calendar = self.env['resource.calendar'].create({
'name': 'Company Calendar 6d/week',
'company_id': self.company.id,
'attendance_ids': [
(0, 0, {'name': 'Monday Morning', 'dayofweek': '0', 'hour_from': 9, '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': 9, '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': 9, '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': 9, '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': 9, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Friday Afternoon', 'dayofweek': '4', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'}),
(0, 0, {'name': 'Saturday Morning', 'dayofweek': '5', 'hour_from': 9, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Saturday Afternoon', 'dayofweek': '5', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'}),
],
})
employee_calendar = self.env['resource.calendar'].create({
'name': 'Employee Calendar Part Time',
'company_id': self.company.id,
'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': 16, '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': 16, 'day_period': 'afternoon'}),
(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': 'Thursday Afternoon', 'dayofweek': '3', 'hour_from': 13, 'hour_to': 16, 'day_period': 'afternoon'}),
(0, 0, {'name': 'Friday Morning', 'dayofweek': '4', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
],
})
self.company.resource_calendar_id = company_calendar
self._set_employee_calendar(employee_calendar)
self.employee.tz = 'Europe/Paris'
# Case 1: Wednesday AM half-day.
# Employee doesn't work Wed PM -> return = Thu.
# Company working days from Wed to Thu (exclusive) = Wed = 1 day.
leave = self.env['hr.leave'].create({
'name': 'Test Wed AM',
'holiday_status_id': self.time_off_type.id,
'employee_id': self.employee.id,
'request_date_from': '2021-09-08',
'request_date_to': '2021-09-08',
'request_unit_half': True,
'request_date_from_period': 'am',
'employee_company_id': self.company.id,
'resource_calendar_id': self.employee.resource_calendar_id.id,
})
leave._compute_date_from_to()
self.assertEqual(leave.number_of_days, 1.0,
'Wed AM half-day should count as 1 jour ouvrable.')
leave.unlink()
# Case 2: Thursday + Friday full days.
# Return = Monday. Company working days: Thu, Fri, Sat = 3 days.
leave = self.env['hr.leave'].create({
'name': 'Test Thu+Fri',
'holiday_status_id': self.time_off_type.id,
'employee_id': self.employee.id,
'request_date_from': '2021-09-09',
'request_date_to': '2021-09-10',
'employee_company_id': self.company.id,
'resource_calendar_id': self.employee.resource_calendar_id.id,
})
leave._compute_date_from_to()
self.assertEqual(leave.number_of_days, 3.0,
'Thu+Fri full days should count as 3 jours ouvrables (Thu, Fri, Sat).')
leave.unlink()
# Case 3: Friday AM half-day.
# Employee doesn't work Fri PM -> return = Monday.
# Company working days from Fri to Mon (exclusive) = Fri, Sat = 2 days.
leave = self.env['hr.leave'].create({
'name': 'Test Fri AM',
'holiday_status_id': self.time_off_type.id,
'employee_id': self.employee.id,
'request_date_from': '2021-09-10',
'request_date_to': '2021-09-10',
'request_unit_half': True,
'request_date_from_period': 'am',
'employee_company_id': self.company.id,
'resource_calendar_id': self.employee.resource_calendar_id.id,
})
leave._compute_date_from_to()
self.assertEqual(leave.number_of_days, 2.0,
'Fri AM half-day should count as 2 jours ouvrables (Fri, Sat).')
leave.unlink()
def test_public_holiday_exclusion(self):
# Regression test: public holidays (global leaves on the company
# calendar) must be excluded from the jours ouvrables count.
# Company works 6 days/week (Mon-Sat). Public holiday on 14/07/2020.
# Leave 13/07/2020 (Mon) -> 19/07/2020 (Sun).
# Company working days without holiday: 13, 14, 15, 16, 17, 18 = 6
# With 14/07 being a public holiday: 13, 15, 16, 17, 18 = 5
company_calendar = self.env['resource.calendar'].create({
'name': 'Company Calendar 6d/week',
'company_id': self.company.id,
'tz': 'Europe/Paris',
'attendance_ids': [
(0, 0, {'name': 'Monday Morning', 'dayofweek': '0', 'hour_from': 9, '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': 9, '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': 9, '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': 9, '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': 9, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Friday Afternoon', 'dayofweek': '4', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'}),
(0, 0, {'name': 'Saturday Morning', 'dayofweek': '5', 'hour_from': 9, 'hour_to': 12, 'day_period': 'morning'}),
(0, 0, {'name': 'Saturday Afternoon', 'dayofweek': '5', 'hour_from': 13, 'hour_to': 17, 'day_period': 'afternoon'}),
],
})
employee_calendar = self.env['resource.calendar'].create({
'name': 'Employee Calendar Part Time',
'company_id': self.company.id,
'tz': 'Europe/Paris',
'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': 16, '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': 16, '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': 16, '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': 16, 'day_period': 'afternoon'}),
],
})
self.company.resource_calendar_id = company_calendar
self._set_employee_calendar(employee_calendar)
self.employee.tz = 'Europe/Paris'
# Create a public holiday on 14/07/2020 (Tuesday) on the company calendar
self.env['resource.calendar.leaves'].create({
'name': 'Bastille Day',
'calendar_id': company_calendar.id,
'date_from': '2020-07-14 00:00:00',
'date_to': '2020-07-14 23:59:59',
})
# Leave from 13/07/2020 (Monday) to 19/07/2020 (Sunday).
# Employee works Mon, Tue, Thu, Fri. Leave covers Mon-Sun.
# Return = Monday 20/07. date_to extended to Sunday 19/07 (non-working).
# Company working days (Mon-Sat) excluding 14/07 holiday:
# 13(Mon), 15(Wed), 16(Thu), 17(Fri), 18(Sat) = 5 days
leave = self.env['hr.leave'].create({
'name': 'Test public holiday',
'holiday_status_id': self.time_off_type.id,
'employee_id': self.employee.id,
'request_date_from': '2020-07-13',
'request_date_to': '2020-07-19',
'employee_company_id': self.company.id,
'resource_calendar_id': self.employee.resource_calendar_id.id,
})
leave._compute_date_from_to()
self.assertEqual(leave.number_of_days, 5.0,
'The number of days should be 5 (14/07 excluded as public holiday).')
leave.unlink()