diff --git a/addons/hr_holidays/models/hr_leave_allocation.py b/addons/hr_holidays/models/hr_leave_allocation.py index fafc55a3aab..75807316027 100644 --- a/addons/hr_holidays/models/hr_leave_allocation.py +++ b/addons/hr_holidays/models/hr_leave_allocation.py @@ -609,17 +609,26 @@ class HolidaysAllocation(models.Model): def _add_lastcalls(self): for allocation in self: - if allocation.allocation_type != 'accrual' or allocation.lastcall: + if allocation.allocation_type != 'accrual': continue today = fields.Date.today() - current_level = allocation._get_current_accrual_plan_level_id(today)[0] - if not current_level: - allocation.lastcall = today - continue - allocation.lastcall = max( - current_level._get_previous_date(today), - allocation.date_from + get_timedelta(current_level.start_count, current_level.start_type) - ) + (current_level, current_level_idx) = allocation._get_current_accrual_plan_level_id(today) + if not allocation.lastcall: + if not current_level: + allocation.lastcall = today + continue + allocation.lastcall = max( + current_level._get_previous_date(today), + allocation.date_from + get_timedelta(current_level.start_count, current_level.start_type) + ) + if not allocation.nextcall and allocation.lastcall < today: + accrual_plan = allocation.accrual_plan_id + next_level = False + allocation.nextcall = current_level._get_next_date(allocation.lastcall) + if current_level_idx < (len(accrual_plan.level_ids) - 1) and accrual_plan.transition_mode == 'immediately': + next_level = allocation.accrual_plan_id.level_ids[current_level_idx + 1] + next_level_start = allocation.date_from + get_timedelta(next_level.start_count, next_level.start_type) + allocation.nextcall = min(allocation.nextcall, next_level_start) def add_follower(self, employee_id): employee = self.env['hr.employee'].browse(employee_id) diff --git a/addons/hr_holidays/tests/__init__.py b/addons/hr_holidays/tests/__init__.py index 575737bd337..8b1189393be 100644 --- a/addons/hr_holidays/tests/__init__.py +++ b/addons/hr_holidays/tests/__init__.py @@ -19,3 +19,4 @@ from . import test_global_leaves from . import test_uninstall from . import test_holidays_calendar from . import test_negative +from . import test_past_accruals diff --git a/addons/hr_holidays/tests/test_past_accruals.py b/addons/hr_holidays/tests/test_past_accruals.py new file mode 100644 index 00000000000..419a309f03f --- /dev/null +++ b/addons/hr_holidays/tests/test_past_accruals.py @@ -0,0 +1,67 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. +from datetime import date +from freezegun import freeze_time + +from odoo.tests import tagged + +from odoo.addons.hr_holidays.tests.common import TestHrHolidaysCommon + + +@tagged('post_install', '-at_install', 'accruals') +class TestAccrualAllocations(TestHrHolidaysCommon): + @classmethod + def setUpClass(cls): + super(TestAccrualAllocations, cls).setUpClass() + cls.leave_type = cls.env['hr.leave.type'].create({ + 'name': 'Accrual Time Off', + 'time_type': 'leave', + 'requires_allocation': 'yes', + 'allocation_validation_type': 'no', + }) + cls.accrual_plan = cls.env['hr.leave.accrual.plan'].with_context(tracking_disable=True).create({ + 'name': 'Test Seniority Plan', + 'level_ids': [ + (0, 0, { + 'start_count': 1, + 'start_type': 'day', + 'added_value': 1, + 'added_value_type': 'day', + 'frequency': 'yearly', + 'cap_accrued_time': True, + 'maximum_leave': 10000, + }), + (0, 0, { + 'start_count': 4, + 'start_type': 'year', + 'added_value': 1, + 'added_value_type': 'day', + 'frequency': 'yearly', + 'cap_accrued_time': True, + 'maximum_leave': 10000, + }), + (0, 0, { + 'start_count': 8, + 'start_type': 'year', + 'added_value': 1, + 'added_value_type': 'day', + 'frequency': 'yearly', + 'cap_accrued_time': True, + 'maximum_leave': 10000, + }), + ] + }) + + def _test_past_accrual(self): + with freeze_time("2023-12-01"): + allocation = self.env['hr.leave.allocation'].create({ + 'employee_id': self.employee_emp_id, + 'allocation_type': 'accrual', + 'accrual_plan_id': self.accrual_plan.id, + 'holiday_status_id': self.leave_type.id, + 'date_from': date(2000, 1, 1), + 'number_of_days': 0, + }) + + allocation._process_accrual_plans() + + self.assertEqual(allocation.number_of_days, 0)