From 4c263e04232b6471b580ae119dd7ce026e52af46 Mon Sep 17 00:00:00 2001 From: mafo-odoo Date: Wed, 20 Jul 2022 13:20:40 +0000 Subject: [PATCH] [FIX] hr_holidays : wrong number of days for multilevel accrual plan Steps to reproduce: - Create an accrual plan and an allocation request such as described in the added test and validate the allocation request - Run the scheduled action for accrual plan computation - Check the number of allocated days Expected behavior: The first level should bring 6 days, the second 3 days and the last 1 day for a total of 10 days Current behavior: The 3 level give non integer values closed to the expected for a total of 9,... days. Explanation: When transiting between two levels the nextcall was the last day of the current level to have the right level, this creates an inconsistency as the end_date of the _process_accrual_plan_level level should go up to the first day of the next level to have the full number of days expected. To solve the issue we change the level selection so that if the date is the first day of the level it is still in the previous level. We also modify the places where the nextcall was modified when transiting level so that there is no more one day delta anymore. opw-2868297 closes odoo/odoo#96665 X-original-commit: 5d055130c97c5d8367c2b71fc617f588c5e15741 Signed-off-by: Kevin Baptiste --- .../hr_holidays/models/hr_leave_allocation.py | 6 +-- .../tests/test_accrual_allocations.py | 49 ++++++++++++++++++- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/addons/hr_holidays/models/hr_leave_allocation.py b/addons/hr_holidays/models/hr_leave_allocation.py index 3fa1237f99c..9467d68584f 100644 --- a/addons/hr_holidays/models/hr_leave_allocation.py +++ b/addons/hr_holidays/models/hr_leave_allocation.py @@ -357,7 +357,7 @@ class HolidaysAllocation(models.Model): current_level = False current_level_idx = -1 for idx, level in enumerate(level_ids): - if date >= self.date_from + get_timedelta(level.start_count, level.start_type): + if date > self.date_from + get_timedelta(level.start_count, level.start_type): current_level = level current_level_idx = idx # If transition_mode is set to `immediately` or we are currently on the first level @@ -421,7 +421,7 @@ class HolidaysAllocation(models.Model): allocation.nextcall = first_level._get_next_date(allocation.lastcall) if len(level_ids) > 1: second_level_start_date = allocation.date_from + get_timedelta(level_ids[1].start_count, level_ids[1].start_type) - allocation.nextcall = min(second_level_start_date - relativedelta(days=1), allocation.nextcall) + allocation.nextcall = min(second_level_start_date, allocation.nextcall) allocation._message_log(body=first_allocation) days_added_per_level = defaultdict(lambda: 0) while allocation.nextcall <= date_to: @@ -435,7 +435,7 @@ class HolidaysAllocation(models.Model): # Also prorate this accrual in the event that we are passing from one level to another if current_level_idx < (len(level_ids) - 1) and allocation.accrual_plan_id.transition_mode == 'immediately': next_level = level_ids[current_level_idx + 1] - current_level_last_date = allocation.date_from + get_timedelta(next_level.start_count, next_level.start_type) - relativedelta(days=1) + current_level_last_date = allocation.date_from + get_timedelta(next_level.start_count, next_level.start_type) if allocation.nextcall != current_level_last_date: nextcall = min(nextcall, current_level_last_date) diff --git a/addons/hr_holidays/tests/test_accrual_allocations.py b/addons/hr_holidays/tests/test_accrual_allocations.py index 9830ac2c85e..799270bf5ba 100644 --- a/addons/hr_holidays/tests/test_accrual_allocations.py +++ b/addons/hr_holidays/tests/test_accrual_allocations.py @@ -639,7 +639,54 @@ class TestAccrualAllocations(TestHrHolidaysCommon): allocation.action_validate() with freeze_time('2022-1-10'): allocation._update_accrual() - self.assertAlmostEqual(allocation.number_of_days, 30.79, 2, "Invalid number of days") + self.assertAlmostEqual(allocation.number_of_days, 30.82, 2, "Invalid number of days") + + def test_three_levels_accrual(self): + accrual_plan = self.env['hr.leave.accrual.plan'].with_context(tracking_disable=True).create({ + 'name': 'Accrual Plan For Test', + 'level_ids': [(0, 0, { + 'start_count': 2, + 'start_type': 'month', + 'added_value': 3, + 'added_value_type': 'days', + 'frequency': 'monthly', + 'maximum_leave': 3, + 'action_with_unused_accruals': 'postponed', + 'first_day': 31, + }), (0, 0, { + 'start_count': 3, + 'start_type': 'month', + 'added_value': 6, + 'added_value_type': 'days', + 'frequency': 'monthly', + 'maximum_leave': 6, + 'action_with_unused_accruals': 'postponed', + 'first_day': 31, + }), (0, 0, { + 'start_count': 4, + 'start_type': 'month', + 'added_value': 1, + 'added_value_type': 'days', + 'frequency': 'monthly', + 'maximum_leave': 100, + 'action_with_unused_accruals': 'postponed', + 'first_day': 31, + })], + }) + allocation = self.env['hr.leave.allocation'].with_user(self.user_hrmanager_id).with_context(tracking_disable=True).create({ + 'name': 'Accrual Allocation - Test', + 'accrual_plan_id': accrual_plan.id, + 'employee_id': self.employee_emp.id, + 'holiday_status_id': self.leave_type.id, + 'number_of_days': 0, + 'allocation_type': 'accrual', + 'date_from': datetime.date(2022, 1, 31), + }) + allocation.action_confirm() + allocation.action_validate() + with freeze_time('2022-7-20'): + allocation._update_accrual() + self.assertEqual(allocation.number_of_days, 10) def test_accrual_lost_previous_days(self): # Test that when an allocation with two levels is made and that the first level has it's action