521 lines
22 KiB
Python
521 lines
22 KiB
Python
from datetime import date
|
|
from dateutil.relativedelta import relativedelta
|
|
|
|
from odoo.tests import tagged
|
|
|
|
from .common import TestPayrollCommon
|
|
|
|
|
|
@tagged("post_install_l10n", "post_install", "-at_install", "payroll_sickness_relapse")
|
|
class TestPayrollSicknessRelapse(TestPayrollCommon):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
|
|
cls.sick_time_off_type = cls.env.ref("hr_holidays.leave_type_sick_time_off")
|
|
|
|
def test_sickness_relapse_visibility(self):
|
|
"""
|
|
Test Case:
|
|
Employee Test is sick for a week. The following week the employee becomes
|
|
sick again and submits another time off request. For the second
|
|
time off request the employee has the option to select if this sickness
|
|
is a relapse of the sickness from the week before or a new sickness.
|
|
"""
|
|
first_leave = self.env["hr.leave"].create(
|
|
{
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2024, 7, 1),
|
|
"request_date_to": date(2024, 7, 5),
|
|
}
|
|
)
|
|
second_leave = self.env["hr.leave"].create(
|
|
{
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2024, 7, 10),
|
|
"request_date_to": date(2024, 7, 12),
|
|
}
|
|
)
|
|
|
|
(first_leave + second_leave).action_approve()
|
|
|
|
self.assertFalse(first_leave.l10n_be_sickness_can_relapse)
|
|
self.assertTrue(second_leave.l10n_be_sickness_can_relapse)
|
|
|
|
def test_sickness_relapse_no_relapse(self):
|
|
"""
|
|
Test Case:
|
|
Employee Test is sick for 3 weeks. A week after the employee becomes
|
|
sick again and submits another time off request for another 3 weeks.
|
|
For the second time off request Employee test has indicated that this
|
|
is a new sickness and not a relapse of the previous sickness.
|
|
This results in a work entry with the code LEAVE110, Sick Time Off,
|
|
30 Calendar days after the first sick day, indicating that
|
|
the first sick leave has no effect on the second one.
|
|
"""
|
|
first_leave = self.env["hr.leave"].create(
|
|
{
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2024, 7, 1),
|
|
"request_date_to": date(2024, 7, 20),
|
|
}
|
|
)
|
|
second_leave = self.env["hr.leave"].create(
|
|
{
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2024, 7, 29),
|
|
"request_date_to": date(2024, 8, 16),
|
|
"l10n_be_sickness_relapse": False,
|
|
}
|
|
)
|
|
|
|
(first_leave + second_leave).action_approve()
|
|
|
|
work_entries = self.employee_test.version_ids.generate_work_entries(
|
|
date(2024, 8, 8), date(2024, 8, 8)
|
|
)
|
|
work_entries.action_validate()
|
|
work_entry_names = set(work_entries.mapped("code"))
|
|
|
|
self.assertSetEqual(work_entry_names, {"LEAVE110"})
|
|
|
|
def test_sickness_relapse_with_relapse(self):
|
|
"""
|
|
Test Case:
|
|
Employee Test is sick for 3 weeks. A week after the employee becomes
|
|
sick again and submits another time off request for another 3 weeks.
|
|
For the second time off request Employee test has indicated that this
|
|
a relapse of the previous sickness. This results in a work entry
|
|
with the code LEAVE214, Sick Time Off(Without Guaranteed Salary),
|
|
31 sick days after the first sick day, indicating that the second
|
|
sick leave is a continuation of the first one.
|
|
"""
|
|
first_leave = self.env["hr.leave"].create(
|
|
{
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2024, 7, 1),
|
|
"request_date_to": date(2024, 7, 20),
|
|
}
|
|
)
|
|
second_leave = self.env["hr.leave"].create(
|
|
{
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2024, 7, 29),
|
|
"request_date_to": date(2024, 8, 16),
|
|
"l10n_be_sickness_relapse": True,
|
|
}
|
|
)
|
|
|
|
(first_leave + second_leave).action_approve()
|
|
|
|
work_entry_paid = self.employee_test.version_ids.generate_work_entries(
|
|
date(2024, 8, 7), date(2024, 8, 7)
|
|
)
|
|
work_entry_unpaid = self.employee_test.version_ids.generate_work_entries(
|
|
date(2024, 8, 8), date(2024, 8, 8)
|
|
)
|
|
|
|
work_entry_paid.action_validate()
|
|
work_entry_unpaid.action_validate()
|
|
|
|
work_entry_paid_code = set(work_entry_paid.mapped("code"))
|
|
work_entry_unpaid_code = set(work_entry_unpaid.mapped("code"))
|
|
|
|
self.assertSetEqual(work_entry_paid_code, {"LEAVE110"})
|
|
self.assertSetEqual(work_entry_unpaid_code, {"LEAVE214"})
|
|
|
|
def test_sickness_multiple_sicknesses_partial_relapse(self):
|
|
"""
|
|
Test Case:
|
|
Employee Test is sick for 5 days every week for 4 weeks. The next week
|
|
Employee Test is sick again, but this is a new sickness. This sickness
|
|
relapses again every week for 2 more week. Even though Employee Test has
|
|
taken 35 days of sick leave he should still be paid fully as the
|
|
two sick leaves are not for the same illness. Thus all work entries
|
|
starting from the first day in the 7th week should still have
|
|
a work entry code of LEAVE110.
|
|
"""
|
|
first_leave = self.env["hr.leave"].create(
|
|
{
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2024, 7, 1),
|
|
"request_date_to": date(2024, 7, 5),
|
|
}
|
|
)
|
|
second_leave = self.env["hr.leave"].create(
|
|
{
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2024, 7, 8),
|
|
"request_date_to": date(2024, 7, 12),
|
|
"l10n_be_sickness_relapse": True,
|
|
}
|
|
)
|
|
third_leave = self.env["hr.leave"].create(
|
|
{
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2024, 7, 15),
|
|
"request_date_to": date(2024, 7, 19),
|
|
"l10n_be_sickness_relapse": True,
|
|
}
|
|
)
|
|
fourth_leave = self.env["hr.leave"].create(
|
|
{
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2024, 7, 22),
|
|
"request_date_to": date(2024, 7, 26),
|
|
"l10n_be_sickness_relapse": True,
|
|
}
|
|
)
|
|
fifth_leave = self.env["hr.leave"].create(
|
|
{
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2024, 7, 29),
|
|
"request_date_to": date(2024, 8, 2),
|
|
"l10n_be_sickness_relapse": False,
|
|
}
|
|
)
|
|
sixth_leave = self.env["hr.leave"].create(
|
|
{
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2024, 8, 5),
|
|
"request_date_to": date(2024, 8, 9),
|
|
"l10n_be_sickness_relapse": True,
|
|
}
|
|
)
|
|
seventh_leave = self.env["hr.leave"].create(
|
|
{
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2024, 8, 12),
|
|
"request_date_to": date(2024, 8, 16),
|
|
"l10n_be_sickness_relapse": True,
|
|
}
|
|
)
|
|
(
|
|
first_leave
|
|
+ second_leave
|
|
+ third_leave
|
|
+ fourth_leave
|
|
+ fifth_leave
|
|
+ sixth_leave
|
|
+ seventh_leave
|
|
).action_approve()
|
|
|
|
work_entries = self.employee_test.version_ids.generate_work_entries(
|
|
date(2024, 8, 12), date(2024, 8, 12)
|
|
)
|
|
work_entries.action_validate()
|
|
work_entries_code = set(work_entries.mapped("code"))
|
|
|
|
self.assertSetEqual(work_entries_code, {"LEAVE110"})
|
|
self.assertFalse(first_leave.l10n_be_sickness_can_relapse)
|
|
self.assertTrue(second_leave.l10n_be_sickness_can_relapse)
|
|
self.assertTrue(third_leave.l10n_be_sickness_can_relapse)
|
|
self.assertTrue(fourth_leave.l10n_be_sickness_can_relapse)
|
|
self.assertTrue(fifth_leave.l10n_be_sickness_can_relapse)
|
|
self.assertTrue(sixth_leave.l10n_be_sickness_can_relapse)
|
|
self.assertTrue(seventh_leave.l10n_be_sickness_can_relapse)
|
|
|
|
def test_sickness_multiple_sicknesses_only_relapse(self):
|
|
"""
|
|
Test Case:
|
|
Employee Test is sick for 5 days every week for 7 weeks, with every sick
|
|
leave being a relapse of the previous one. All work entries starting
|
|
from the first day in the 7th week should have a work entry code of LEAVE214.
|
|
"""
|
|
first_leave = self.env["hr.leave"].create(
|
|
{
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2024, 7, 1),
|
|
"request_date_to": date(2024, 7, 5),
|
|
}
|
|
)
|
|
second_leave = self.env["hr.leave"].create(
|
|
{
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2024, 7, 8),
|
|
"request_date_to": date(2024, 7, 12),
|
|
"l10n_be_sickness_relapse": True,
|
|
}
|
|
)
|
|
third_leave = self.env["hr.leave"].create(
|
|
{
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2024, 7, 15),
|
|
"request_date_to": date(2024, 7, 19),
|
|
"l10n_be_sickness_relapse": True,
|
|
}
|
|
)
|
|
fourth_leave = self.env["hr.leave"].create(
|
|
{
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2024, 7, 22),
|
|
"request_date_to": date(2024, 7, 26),
|
|
"l10n_be_sickness_relapse": True,
|
|
}
|
|
)
|
|
fifth_leave = self.env["hr.leave"].create(
|
|
{
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2024, 7, 29),
|
|
"request_date_to": date(2024, 8, 2),
|
|
"l10n_be_sickness_relapse": True,
|
|
}
|
|
)
|
|
sixth_leave = self.env["hr.leave"].create(
|
|
{
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2024, 8, 5),
|
|
"request_date_to": date(2024, 8, 9),
|
|
"l10n_be_sickness_relapse": True,
|
|
}
|
|
)
|
|
seventh_leave = self.env["hr.leave"].create(
|
|
{
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2024, 8, 12),
|
|
"request_date_to": date(2024, 8, 16),
|
|
"l10n_be_sickness_relapse": True,
|
|
}
|
|
)
|
|
|
|
(
|
|
first_leave
|
|
+ second_leave
|
|
+ third_leave
|
|
+ fourth_leave
|
|
+ fifth_leave
|
|
+ sixth_leave
|
|
+ seventh_leave
|
|
).action_approve()
|
|
|
|
work_entries = self.employee_test.version_ids.generate_work_entries(
|
|
date(2024, 8, 12), date(2024, 8, 12)
|
|
)
|
|
work_entries.action_validate()
|
|
work_entries_code = set(work_entries.mapped("code"))
|
|
|
|
self.assertSetEqual(work_entries_code, {"LEAVE214"})
|
|
self.assertFalse(first_leave.l10n_be_sickness_can_relapse)
|
|
self.assertTrue(second_leave.l10n_be_sickness_can_relapse)
|
|
self.assertTrue(third_leave.l10n_be_sickness_can_relapse)
|
|
self.assertTrue(fourth_leave.l10n_be_sickness_can_relapse)
|
|
self.assertTrue(fifth_leave.l10n_be_sickness_can_relapse)
|
|
self.assertTrue(sixth_leave.l10n_be_sickness_can_relapse)
|
|
self.assertTrue(seventh_leave.l10n_be_sickness_can_relapse)
|
|
|
|
def test_sickness_biweekly_relapse(self):
|
|
"""
|
|
Test Case:
|
|
A person is sick for 2 days every 14 days for almost 8 months.
|
|
Eventually the sick leave days should culminate in over 30 days
|
|
of leave causing the person to no longer have work entries with the
|
|
code LEAVE110.
|
|
"""
|
|
for i in range(16):
|
|
start_date = date(2024, 1, 1) + relativedelta(days=(14 * i))
|
|
end_date = start_date + relativedelta(days=1)
|
|
short_leave = self.env["hr.leave"].create(
|
|
{
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": start_date,
|
|
"request_date_to": end_date,
|
|
"l10n_be_sickness_relapse": True,
|
|
}
|
|
)
|
|
short_leave.action_approve()
|
|
|
|
work_entries = self.employee_test.version_ids.generate_work_entries(
|
|
date(2024, 7, 15), date(2024, 7, 29)
|
|
)
|
|
|
|
work_entries.action_validate()
|
|
|
|
paid_date = work_entries.filtered(lambda entry: entry.date.day == 15)
|
|
unpaid_date = work_entries.filtered(lambda entry: entry.date.day == 29)
|
|
|
|
work_entry_paid_code = set(paid_date.mapped("code"))
|
|
work_entry_unpaid_code = set(unpaid_date.mapped("code"))
|
|
|
|
self.assertSetEqual(work_entry_paid_code, {"LEAVE110"})
|
|
self.assertSetEqual(work_entry_unpaid_code, {"LEAVE214"})
|
|
|
|
def test_from_comment(self):
|
|
"""
|
|
Example (all dates are inclusive):
|
|
| Name | Date from | Date to | Relapse | Calendar Days | Work Days |
|
|
| ---- | ----------- | ----------- | ------- | ------------- | ---------- |
|
|
| 1st | 10/Jun/2024 | 12/Jun/2024 | False | 03 (c)days | 03 (w)days |
|
|
| 2nd | 01/Jul/2024 | 08/Jul/2024 | False | 08 (c)days | 06 (w)days |
|
|
| 3rd | 15/Jul/2024 | 30/Jul/2024 | True | 16 (c)days | 12 (w)days |
|
|
| 4th | 05/Aug/2024 | 15/Aug/2024 | True | 11 (c)days | 09 (w)days |
|
|
|
|
Note: 1st and 2nd leave will have a relapse value of True in practice because
|
|
that is the default value for the field. In this example, the value is set to
|
|
False to hopefully make the example clearer.
|
|
|
|
The first leave is shorter than 30 (calendar) days.
|
|
All (work) days within this leave have a guaranteed salary.
|
|
|
|
The second leave is shorter than 30 (c) days.
|
|
The gap between it and the first leave is greater than 14 days.
|
|
All (w) days within this leave have a guaranteed salary.
|
|
|
|
The third leave is shorter than 30 (c) days.
|
|
The gap between it and the second leave is less than 14 days.
|
|
It is a relapse, sum the duration of this and previous related leaves.
|
|
The sum is 8 + 16 = 24 (c) days, which is less than 30 days.
|
|
All (w) days within this leave have a guaranteed salary.
|
|
|
|
The fourth leave is shorter than 30 (c) days.
|
|
The gap between it and the third leave is less than 14 days.
|
|
It is a relapse, sum the duration of this and previous related leaves.
|
|
That sum is 8 + 16 + 11 = 35 (c) days, which is greater than 30 days.
|
|
The first 6 (c) days have a guaranteed salary.
|
|
(w) days 12/08 - 15/08 do not have a guaranteed salary.
|
|
"""
|
|
first_leave = self.env["hr.leave"].create(
|
|
{
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2024, 6, 10),
|
|
"request_date_to": date(2024, 6, 12),
|
|
}
|
|
)
|
|
second_leave = self.env["hr.leave"].create(
|
|
{
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2024, 7, 1),
|
|
"request_date_to": date(2024, 7, 8),
|
|
}
|
|
)
|
|
third_leave = self.env["hr.leave"].create(
|
|
{
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2024, 7, 15),
|
|
"request_date_to": date(2024, 7, 30),
|
|
}
|
|
)
|
|
fourth_leave = self.env["hr.leave"].create(
|
|
{
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2024, 8, 5),
|
|
"request_date_to": date(2024, 8, 15),
|
|
}
|
|
)
|
|
(first_leave + second_leave + third_leave + fourth_leave).action_approve()
|
|
|
|
work_entries = self.employee_test.version_ids.generate_work_entries(
|
|
date(2024, 8, 9), date(2024, 8, 12)
|
|
)
|
|
|
|
work_entries.action_validate()
|
|
|
|
paid_date = work_entries.filtered(lambda entry: entry.date.day == 9)
|
|
unpaid_date = work_entries.filtered(lambda entry: entry.date.day == 12)
|
|
work_entry_paid_code = set(paid_date.mapped("code"))
|
|
work_entry_unpaid_code = set(unpaid_date.mapped("code"))
|
|
|
|
self.assertSetEqual(work_entry_paid_code, {"LEAVE110"})
|
|
self.assertSetEqual(work_entry_unpaid_code, {"LEAVE214"})
|
|
self.assertFalse(first_leave.l10n_be_sickness_can_relapse)
|
|
self.assertFalse(second_leave.l10n_be_sickness_can_relapse)
|
|
self.assertTrue(third_leave.l10n_be_sickness_can_relapse)
|
|
self.assertTrue(fourth_leave.l10n_be_sickness_can_relapse)
|
|
|
|
def test_sickness_relapse_starting_from_2026(self):
|
|
"""
|
|
Example (all dates are inclusive):
|
|
| Leave | Date from | Date to | Relapse | Calendar Days | Work Days |
|
|
| ----- | ----------- | ----------- | ------- | ------------- | ---------- |
|
|
| 1st | 10/Jan/26 | 30/Jan/26 | False | 21 (c)days | 15 (w)days |
|
|
| 2nd | 01/Apr/26 | 15/Apr/26 | False | 15 (c)days | 11 (w)days |
|
|
| 3rd | 11/May/26 | 30/May/26 | True | 20 (c)days | 15 (w)days |
|
|
| 4th | 10/Aug/26 | 20/Aug/26 | False | 11 (c)days | 8 (w)days |
|
|
The first leave is shorter than 30 (calendar) days.
|
|
All (work) days within this leave have a guaranteed salary.
|
|
The second leave is shorter than 30 (c) days.
|
|
The gap between it and the first leave is greater than 56 days.
|
|
It is not considered as a relapse.
|
|
All (w) days within this leave have a guaranteed salary.
|
|
The third leave is shorter than 30 (c) days.
|
|
The gap between it and the second leave is less than 56 days.
|
|
It is a relapse, sum the duration of this and previous related leaves.
|
|
The sum is 15 + 20 = 35 (c) days, which is greater than 30 days.
|
|
The first 30 (c) days have a guaranteed salary.
|
|
(w) days 26/05 - 30/05 do not have a guaranteed salary.
|
|
The fourth leave is shorter than 30 (c) days.
|
|
The gap between it and the third leave is greater than 56 days.
|
|
It is not considered as a relapse.
|
|
"""
|
|
|
|
first_leave = self.env["hr.leave"].create({
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2026, 1, 10),
|
|
"request_date_to": date(2026, 1, 30),
|
|
})
|
|
|
|
second_leave = self.env["hr.leave"].create({
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2026, 4, 1),
|
|
"request_date_to": date(2026, 4, 15),
|
|
})
|
|
|
|
third_leave = self.env["hr.leave"].create({
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2026, 5, 11),
|
|
"request_date_to": date(2026, 5, 30),
|
|
})
|
|
|
|
fourth_leave = self.env["hr.leave"].create({
|
|
"holiday_status_id": self.sick_time_off_type.id,
|
|
"employee_id": self.employee_test.id,
|
|
"request_date_from": date(2026, 8, 10),
|
|
"request_date_to": date(2026, 8, 20),
|
|
})
|
|
(first_leave + second_leave + third_leave + fourth_leave).action_approve()
|
|
|
|
work_entries = self.employee_test.version_ids.generate_work_entries(
|
|
date(2026, 5, 21), date(2026, 5, 30)
|
|
)
|
|
work_entries.action_validate()
|
|
|
|
paid_date = work_entries.filtered(lambda entry: entry.date.day == 22)
|
|
unpaid_date = work_entries.filtered(lambda entry: entry.date.day == 29)
|
|
work_entry_paid_code = set(paid_date.mapped("code"))
|
|
work_entry_unpaid_code = set(unpaid_date.mapped("code"))
|
|
|
|
self.assertSetEqual(work_entry_paid_code, {"LEAVE110"})
|
|
self.assertSetEqual(work_entry_unpaid_code, {"LEAVE214"})
|
|
|
|
self.assertFalse(first_leave.l10n_be_sickness_can_relapse)
|
|
self.assertFalse(second_leave.l10n_be_sickness_can_relapse)
|
|
self.assertTrue(third_leave.l10n_be_sickness_can_relapse)
|
|
self.assertFalse(fourth_leave.l10n_be_sickness_can_relapse)
|