Skip to content

Commit

Permalink
[FIX] hr_holidays: remove allocation_id on hr.leave
Browse files Browse the repository at this point in the history
As part of hr_holidays B2B, the holidays allowances were moved from hr_leave_type to hr_leave_allocation.
This didn't allow to take a leave longer than the maximum duration of an allocation. Also, despite all the
allocations could have enough days for a certain leave, it was not possible to use all available days without
splitting the leaves across the different allocations.

This commit moves the holidays allowance to the hr_leave_type to remediate the issues described above.

task-2834887

closes odoo#96545

Signed-off-by: phwa-odoo <phwa@odoo.com>
  • Loading branch information
Philippe Wauthy committed Aug 11, 2022
1 parent 1a8a6c3 commit 7eaacf4
Show file tree
Hide file tree
Showing 7 changed files with 201 additions and 193 deletions.
100 changes: 15 additions & 85 deletions addons/hr_holidays/models/hr_leave.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,9 +295,9 @@ def _auto_init(self):

@api.constrains('holiday_status_id', 'number_of_days')
def _check_allocation_duration(self):
for holiday in self:
if holiday.holiday_status_id.requires_allocation == 'yes' and holiday.holiday_allocation_id and holiday.number_of_days > holiday.holiday_allocation_id.number_of_days:
raise ValidationError(_("You have several allocations for those type and period.\nPlease split your request to fit in their number of days."))
# Deprecated as part of https://github.com/odoo/odoo/pull/96545
# TODO: remove in master
return

@api.depends_context('uid')
def _compute_description(self):
Expand Down Expand Up @@ -336,49 +336,9 @@ def _compute_state(self):

@api.depends('holiday_status_id.requires_allocation', 'validation_type', 'employee_id', 'date_from', 'date_to')
def _compute_from_holiday_status_id(self):
invalid_self = self.filtered(lambda leave: not leave.date_to or not leave.date_from)
if invalid_self:
invalid_self.update({'holiday_allocation_id': False})
self = self - invalid_self
if not self:
return
allocations = self.env['hr.leave.allocation'].search_read(
[
('holiday_status_id', 'in', self.holiday_status_id.ids),
('employee_id', 'in', self.employee_id.ids),
('state', '=', 'validate'),
'|',
('date_to', '>=', min(self.mapped('date_to'))),
'&',
('date_to', '=', False),
('date_from', '<=', max(self.mapped('date_from'))),
], ['id', 'date_from', 'date_to', 'holiday_status_id', 'employee_id', 'max_leaves', 'taken_leave_ids'], order="date_to, id"
)
allocations_dict = defaultdict(lambda: [])
for allocation in allocations:
allocation['taken_leaves'] = self.env['hr.leave'].browse(allocation.pop('taken_leave_ids'))\
.filtered(lambda leave: leave.state in ['confirm', 'validate', 'validate1'])
allocations_dict[(allocation['holiday_status_id'][0], allocation['employee_id'][0])].append(allocation)

for leave in self:
if leave.holiday_status_id.requires_allocation == 'yes' and leave.date_from and leave.date_to:
found_allocation = False
date_to = leave.date_to.replace(tzinfo=UTC).astimezone(timezone(leave.tz)).date()
date_from = leave.date_from.replace(tzinfo=UTC).astimezone(timezone(leave.tz)).date()
leave_unit = 'number_of_%s_display' % ('hours' if leave.leave_type_request_unit == 'hour' else 'days')
for allocation in allocations_dict[(leave.holiday_status_id.id, leave.employee_id.id)]:
date_to_check = allocation['date_to'] >= date_to if allocation['date_to'] else True
date_from_check = allocation['date_from'] <= date_from
if (date_to_check and date_from_check):
allocation_taken_leaves = allocation['taken_leaves'] - leave
allocation_taken_number_of_units = sum(allocation_taken_leaves.mapped(leave_unit))
leave_number_of_units = leave[leave_unit]
if allocation['max_leaves'] >= allocation_taken_number_of_units + leave_number_of_units:
found_allocation = allocation['id']
break
leave.holiday_allocation_id = self.env['hr.leave.allocation'].browse(found_allocation) if found_allocation else False
else:
leave.holiday_allocation_id = False
# Deprecated as part of https://github.com/odoo/odoo/pull/96545
# TODO: remove in master
self.holiday_allocation_id = False

@api.depends('request_date_from_period', 'request_hour_from', 'request_hour_to', 'request_date_from', 'request_date_to',
'request_unit_half', 'request_unit_hours', 'request_unit_custom', 'employee_id')
Expand Down Expand Up @@ -668,14 +628,14 @@ def _check_date(self):

@api.constrains('state', 'number_of_days', 'holiday_status_id')
def _check_holidays(self):
mapped_days = self.holiday_status_id.get_employees_days(self.employee_id.ids)
for holiday in self:
if holiday.holiday_type != 'employee' or not holiday.employee_id or not holiday.holiday_status_id or holiday.holiday_status_id.requires_allocation == 'no':
if holiday.holiday_type != 'employee' or not holiday.employee_id or holiday.holiday_status_id.requires_allocation == 'no':
continue
mapped_days = holiday.holiday_status_id.get_employees_days([holiday.employee_id.id], holiday.date_from)
leave_days = mapped_days[holiday.employee_id.id][holiday.holiday_status_id.id]
if float_compare(leave_days['remaining_leaves'], 0, precision_digits=2) == -1 or float_compare(leave_days['virtual_remaining_leaves'], 0, precision_digits=2) == -1:
raise ValidationError(_('The number of remaining time off is not sufficient for this time off type.\n'
'Please also check the time off waiting for validation.') + '\n- %s' % holiday.display_name)
'Please also check the time off waiting for validation.'))

@api.constrains('date_from', 'date_to', 'employee_id')
def _check_date_state(self):
Expand Down Expand Up @@ -803,43 +763,15 @@ def add_follower(self, employee_id):

@api.constrains('holiday_allocation_id')
def _check_allocation_id(self):
for leave in self:
if leave.holiday_type == 'employee' and not leave.multi_employee and\
leave.holiday_status_id.requires_allocation == 'yes' and not leave.holiday_allocation_id:
raise ValidationError(_(
'Could not find an allocation of type %(leave_type)s for the requested time period.',
leave_type=leave.holiday_status_id.display_name,
) + '\n- %s' % (leave.employee_id.name))
# Deprecated as part of https://github.com/odoo/odoo/pull/96545
# TODO: remove in master
return

@api.constrains('holiday_allocation_id', 'date_to', 'date_from')
def _check_leave_type_validity(self):
for leave in self:
vstart = leave.holiday_allocation_id.date_from
vstop = leave.holiday_allocation_id.date_to
dfrom = leave.date_from
dto = leave.date_to
if vstart and vstop:
if dfrom and dto and (dfrom.date() < vstart or dto.date() > vstop):
raise ValidationError(_(
'%(leave_type)s are only valid between %(start)s and %(end)s',
leave_type=leave.holiday_status_id.display_name,
start=vstart,
end=vstop
))
elif vstart:
if dfrom and (dfrom.date() < vstart):
raise ValidationError(_(
'%(leave_type)s are only valid starting from %(date)s',
leave_type=leave.holiday_status_id.display_name,
date=vstart
))
elif vstop:
if dto and (dto.date() > vstop):
raise ValidationError(_(
'%(leave_type)s are only valid until %(date)s',
leave_type=leave.holiday_status_id.display_name,
date=vstop
))
# Deprecated as part of https://github.com/odoo/odoo/pull/96545
# TODO: remove in master
return

def _check_double_validation_rules(self, employees, state):
if self.user_has_groups('hr_holidays.group_hr_holidays_manager'):
Expand Down Expand Up @@ -882,8 +814,6 @@ def create(self, vals_list):

holidays = super(HolidaysRequest, self.with_context(mail_create_nosubscribe=True)).create(vals_list)

holidays.filtered(lambda holiday: not holiday.holiday_allocation_id).with_user(SUPERUSER_ID)._compute_from_holiday_status_id()

for holiday in holidays:
if not self._context.get('leave_fast_create'):
# Everything that is done here must be done using sudo because we might
Expand Down
5 changes: 2 additions & 3 deletions addons/hr_holidays/models/hr_leave_allocation.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,11 +193,10 @@ def _compute_description_validity(self):

@api.depends('employee_id', 'holiday_status_id', 'taken_leave_ids.number_of_days', 'taken_leave_ids.state')
def _compute_leaves(self):
employee_days_per_allocation = self.holiday_status_id._get_employees_days_per_allocation(self.employee_id.ids)
for allocation in self:
allocation.max_leaves = allocation.number_of_hours_display if allocation.type_request_unit == 'hour' else allocation.number_of_days
allocation.leaves_taken = sum(taken_leave.number_of_hours_display if taken_leave.leave_type_request_unit == 'hour' else taken_leave.number_of_days\
for taken_leave in allocation.taken_leave_ids\
if taken_leave.state == 'validate')
allocation.leaves_taken = employee_days_per_allocation[allocation.employee_id.id][allocation.holiday_status_id][allocation]['leaves_taken']

@api.depends('number_of_days')
def _compute_number_of_days_display(self):
Expand Down
Loading

0 comments on commit 7eaacf4

Please sign in to comment.