[FIX] hr_holidays: accross two years accrual plans period fail:
Steps to reproduce: - Create Accrual plan to add 3 days with frequency Yearly on 1 of January and days lost at the end of the year - Submit an Allocation request for this accrual plan starting more than 2 years ago - Run scheduled action "Accrual Time: Updates the number of time off" Current behavior: Allocation request calculation time off computes 0 hours Expected behavior: Allocation request calculation time off computes 3 hours for the period between the first of last year and the first of this year Explanation: With this modification there are two changes: 1) When the attribution day is the first of january, the nextcall set in the _end_of_the_year_accrual is the first day of next year meaning that no days are going to be computed for the last year period. We change that so that if the first of the year is the attribution day then the first of the year is the nextcall and the last call is computed accordingly. 2) If the period to compute the attributed days is acrros two years the begining of the period is not the first of the year anymore but the usual lastcall, this has an impact particularly on based on worked time accrual plans. opw-2948216 closes odoo/odoo#99728 X-original-commit: 88ba0e68c7878ac4b45cd7103bfecf9cfb567d4f Signed-off-by: Fockedey Martin (mafo) <mafo@odoo.com> Signed-off-by: Kevin Baptiste <kba@odoo.com>
This commit is contained in:
@@ -330,17 +330,21 @@ class HolidaysAllocation(models.Model):
|
||||
current_level = allocation._get_current_accrual_plan_level_id(first_day_this_year)[0]
|
||||
if not current_level:
|
||||
continue
|
||||
lastcall = current_level._get_previous_date(first_day_this_year)
|
||||
nextcall = current_level._get_next_date(first_day_this_year)
|
||||
if current_level.action_with_unused_accruals == 'lost':
|
||||
if lastcall == first_day_this_year:
|
||||
lastcall = current_level._get_previous_date(first_day_this_year - relativedelta(days=1))
|
||||
nextcall = first_day_this_year
|
||||
# Allocations are lost but number_of_days should not be lower than leaves_taken
|
||||
allocation.write({'number_of_days': allocation.leaves_taken, 'lastcall': first_day_this_year, 'nextcall': nextcall})
|
||||
allocation.write({'number_of_days': allocation.leaves_taken, 'lastcall': lastcall, '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': first_day_this_year, 'nextcall': nextcall})
|
||||
allocation.write({'number_of_days': number_of_days, 'lastcall': lastcall, 'nextcall': nextcall})
|
||||
|
||||
def _get_current_accrual_plan_level_id(self, date, level_ids=False):
|
||||
"""
|
||||
@@ -444,33 +448,24 @@ class HolidaysAllocation(models.Model):
|
||||
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)
|
||||
|
||||
# We have to check for end of year actions if it is within our period
|
||||
# since we can create retroactive allocations.
|
||||
if allocation.lastcall.year < allocation.nextcall.year and\
|
||||
current_level.action_with_unused_accruals == 'postponed' and\
|
||||
current_level.postpone_max_days > 0:
|
||||
# Compute number of days kept
|
||||
allocation_days = allocation.number_of_days - allocation.leaves_taken
|
||||
allowed_to_keep = max(0, current_level.postpone_max_days - allocation_days)
|
||||
number_of_days = min(allocation_days, current_level.postpone_max_days)
|
||||
allocation.number_of_days = number_of_days + allocation.leaves_taken
|
||||
total_gained_days = sum(days_added_per_level.values())
|
||||
days_added_per_level.clear()
|
||||
days_added_per_level[current_level] = min(total_gained_days, allowed_to_keep)
|
||||
gained_days = allocation._process_accrual_plan_level(
|
||||
current_level, period_start, allocation.lastcall, period_end, allocation.nextcall)
|
||||
days_added_per_level[current_level] += gained_days
|
||||
if current_level.maximum_leave > 0 and sum(days_added_per_level.values()) > current_level.maximum_leave:
|
||||
days_added_per_level[current_level] -= sum(days_added_per_level.values()) - current_level.maximum_leave
|
||||
# We have to check for end of year actions if it is within our period
|
||||
# since we can create retroactive allocations.
|
||||
if allocation.lastcall.year < allocation.nextcall.year and\
|
||||
(current_level.action_with_unused_accruals == 'lost' or\
|
||||
current_level.postpone_max_days > 0):
|
||||
after_period_gains = allocation._process_accrual_plan_level(
|
||||
current_level, period_start, allocation.nextcall + relativedelta(day=1, month=1),
|
||||
period_end, allocation.nextcall)
|
||||
if current_level.action_with_unused_accruals == 'postponed':
|
||||
# Compute number of days kept
|
||||
allocation_days = allocation.number_of_days - allocation.leaves_taken
|
||||
allowed_to_keep = max(0, current_level.postpone_max_days - allocation_days)
|
||||
number_of_days = min(allocation_days, current_level.postpone_max_days)
|
||||
allocation.number_of_days = number_of_days + allocation.leaves_taken
|
||||
total_gained_days = sum(days_added_per_level.values())
|
||||
days_added_per_level.clear()
|
||||
days_added_per_level[current_level] = min(total_gained_days - after_period_gains, allowed_to_keep)
|
||||
else:
|
||||
allocation.number_of_days = allocation.leaves_taken
|
||||
days_added_per_level.clear()
|
||||
days_added_per_level[current_level] += after_period_gains
|
||||
|
||||
allocation.lastcall = allocation.nextcall
|
||||
allocation.nextcall = nextcall
|
||||
|
||||
@@ -534,7 +534,7 @@ class TestAccrualAllocations(TestHrHolidaysCommon):
|
||||
accrual_cron.lastcall = datetime.date(2021, 9, 1)
|
||||
with freeze_time('2022-01-01'):
|
||||
allocation._update_accrual()
|
||||
self.assertEqual(allocation.number_of_days, 0, 'There number of days should be reset')
|
||||
self.assertEqual(allocation.number_of_days, 1, 'The number of days should be reset')
|
||||
|
||||
def test_unused_accrual_postponed(self):
|
||||
# 1 accrual with 2 levels and level transition after
|
||||
@@ -733,6 +733,36 @@ class TestAccrualAllocations(TestHrHolidaysCommon):
|
||||
allocation.action_validate()
|
||||
with freeze_time('2022-4-4'):
|
||||
allocation._update_accrual()
|
||||
self.assertEqual(allocation.number_of_days, 4, "Invalid number of days")
|
||||
|
||||
def test_accrual_lost_first_january(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': 0,
|
||||
'start_type': 'day',
|
||||
'added_value': 3,
|
||||
'added_value_type': 'days',
|
||||
'frequency': 'yearly',
|
||||
'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(2019, 1, 1),
|
||||
})
|
||||
allocation.action_confirm()
|
||||
allocation.action_validate()
|
||||
with freeze_time('2022-4-1'):
|
||||
allocation._update_accrual()
|
||||
self.assertEqual(allocation.number_of_days, 3, "Invalid number of days")
|
||||
|
||||
def test_accrual_maximum_leaves(self):
|
||||
|
||||
Reference in New Issue
Block a user