From 92ef335beef6f373a110b230b00ce5483cf699ce Mon Sep 17 00:00:00 2001 From: mafo-odoo Date: Mon, 27 Jun 2022 08:14:59 +0000 Subject: [PATCH] [FIX] hr_holidays: negative allocation in accural plan Steps to reproduce: - Create an accural plan with two levels, the first should have its action_with_unused_accruals set as lost. The second should start one year after the first level. - Use this plan on a employee and make it start the first day of the previous year. Current behavior: The number of allocated day is wrong and can even be negative Expected behavior: The days of the first level are lost and there is the right amount of allocated days, Eplanation: The _end_of_the_year function was first designed to be only called on the first day of the year but the it changed since then without updating it's content and it can calle any day of the year now. In this case the use of today() does not make sense and it should be replaced by the first day of the current year. opw-2868297 closes odoo/odoo#94897 X-original-commit: 476818972e93b32df6f25cf299f631a8f7eb3af4 Signed-off-by: Fockedey Martin (mafo) Signed-off-by: Kevin Baptiste --- .../hr_holidays/models/hr_leave_allocation.py | 9 ++-- .../tests/test_accrual_allocations.py | 41 +++++++++++++++++++ 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/addons/hr_holidays/models/hr_leave_allocation.py b/addons/hr_holidays/models/hr_leave_allocation.py index 7dcc0357801..cf43d0ac769 100644 --- a/addons/hr_holidays/models/hr_leave_allocation.py +++ b/addons/hr_holidays/models/hr_leave_allocation.py @@ -331,21 +331,22 @@ class HolidaysAllocation(models.Model): # to override in payroll today = fields.Date.today() last_day_last_year = today + relativedelta(years=-1, month=12, day=31) + first_day_this_year = today + relativedelta(month=1, day=1) for allocation in self: - current_level = allocation._get_current_accrual_plan_level_id(today)[0] + current_level = allocation._get_current_accrual_plan_level_id(first_day_this_year)[0] if not current_level: continue - nextcall = current_level._get_next_date(today) + nextcall = current_level._get_next_date(first_day_this_year) if current_level.action_with_unused_accruals == 'lost': # Allocations are lost but number_of_days should not be lower than leaves_taken - allocation.write({'number_of_days': allocation.leaves_taken, 'lastcall': today, 'nextcall': nextcall}) + allocation.write({'number_of_days': allocation.leaves_taken, 'lastcall': first_day_this_year, 'nextcall': nextcall}) elif current_level.action_with_unused_accruals == 'postponed' and current_level.postpone_max_days: # Make sure the period was ran until the last day of last year if allocation.nextcall: allocation.nextcall = last_day_last_year allocation._process_accrual_plans(last_day_last_year, True) number_of_days = min(allocation.number_of_days - allocation.leaves_taken, current_level.postpone_max_days) + allocation.leaves_taken - allocation.write({'number_of_days': number_of_days, 'lastcall': today, 'nextcall': nextcall}) + allocation.write({'number_of_days': number_of_days, 'lastcall': first_day_this_year, 'nextcall': nextcall}) def _get_current_accrual_plan_level_id(self, date, level_ids=False): """ diff --git a/addons/hr_holidays/tests/test_accrual_allocations.py b/addons/hr_holidays/tests/test_accrual_allocations.py index 42b5449d363..9830ac2c85e 100644 --- a/addons/hr_holidays/tests/test_accrual_allocations.py +++ b/addons/hr_holidays/tests/test_accrual_allocations.py @@ -641,6 +641,47 @@ class TestAccrualAllocations(TestHrHolidaysCommon): allocation._update_accrual() self.assertAlmostEqual(allocation.number_of_days, 30.79, 2, "Invalid number of days") + 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 + # with unused accruals set as lost that the days are effectively lost + 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': 0, + 'start_type': 'day', + 'added_value': 1, + 'added_value_type': 'days', + 'frequency': 'monthly', + 'maximum_leave': 12, + 'action_with_unused_accruals': 'lost', + }), + (0, 0, { + 'start_count': 1, + 'start_type': 'year', + 'added_value': 1, + 'added_value_type': 'days', + 'frequency': 'monthly', + 'maximum_leave': 12, + 'action_with_unused_accruals': 'lost', + }), + ], + }) + 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(2021, 1, 1), + }) + allocation.action_confirm() + allocation.action_validate() + with freeze_time('2022-4-4'): + allocation._update_accrual() + self.assertEqual(allocation.number_of_days, 3, "Invalid number of days") + def test_accrual_maximum_leaves(self): accrual_plan = self.env['hr.leave.accrual.plan'].with_context(tracking_disable=True).create({ 'name': 'Accrual Plan For Test',