[FIX] hr_holidays: fix banner and days count
In hr_holidays, the banner disappears when the number of days taken is more than the days allocated. Also, the count of the days is based on all existing allocations. This commit fixes the banner by allowing to display negative days remaining when there are more days taken than days allocated. It also fixes the count of the days by couting days only for active allocations. task-2983188 closes odoo/odoo#100452 X-original-commit: efb351f86a3645ad292fdaaa6b223ff80096b63c Signed-off-by: Kevin Baptiste <kba@odoo.com> Signed-off-by: phwa-odoo <phwa@odoo.com>
This commit is contained in:
@@ -229,7 +229,7 @@ class HolidaysType(models.Model):
|
||||
('holiday_status_id', 'in', self.ids)
|
||||
])
|
||||
|
||||
allocations = self.env['hr.leave.allocation'].search([
|
||||
allocations = self.env['hr.leave.allocation'].with_context(active_test=False).search([
|
||||
('employee_id', 'in', employee_ids),
|
||||
('state', 'in', ['validate']),
|
||||
('holiday_status_id', 'in', self.ids),
|
||||
@@ -328,6 +328,8 @@ class HolidaysType(models.Model):
|
||||
leave_unit = 'hours'
|
||||
if holiday_status_id.requires_allocation != 'no':
|
||||
for available_allocation in sorted_available_allocations:
|
||||
if available_allocation.date_to and available_allocation.date_to < leave.date_from.date():
|
||||
continue
|
||||
virtual_remaining_leaves = (available_allocation.number_of_days if leave_unit == 'days' else available_allocation.number_of_hours_display) - allocations_days_consumed[employee_id][holiday_status_id][available_allocation]['virtual_leaves_taken']
|
||||
max_leaves = min(virtual_remaining_leaves, leave_duration)
|
||||
days_consumed[available_allocation]['virtual_leaves_taken'] += max_leaves
|
||||
@@ -337,7 +339,6 @@ class HolidaysType(models.Model):
|
||||
if leave_duration > 0:
|
||||
# There are not enough allocation for the number of leaves
|
||||
days_consumed[False]['virtual_remaining_leaves'] -= leave_duration
|
||||
return allocations_days_consumed
|
||||
else:
|
||||
days_consumed[False]['virtual_leaves_taken'] += leave_duration
|
||||
if leave.state == 'validate':
|
||||
@@ -353,7 +354,10 @@ class HolidaysType(models.Model):
|
||||
fields.datetime.combine(date, time.max) + timedelta(days=5*365),
|
||||
self.env['hr.leave'])])
|
||||
search_date = date
|
||||
allocations_of_that_type = intervals._items[0][2].filtered(lambda a: a.date_to and a.state == 'validate' and a.date_to >= date)
|
||||
closest_allocations = self.env['hr.leave.allocation']
|
||||
for interval in intervals._items:
|
||||
closest_allocations |= interval[2]
|
||||
allocations_of_that_type = closest_allocations.filtered(lambda a: a.date_to and a.state == 'validate' and a.date_to >= date)
|
||||
allocations_sorted = sorted(allocations_of_that_type, key=lambda a: a.date_to)
|
||||
allocation_closest = allocations_sorted[0] if allocations_sorted else False
|
||||
allocations_days_consumed[employee_id][holiday_status_id][False]['closest_allocation_to_expire'] = allocation_closest
|
||||
@@ -361,6 +365,8 @@ class HolidaysType(models.Model):
|
||||
if future_allocation_interval[0].date() > search_date:
|
||||
continue
|
||||
for allocation in future_allocation_interval[2]:
|
||||
if not allocation.active:
|
||||
continue
|
||||
days_consumed = allocations_days_consumed[employee_id][holiday_status_id][allocation]
|
||||
if future_allocation_interval[1] != fields.datetime.combine(date, time.max) + timedelta(days=5*365):
|
||||
# Compute the remaining number of days/hours in the allocation only if it has an end date
|
||||
@@ -404,6 +410,9 @@ class HolidaysType(models.Model):
|
||||
} for employee_id in employee_ids
|
||||
}
|
||||
|
||||
if not date:
|
||||
date = fields.Date.to_date(self.env.context.get('default_date_from')) or fields.Date.context_today(self)
|
||||
|
||||
allocations_days_consumed = self._get_employees_days_per_allocation(employee_ids, date)
|
||||
|
||||
leave_keys = ['max_leaves', 'leaves_taken', 'remaining_leaves', 'virtual_remaining_leaves', 'virtual_leaves_taken']
|
||||
@@ -412,6 +421,8 @@ class HolidaysType(models.Model):
|
||||
for holiday_status_id in allocations_days_consumed[employee_id]:
|
||||
for allocation in allocations_days_consumed[employee_id][holiday_status_id]:
|
||||
if allocation:
|
||||
if allocation.date_to and (allocation.date_to < date or allocation.date_from > date):
|
||||
continue
|
||||
for leave_key in leave_keys:
|
||||
result[employee_id][holiday_status_id if isinstance(holiday_status_id, int) else holiday_status_id.id][leave_key] += allocations_days_consumed[employee_id][holiday_status_id][allocation][leave_key]
|
||||
else:
|
||||
@@ -419,6 +430,7 @@ class HolidaysType(models.Model):
|
||||
for leave_key in leave_keys:
|
||||
if allocations_days_consumed[employee_id][holiday_status_id][False].get(leave_key):
|
||||
result[employee_id][holiday_status_id if isinstance(holiday_status_id, int) else holiday_status_id.id][leave_key] = allocations_days_consumed[employee_id][holiday_status_id][False][leave_key]
|
||||
|
||||
return result
|
||||
|
||||
@api.model
|
||||
|
||||
@@ -62,6 +62,20 @@ class TestLeaveRequests(TestHrHolidaysCommon):
|
||||
cls.set_employee_create_date(cls.employee_emp_id, '2010-02-03 00:00:00')
|
||||
cls.set_employee_create_date(cls.employee_hruser_id, '2010-02-03 00:00:00')
|
||||
|
||||
def _check_holidays_count(self, holidays_count_result, ml, lt, rl, vrl, vlt, closest_allocation):
|
||||
self.assertEqual(
|
||||
holidays_count_result,
|
||||
{
|
||||
'closest_allocation_to_expire': closest_allocation,
|
||||
'max_leaves': ml,
|
||||
'leaves_taken': lt,
|
||||
'remaining_leaves': rl,
|
||||
'virtual_remaining_leaves': vrl,
|
||||
'virtual_leaves_taken': vlt,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@classmethod
|
||||
def set_employee_create_date(cls, _id, newdate):
|
||||
""" This method is a hack in order to be able to define/redefine the create_date
|
||||
@@ -799,16 +813,9 @@ class TestLeaveRequests(TestHrHolidaysCommon):
|
||||
'number_of_days': 3,
|
||||
})
|
||||
|
||||
self.assertEqual(
|
||||
self._check_holidays_count(
|
||||
self.holidays_type_2.get_employees_days([self.employee_emp_id])[self.employee_emp_id][self.holidays_type_2.id],
|
||||
{
|
||||
'closest_allocation_to_expire': allocation,
|
||||
'max_leaves': 5,
|
||||
'leaves_taken': 0,
|
||||
'remaining_leaves': 5,
|
||||
'virtual_remaining_leaves': 2,
|
||||
'virtual_leaves_taken': 3,
|
||||
}
|
||||
ml=5, lt=0, rl=5, vrl=2, vlt=3, closest_allocation=allocation,
|
||||
)
|
||||
|
||||
self.holidays_type_2.requires_allocation = 'no'
|
||||
@@ -823,32 +830,115 @@ class TestLeaveRequests(TestHrHolidaysCommon):
|
||||
|
||||
# The 5 allocation days are not consumed anymore
|
||||
# virtual_remaining_leaves reflect the total number of leave days taken
|
||||
self.assertEqual(
|
||||
self._check_holidays_count(
|
||||
self.holidays_type_2.get_employees_days([self.employee_emp_id])[self.employee_emp_id][self.holidays_type_2.id],
|
||||
{
|
||||
'closest_allocation_to_expire': allocation,
|
||||
'max_leaves': 5,
|
||||
'leaves_taken': 0,
|
||||
'remaining_leaves': 5,
|
||||
'virtual_remaining_leaves': 5,
|
||||
'virtual_leaves_taken': 6,
|
||||
}
|
||||
ml=5, lt=0, rl=5, vrl=5, vlt=6, closest_allocation=allocation,
|
||||
)
|
||||
|
||||
leave1.with_user(self.user_hrmanager_id).action_approve()
|
||||
leave2.with_user(self.user_hrmanager_id).action_approve()
|
||||
|
||||
# leaves_taken and virtual_leaves_taken reflect the total number of leave days taken
|
||||
self.assertEqual(
|
||||
self._check_holidays_count(
|
||||
self.holidays_type_2.get_employees_days([self.employee_emp_id])[self.employee_emp_id][self.holidays_type_2.id],
|
||||
{
|
||||
'closest_allocation_to_expire': allocation,
|
||||
'max_leaves': 5,
|
||||
'leaves_taken': 6,
|
||||
'remaining_leaves': 5,
|
||||
'virtual_remaining_leaves': 5,
|
||||
'virtual_leaves_taken': 6,
|
||||
}
|
||||
ml=5, lt=6, rl=5, vrl=5, vlt=6, closest_allocation=allocation,
|
||||
)
|
||||
|
||||
def test_archived_allocation(self):
|
||||
with freeze_time('2022-09-15'):
|
||||
allocation_2021 = self.env['hr.leave.allocation'].create({
|
||||
'name': 'Annual Time Off 2021',
|
||||
'employee_id': self.employee_emp_id,
|
||||
'holiday_status_id': self.holidays_type_2.id,
|
||||
'number_of_days': 10,
|
||||
'state': 'confirm',
|
||||
'date_from': '2021-06-01',
|
||||
'date_to': '2021-12-31',
|
||||
})
|
||||
allocation_2022 = self.env['hr.leave.allocation'].create({
|
||||
'name': 'Annual Time Off 2022',
|
||||
'employee_id': self.employee_emp_id,
|
||||
'holiday_status_id': self.holidays_type_2.id,
|
||||
'number_of_days': 20,
|
||||
'state': 'confirm',
|
||||
'date_from': '2022-01-01',
|
||||
'date_to': '2022-12-31',
|
||||
})
|
||||
allocation_2021.action_validate()
|
||||
allocation_2022.action_validate()
|
||||
|
||||
# Leave taken in 2021
|
||||
leave_2021 = self.env['hr.leave'].with_user(self.user_employee_id).create({
|
||||
'name': 'Holiday Request',
|
||||
'holiday_type': 'employee',
|
||||
'employee_id': self.employee_emp.id,
|
||||
'holiday_status_id': self.holidays_type_2.id,
|
||||
'date_from': datetime(2021, 8, 9, 0, 0, 0),
|
||||
'date_to': datetime(2021, 8, 13, 23, 59, 59),
|
||||
})
|
||||
leave_2021.with_user(self.user_hrmanager_id).action_approve()
|
||||
|
||||
# The holidays count only takes into account the valid allocations at that date
|
||||
self._check_holidays_count(
|
||||
self.holidays_type_2.get_employees_days([self.employee_emp_id], date=date(2021, 12, 1))[self.employee_emp_id][self.holidays_type_2.id],
|
||||
ml=10, lt=5, rl=5, vrl=5, vlt=5, closest_allocation=allocation_2021,
|
||||
)
|
||||
|
||||
# Virtual remaining leave is equal to 1 because there is only one day remaining in the allocation based on its validity
|
||||
self._check_holidays_count(
|
||||
self.holidays_type_2.get_employees_days([self.employee_emp_id], date=date(2021, 12, 31))[self.employee_emp_id][self.holidays_type_2.id],
|
||||
ml=10, lt=5, rl=5, vrl=1, vlt=5, closest_allocation=allocation_2021,
|
||||
)
|
||||
|
||||
leave_2022 = self.env['hr.leave'].with_user(self.user_employee_id).create({
|
||||
'name': 'Holiday Request',
|
||||
'holiday_type': 'employee',
|
||||
'employee_id': self.employee_emp.id,
|
||||
'holiday_status_id': self.holidays_type_2.id,
|
||||
'date_from': datetime(2022, 8, 9, 0, 0, 0),
|
||||
'date_to': datetime(2022, 8, 13, 23, 59, 59),
|
||||
})
|
||||
leave_2022.with_user(self.user_hrmanager_id).action_approve()
|
||||
|
||||
# The holidays count in 2022 is not affected by the first leave taken in 2021
|
||||
self._check_holidays_count(
|
||||
self.holidays_type_2.get_employees_days([self.employee_emp_id])[self.employee_emp_id][self.holidays_type_2.id],
|
||||
ml=20, lt=4, rl=16, vrl=16, vlt=4, closest_allocation=allocation_2022,
|
||||
)
|
||||
|
||||
# The holidays count in 2021 is not affected by the leave taken in 2022
|
||||
self._check_holidays_count(
|
||||
self.holidays_type_2.get_employees_days([self.employee_emp_id], date=date(2021, 12, 1))[self.employee_emp_id][self.holidays_type_2.id],
|
||||
ml=10, lt=5, rl=5, vrl=5, vlt=5, closest_allocation=allocation_2021,
|
||||
)
|
||||
|
||||
allocation_2021.active = False
|
||||
|
||||
# If the allocation is archived, the leaves taken are still counted on this allocation
|
||||
# but the max leaves and remaining leaves are not counted anymore
|
||||
self._check_holidays_count(
|
||||
self.holidays_type_2.get_employees_days([self.employee_emp_id], date=date(2021, 12, 1))[self.employee_emp_id][self.holidays_type_2.id],
|
||||
ml=0, lt=5, rl=0, vrl=0, vlt=5, closest_allocation=allocation_2021,
|
||||
)
|
||||
|
||||
# The holidays count in 2022 is not affected by the archived allocation in 2021
|
||||
self._check_holidays_count(
|
||||
self.holidays_type_2.get_employees_days([self.employee_emp_id])[self.employee_emp_id][self.holidays_type_2.id],
|
||||
ml=20, lt=4, rl=16, vrl=16, vlt=4, closest_allocation=allocation_2022,
|
||||
)
|
||||
|
||||
allocation_2021.active = True
|
||||
|
||||
# The holidays count in 2021 is back to what it was when the allocation was active
|
||||
self._check_holidays_count(
|
||||
self.holidays_type_2.get_employees_days([self.employee_emp_id], date=date(2021, 12, 1))[self.employee_emp_id][self.holidays_type_2.id],
|
||||
ml=10, lt=5, rl=5, vrl=5, vlt=5, closest_allocation=allocation_2021,
|
||||
)
|
||||
|
||||
# The holidays count in 2022 is still not affected by the allocation in 2021
|
||||
self._check_holidays_count(
|
||||
self.holidays_type_2.get_employees_days([self.employee_emp_id])[self.employee_emp_id][self.holidays_type_2.id],
|
||||
ml=20, lt=4, rl=16, vrl=16, vlt=4, closest_allocation=allocation_2022,
|
||||
)
|
||||
|
||||
def test_cancel_leave(self):
|
||||
|
||||
Reference in New Issue
Block a user