[MOV]hr_holidays_timeoff_analysis:move hr_holidays_timeoff_analysis from elabore-addons repos to hr-tools repos

This commit is contained in:
2026-06-02 11:02:13 +02:00
parent cc719291eb
commit de80996484
15 changed files with 2033 additions and 0 deletions

View File

@@ -0,0 +1 @@
from . import test_hr_leave_timeoff_day

View File

@@ -0,0 +1,719 @@
from odoo.fields import Date
from odoo.tests import tagged
from odoo.tests.common import TransactionCase
@tagged("post_install", "-at_install")
class TestHrLeaveTimeoffDay(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.employee = cls.env["hr.employee"].create(
{
"name": "Camille",
"tz": "Europe/Paris",
}
)
cls.base_calendar = cls.env["resource.calendar"].create(
{
"name": "default calendar",
}
)
cls.time_off_type = cls.env["hr.leave.type"].create(
{
"name": "Time Off",
"requires_allocation": "no",
"request_unit": "half_day",
}
)
cls.time_off_hour_type = cls.env["hr.leave.type"].create(
{
"name": "Recovery",
"requires_allocation": "no",
"request_unit": "hour",
}
)
def test_leave_between_2_months_nb_of_days(self):
leave = self.env["hr.leave"].create(
{
"employee_id": self.employee.id,
"request_date_from": Date.to_date("2025-06-30"),
"request_date_to": Date.to_date("2025-07-06"),
"holiday_status_id": self.time_off_type.id,
}
)
leave.state = "validate" # Simulate the leave being validated
self.env["hr.leave.timeoff.day"].cron_manage_timeoff_days()
# Vérifie qu'il existe bien 5 hr.leave.timeoff.day pour ce leave
timeoff_days = self.env["hr.leave.timeoff.day"].search(
[
("employee_id", "=", self.employee.id),
("hr_leave_id", "=", leave.id),
]
)
self.assertEqual(
len(timeoff_days), 5, "There should be 5 timeoff days for this leave"
)
# Vérifie que la somme des leave_duration_by_day fait bien 5
total_duration = sum(timeoff_days.mapped("leave_duration_by_day"))
self.assertEqual(
total_duration,
5.0,
"The sum of leave_duration_by_day should be 5.0 for this leave",
)
def test_leave_duration_by_day_half_day(self):
leave = self.env["hr.leave"].create(
{
"employee_id": self.employee.id,
"request_date_from": Date.to_date("2025-07-02"),
"request_date_to": Date.to_date("2025-07-02"),
"holiday_status_id": self.time_off_type.id,
"request_unit_half": True,
}
)
leave.state = "validate" # Simulate the leave being validated
self.env["hr.leave.timeoff.day"].cron_manage_timeoff_days()
timeoff_days = self.env["hr.leave.timeoff.day"].search(
[
("employee_id", "=", self.employee.id),
("hr_leave_id", "=", leave.id),
]
)
self.assertEqual(
len(timeoff_days), 1, "There should be 1 timeoff day for this leave"
)
total_duration = sum(timeoff_days.mapped("leave_duration_by_day"))
self.assertEqual(
total_duration,
0.5,
"leave_duration_by_day should be 0.5 for a half day leave",
)
def test_leave_duration_by_day_hour_compare_to_employee_calendar(self):
employee_calendar = self.env["resource.calendar"].create(
{
"name": "Employee Calendar",
"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",
},
),
],
}
)
self.employee.resource_calendar_id = employee_calendar
leave = self.env["hr.leave"].create(
{
"employee_id": self.employee.id,
"request_date_from": Date.to_date("2025-07-03"),
"request_date_to": Date.to_date("2025-07-03"),
"request_unit_hours": True,
"request_hour_from": "8",
"request_hour_to": "12",
"holiday_status_id": self.time_off_hour_type.id,
}
)
leave._compute_date_from_to()
leave._compute_duration()
leave.state = "validate" # Simulate the leave being validated
self.env["hr.leave.timeoff.day"].cron_manage_timeoff_days()
timeoff_days = self.env["hr.leave.timeoff.day"].search(
[
("employee_id", "=", self.employee.id),
("hr_leave_id", "=", leave.id),
]
)
self.assertEqual(
len(timeoff_days), 1, "There should be 1 timeoff day for this leave"
)
total_duration = sum(timeoff_days.mapped("leave_duration_by_day"))
self.assertEqual(
total_duration,
0.5,
"leave_duration_by_day should be 0.5 for 4 hours on an 8h day",
)
def test_leave_duration_by_day_compare_to_time_part_employee_calendar(self):
employee_calendar = self.env["resource.calendar"].create(
{
"name": "Employee Calendar",
"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",
},
),
],
}
)
self.employee.resource_calendar_id = employee_calendar
leave = self.env["hr.leave"].create(
{
"employee_id": self.employee.id,
"request_date_from": Date.to_date("2025-07-21"),
"request_date_to": Date.to_date("2025-07-27"),
"holiday_status_id": self.time_off_type.id,
}
)
leave.state = "validate" # Simulate the leave being validated
self.env["hr.leave.timeoff.day"].cron_manage_timeoff_days()
timeoff_days = self.env["hr.leave.timeoff.day"].search(
[
("employee_id", "=", self.employee.id),
("hr_leave_id", "=", leave.id),
]
)
self.assertEqual(
len(timeoff_days), 4, "There should be 4 timeoff day for this leave"
)
total_duration = sum(timeoff_days.mapped("leave_duration_by_day"))
self.assertEqual(
total_duration,
4,
"leave_duration_by_day should be 4 day",
)
def test_public_holidays_between_a_leave(self):
# Create a public holiday on 8 May 2025,
# because of TZ conversion we set it from 7 May 22:00 to 8 May 23:00
self.env["resource.calendar.leaves"].create(
{
"name": "8 mai 2025",
"date_from": "2025-05-07 22:00:00",
"date_to": "2025-05-08 23:00:00",
}
)
leave = self.env["hr.leave"].create(
{
"employee_id": self.employee.id,
"request_date_from": Date.to_date("2025-05-05"),
"request_date_to": Date.to_date(
"2025-05-11"
), # a public holiday is in between (8 may)
"holiday_status_id": self.time_off_type.id,
}
)
leave.state = "validate" # Simulate the leave being validated
self.env["hr.leave.timeoff.day"].cron_manage_timeoff_days()
# Vérifie qu'il existe bien 4 hr.leave.timeoff.day pour ce leave
timeoff_days = self.env["hr.leave.timeoff.day"].search(
[
("employee_id", "=", self.employee.id),
("hr_leave_id", "=", leave.id),
]
)
self.assertEqual(
len(timeoff_days), 4, "There should be 4 timeoff days for this leave"
)
# Vérifie que la somme des leave_duration_by_day fait bien 4
total_duration = sum(timeoff_days.mapped("leave_duration_by_day"))
self.assertEqual(
total_duration,
4.0,
"The sum of leave_duration_by_day should be 4.0 for this leave",
)
def test_unvalidated_leave(self):
leave = self.env["hr.leave"].create(
{
"employee_id": self.employee.id,
"request_date_from": Date.to_date("2025-08-04"),
"request_date_to": Date.to_date("2025-08-10"),
"holiday_status_id": self.time_off_type.id,
}
)
leave.state = "validate" # Simulate the leave being validated
self.env["hr.leave.timeoff.day"].cron_manage_timeoff_days()
# Vérifie qu'il existe bien 5 hr.leave.timeoff.day pour ce leave
timeoff_days = self.env["hr.leave.timeoff.day"].search(
[
("employee_id", "=", self.employee.id),
("hr_leave_id", "=", leave.id),
]
)
self.assertEqual(
len(timeoff_days), 5, "There should be 5 timeoff days for this leave"
)
leave.state = "confirm"
self.env["hr.leave.timeoff.day"].cron_manage_timeoff_days()
# Vérifie qu'il n'existe plus de hr.leave.timeoff.day pour ce leave
timeoff_days = self.env["hr.leave.timeoff.day"].search(
[
("employee_id", "=", self.employee.id),
("hr_leave_id", "=", leave.id),
]
)
self.assertEqual(
len(timeoff_days), 0, "There should be no timeoff days for this leave"
)
def test_deleted_leave(self):
leave = self.env["hr.leave"].create(
{
"employee_id": self.employee.id,
"request_date_from": Date.to_date("2025-08-18"),
"request_date_to": Date.to_date("2025-08-24"),
"holiday_status_id": self.time_off_type.id,
}
)
leave.state = "validate" # Simulate the leave being validated
self.env["hr.leave.timeoff.day"].cron_manage_timeoff_days()
# Vérifie qu'il existe bien 5 hr.leave.timeoff.day pour ce leave
timeoff_days = self.env["hr.leave.timeoff.day"].search(
[
("employee_id", "=", self.employee.id),
("hr_leave_id", "=", leave.id),
]
)
self.assertEqual(
len(timeoff_days), 5, "There should be 5 timeoff days for this leave"
)
leave.state = "confirm"
leave.unlink()
self.env["hr.leave.timeoff.day"].cron_manage_timeoff_days()
# Vérifie qu'il n'existe plus de hr.leave.timeoff.day pour ce leave
timeoff_days = self.env["hr.leave.timeoff.day"].search(
[
("employee_id", "=", self.employee.id),
("hr_leave_id", "=", leave.id),
]
)
self.assertEqual(
len(timeoff_days), 0, "There should be no timeoff days for this leave"
)
def test_unactive_leave(self):
"""
When a leave is canceled, his status stay 'validate' but the field active is set
to False.
"""
leave = self.env["hr.leave"].create(
{
"employee_id": self.employee.id,
"request_date_from": Date.to_date("2025-12-08"),
"request_date_to": Date.to_date("2025-12-14"),
"holiday_status_id": self.time_off_type.id,
}
)
leave.state = "validate" # Simulate the leave being validated
self.env["hr.leave.timeoff.day"].cron_manage_timeoff_days()
# Vérifie qu'il existe bien 5 hr.leave.timeoff.day pour ce leave
timeoff_days = self.env["hr.leave.timeoff.day"].search(
[
("employee_id", "=", self.employee.id),
("hr_leave_id", "=", leave.id),
]
)
self.assertEqual(
len(timeoff_days), 5, "There should be 5 timeoff days for this leave"
)
leave._force_cancel(
"reason test", "mail.mt_note"
) # Simulate the leave being unactive but status stay 'validate'
self.env["hr.leave.timeoff.day"].cron_manage_timeoff_days()
# Vérifie qu'il n'existe plus de hr.leave.timeoff.day pour ce leave
timeoff_days = self.env["hr.leave.timeoff.day"].search(
[
("employee_id", "=", self.employee.id),
("hr_leave_id", "=", leave.id),
]
)
self.assertEqual(
len(timeoff_days), 0, "There should be no timeoff days for this leave"
)
def test_hr_employee_calendar(self):
if "hr.employee.calendar" not in self.env:
return
employee_calendar_1 = (
self.base_calendar
) # full time calendar (from monday to friday)
employee_calendar_2 = self.env["resource.calendar"].create(
{ # part time calendar (from monday to thursday)
"name": "Employee Calendar",
"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",
},
),
],
}
)
self.env["hr.employee.calendar"].create(
{
"employee_id": self.employee.id,
"date_start": Date.to_date("2023-07-01"),
"date_end": Date.to_date("2025-06-30"),
"calendar_id": employee_calendar_1.id,
}
)
self.env["hr.employee.calendar"].create(
{
"employee_id": self.employee.id,
"date_start": Date.to_date("2025-07-01"),
"date_end": None,
"calendar_id": employee_calendar_2.id,
}
)
self.employee.resource_calendar_id = employee_calendar_2
# Leave during employee_calendar_1 period when employee is full time
leave = self.env["hr.leave"].create(
{
"employee_id": self.employee.id,
"request_date_from": Date.to_date(
"2024-07-22"
), # this leave occures when employee_calendar_1 is applied
"request_date_to": Date.to_date("2024-07-28"),
"holiday_status_id": self.time_off_type.id,
}
)
leave.state = "validate" # Simulate the leave being validated
self.env["hr.leave.timeoff.day"].cron_manage_timeoff_days()
timeoff_days = self.env["hr.leave.timeoff.day"].search(
[
("employee_id", "=", self.employee.id),
("hr_leave_id", "=", leave.id),
]
)
self.assertEqual(
len(timeoff_days), 5, "There should be 5 timeoff day for this leave"
)
total_duration = sum(timeoff_days.mapped("leave_duration_by_day"))
self.assertEqual(
total_duration,
5,
"leave_duration_by_day should be 5 day",
)
leave.state = "confirm"
leave.unlink()
# Leave during employee_calendar_2 period (the employee his part time now)
leave_2 = self.env["hr.leave"].create(
{
"employee_id": self.employee.id,
"request_date_from": Date.to_date(
"2025-11-24"
), # this leave occures when employee_calendar_1 is applied
"request_date_to": Date.to_date("2025-11-30"),
"holiday_status_id": self.time_off_type.id,
}
)
leave_2.state = "validate" # Simulate the leave being validated
self.env["hr.leave.timeoff.day"].cron_manage_timeoff_days()
timeoff_days_2 = self.env["hr.leave.timeoff.day"].search(
[
("employee_id", "=", self.employee.id),
("hr_leave_id", "=", leave_2.id),
]
)
self.assertEqual(
len(timeoff_days_2), 4, "There should be 4 timeoff day for this leave"
)
total_duration_2 = sum(timeoff_days_2.mapped("leave_duration_by_day"))
self.assertEqual(
total_duration_2,
4,
"leave_duration_by_day should be 4 day",
)