summaryrefslogtreecommitdiff
path: root/addons/hr_holidays/models
diff options
context:
space:
mode:
authorYannick Tivisse <yti@odoo.com>2020-05-19 09:18:00 +0000
committerYannick Tivisse <yti@odoo.com>2020-08-25 13:22:24 +0000
commit8c96a887d3f05680c923dcd44f9c70c0e5e0bd32 (patch)
treece00e88fb50d8642bcf550661db07d53210d3f59 /addons/hr_holidays/models
parent369375a69adc20a92075a89ef9557bf6b46cd605 (diff)
[FW][MERGE] resource,calendar,hr_holidays: Improve the performances
TL;DR ===== Improve performances with nearly a factor of 2. Use case, call action_validate on hr.leave for 100 employees - 1987 requests -> 844 requests - 1300 ms -> 700 ms Purpose ======= The first purpose of this commit is to add a test ensuring the number of request while creating a company leave for 100 employees, if 15 of them already have a leave during that period. It includes, the mass leave generation, and the conflicts resolutions. (Cancelling/Splitting the already existing one and adapting the dates accordingly). The second one is to reduce the number of request for this test. In term of requests, currently we have: - 5154 requests without bypassing the mail tracking + the activities management - 1987 requests when bypassing the mail post-process (this is the current value, the bypassing was already done several month ago) - 844 requests with all the optimization done in resource/calendar/hr_holidays In terms of execution time, we have a reduction from +- 1300 ms to call the method action_validate to +- 700 ms As the performances issues severity increases with the number of leaves to create and the real time access to the database, on the production base, we reduced the execution time to generate more than 500 hr.leaves from several minutes to 21 seconds. A fix to avoid deadlock was already made at https://github.com/odoo/enterprise/pull/10740/files Some contortions were made to avoid changing a signature method in a stable release and thus introducing for each method a second one, with the "batched" implementation, to keep a retro-compatibility for the existing custom code. But surely this could be cleaned in the master version. The old one will be deprecated while waiting to be removed in a few versions. closes odoo/odoo#56477 Taskid: 2256705 X-original-commit: 8820db912f9e8ca71a57d3b0d32d2020d35b963f Related: odoo/enterprise#12642 Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
Diffstat (limited to 'addons/hr_holidays/models')
-rw-r--r--addons/hr_holidays/models/hr_leave.py250
-rw-r--r--addons/hr_holidays/models/hr_leave_allocation.py13
-rw-r--r--addons/hr_holidays/models/hr_leave_type.py28
3 files changed, 162 insertions, 129 deletions
diff --git a/addons/hr_holidays/models/hr_leave.py b/addons/hr_holidays/models/hr_leave.py
index 2525ad737ac..fed3140b8a8 100644
--- a/addons/hr_holidays/models/hr_leave.py
+++ b/addons/hr_holidays/models/hr_leave.py
@@ -119,7 +119,7 @@ class HolidaysRequest(models.Model):
('refuse', 'Refused'),
('validate1', 'Second Approval'),
('validate', 'Approved')
- ], string='Status', compute='_compute_state', store=True, tracking=True, copy=False,
+ ], string='Status', compute='_compute_state', store=True, tracking=True, copy=False, readonly=False,
help="The status is set to 'To Submit', when a time off request is created." +
"\nThe status is 'To Approve', when time off request is confirmed by user." +
"\nThe status is 'Refused', when time off request is refused by manager." +
@@ -498,8 +498,9 @@ class HolidaysRequest(models.Model):
start_dt = start_dt.replace(tzinfo=UTC)
if not end_dt.tzinfo:
end_dt = end_dt.replace(tzinfo=UTC)
- intervals = calendar._attendance_intervals(start_dt, end_dt, holiday.employee_id.resource_id) \
- - calendar._leave_intervals(start_dt, end_dt, None) # Substract Global Leaves
+ resource = holiday.employee_id.resource_id
+ intervals = calendar._attendance_intervals_batch(start_dt, end_dt, resource)[resource.id] \
+ - calendar._leave_intervals_batch(start_dt, end_dt, None)[False] # Substract Global Leaves
number_of_hours = sum((stop - start).total_seconds() / 3600 for start, stop, dummy in intervals)
else:
number_of_hours = holiday._get_number_of_days(holiday.date_from, holiday.date_to, holiday.employee_id.id)['hours']
@@ -564,16 +565,19 @@ class HolidaysRequest(models.Model):
@api.constrains('state', 'number_of_days', 'holiday_status_id')
def _check_holidays(self):
+ mapped_days = self.mapped('holiday_status_id').get_employees_days(self.mapped('employee_id').ids)
for holiday in self:
if holiday.holiday_type != 'employee' or not holiday.employee_id or holiday.holiday_status_id.allocation_type == 'no':
continue
- leave_days = holiday.holiday_status_id.get_days(holiday.employee_id.id)[holiday.holiday_status_id.id]
+ 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.'))
@api.constrains('date_from', 'date_to', 'employee_id')
def _check_date_state(self):
+ if self.env.context.get('leave_skip_state_check'):
+ return
for holiday in self:
if holiday.state in ['cancel', 'refuse', 'validate1', 'validate']:
raise ValidationError(_("This modification is not allowed in the current state."))
@@ -582,7 +586,7 @@ class HolidaysRequest(models.Model):
""" Returns a float equals to the timedelta between two dates given as string."""
if employee_id:
employee = self.env['hr.employee'].browse(employee_id)
- return employee._get_work_days_data(date_from, date_to)
+ return employee._get_work_days_data_batch(date_from, date_to)[employee.id]
today_hours = self.env.company.resource_calendar_id.get_work_hours_count(
datetime.combine(date_from.date(), time.min),
@@ -730,43 +734,52 @@ class HolidaysRequest(models.Model):
# Is probably handled via ir.rule
raise AccessError(_('You don\'t have the rights to apply second approval on a time off request'))
- @api.model
- def create(self, values):
+ @api.model_create_multi
+ def create(self, vals_list):
""" Override to avoid automatic logging of creation """
if not self._context.get('leave_fast_create'):
- employee_id = values.get('employee_id', False)
- leave_type_id = values.get('holiday_status_id')
- leave_type = self.env['hr.leave.type'].browse(leave_type_id)
- # Handle automatic department_id
- if not values.get('department_id'):
- values.update({'department_id': self.env['hr.employee'].browse(employee_id).department_id.id})
-
- # Handle no_validation
- if leave_type.leave_validation_type == 'no_validation':
- values.update({'state': 'confirm'})
-
- # Handle double validation
- if leave_type.leave_validation_type == 'both':
- self._check_double_validation_rules(employee_id, values.get('state', False))
-
- holiday = super(HolidaysRequest, self.with_context(mail_create_nosubscribe=True)).create(values)
- if not self._context.get('leave_fast_create'):
- # Everything that is done here must be done using sudo because we might
- # have different create and write rights
- # eg : holidays_user can create a leave request with validation_type = 'manager' for someone else
- # but they can only write on it if they are leave_manager_id
- holiday_sudo = holiday.sudo()
- holiday_sudo.add_follower(employee_id)
- if holiday.validation_type == 'manager':
- holiday_sudo.message_subscribe(partner_ids=holiday.employee_id.leave_manager_id.partner_id.ids)
- if holiday.validation_type == 'no_validation':
- # Automatic validation should be done in sudo, because user might not have the rights to do it by himself
- holiday_sudo.action_validate()
- holiday_sudo.message_subscribe(partner_ids=[holiday._get_responsible_for_approval().partner_id.id])
- holiday_sudo.message_post(body=_("The time off has been automatically approved"), subtype_xmlid="mail.mt_comment") # Message from OdooBot (sudo)
- elif not self._context.get('import_file'):
- holiday_sudo.activity_update()
- return holiday
+ leave_types = self.env['hr.leave.type'].browse([values.get('holiday_status_id') for values in vals_list if values.get('holiday_status_id')])
+ mapped_validation_type = {leave_type.id: leave_type.leave_validation_type for leave_type in leave_types}
+
+ for values in vals_list:
+ employee_id = values.get('employee_id', False)
+ leave_type_id = values.get('holiday_status_id')
+ # Handle automatic department_id
+ if not values.get('department_id'):
+ values.update({'department_id': self.env['hr.employee'].browse(employee_id).department_id.id})
+
+ # Handle no_validation
+ if mapped_validation_type[leave_type_id] == 'no_validation':
+ values.update({'state': 'confirm'})
+
+ if 'state' not in values:
+ # To mimic the behavior of compute_state that was always triggered, as the field was readonly
+ values['state'] = 'confirm' if mapped_validation_type[leave_type_id] != 'no_validation' else 'draft'
+
+ # Handle double validation
+ if mapped_validation_type[leave_type_id] == 'both':
+ self._check_double_validation_rules(employee_id, values.get('state', False))
+
+ holidays = super(HolidaysRequest, self.with_context(mail_create_nosubscribe=True)).create(vals_list)
+
+ 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
+ # have different create and write rights
+ # eg : holidays_user can create a leave request with validation_type = 'manager' for someone else
+ # but they can only write on it if they are leave_manager_id
+ holiday_sudo = holiday.sudo()
+ holiday_sudo.add_follower(employee_id)
+ if holiday.validation_type == 'manager':
+ holiday_sudo.message_subscribe(partner_ids=holiday.employee_id.leave_manager_id.partner_id.ids)
+ if holiday.validation_type == 'no_validation':
+ # Automatic validation should be done in sudo, because user might not have the rights to do it by himself
+ holiday_sudo.action_validate()
+ holiday_sudo.message_subscribe(partner_ids=[holiday._get_responsible_for_approval().partner_id.id])
+ holiday_sudo.message_post(body=_("The time off has been automatically approved"), subtype_xmlid="mail.mt_comment") # Message from OdooBot (sudo)
+ elif not self._context.get('import_file'):
+ holiday_sudo.activity_update()
+ return holidays
def write(self, values):
is_officer = self.env.user.has_group('hr_holidays.group_hr_holidays_user') or self.env.is_superuser()
@@ -832,20 +845,15 @@ class HolidaysRequest(models.Model):
""" This method will create entry in resource calendar time off object at the time of holidays validated
:returns: created `resource.calendar.leaves`
"""
- vals_list = []
- for leave in self:
- date_from = fields.Datetime.from_string(leave.date_from)
- date_to = fields.Datetime.from_string(leave.date_to)
-
- vals_list.append({
- 'name': leave.name,
- 'date_from': fields.Datetime.to_string(date_from),
- 'holiday_id': leave.id,
- 'date_to': fields.Datetime.to_string(date_to),
- 'resource_id': leave.employee_id.resource_id.id,
- 'calendar_id': leave.employee_id.resource_calendar_id.id,
- 'time_type': leave.holiday_status_id.time_type,
- })
+ vals_list = [{
+ 'name': leave.name,
+ 'date_from': leave.date_from,
+ 'holiday_id': leave.id,
+ 'date_to': leave.date_to,
+ 'resource_id': leave.employee_id.resource_id.id,
+ 'calendar_id': leave.employee_id.resource_calendar_id.id,
+ 'time_type': leave.holiday_status_id.time_type,
+ } for leave in self]
return self.env['resource.calendar.leaves'].sudo().create(vals_list)
def _remove_resource_leave(self):
@@ -857,39 +865,52 @@ class HolidaysRequest(models.Model):
by creating a calendar event and a resource time off. """
holidays = self.filtered(lambda request: request.holiday_type == 'employee')
holidays._create_resource_leave()
- for holiday in holidays.filtered(lambda l: l.holiday_status_id.create_calendar_meeting):
- meeting_values = holiday._prepare_holidays_meeting_values()
- meeting = self.env['calendar.event'].with_context(no_mail_to_attendees=True, active_model=self._name).create(meeting_values)
- holiday.write({'meeting_id': meeting.id})
+ meeting_holidays = holidays.filtered(lambda l: l.holiday_status_id.create_calendar_meeting)
+ if meeting_holidays:
+ meeting_values = meeting_holidays._prepare_holidays_meeting_values()
+ meetings = self.env['calendar.event'].with_context(
+ no_mail_to_attendees=True,
+ active_model=self._name
+ ).create(meeting_values)
+ for holiday, meeting in zip(meeting_holidays, meetings):
+ holiday.meeting_id = meeting
def _prepare_holidays_meeting_values(self):
- self.ensure_one()
- calendar = self.employee_id.resource_calendar_id or self.env.company.resource_calendar_id
- if self.leave_type_request_unit == 'hour':
- meeting_name = _("%s on Time Off : %.2f hour(s)") % (self.employee_id.name or self.category_id.name, self.number_of_hours_display)
- else:
- meeting_name = _("%s on Time Off : %.2f day(s)") % (self.employee_id.name or self.category_id.name, self.number_of_days)
- meeting_values = {
- 'name': meeting_name,
- 'duration': self.number_of_days * (calendar.hours_per_day or HOURS_PER_DAY),
- 'description': self.notes,
- 'user_id': self.user_id.id,
- 'start': self.date_from,
- 'stop': self.date_to,
- 'allday': False,
- 'privacy': 'confidential',
- 'event_tz': self.user_id.tz,
- 'activity_ids': [(5, 0, 0)],
- }
- # Add the partner_id (if exist) as an attendee
- if self.user_id and self.user_id.partner_id:
- meeting_values['partner_ids'] = [
- (4, self.user_id.partner_id.id)]
- return meeting_values
+ result = []
+ company_calendar = self.env.company.resource_calendar_id
+ for holiday in self:
+ calendar = holiday.employee_id.resource_calendar_id or company_calendar
+ if holiday.leave_type_request_unit == 'hour':
+ meeting_name = _("%s on Time Off : %.2f hour(s)") % (holiday.employee_id.name or holiday.category_id.name, holiday.number_of_hours_display)
+ else:
+ meeting_name = _("%s on Time Off : %.2f day(s)") % (holiday.employee_id.name or holiday.category_id.name, holiday.number_of_days)
+ meeting_values = {
+ 'name': meeting_name,
+ 'duration': holiday.number_of_days * (calendar.hours_per_day or HOURS_PER_DAY),
+ 'description': holiday.notes,
+ 'user_id': holiday.user_id.id,
+ 'start': holiday.date_from,
+ 'stop': holiday.date_to,
+ 'allday': False,
+ 'privacy': 'confidential',
+ 'event_tz': holiday.user_id.tz,
+ 'activity_ids': [(5, 0, 0)],
+ }
+ # Add the partner_id (if exist) as an attendee
+ if holiday.user_id and holiday.user_id.partner_id:
+ meeting_values['partner_ids'] = [
+ (4, holiday.user_id.partner_id.id)]
+ result.append(meeting_values)
+ return result
+ # YTI TODO: Remove me in master
def _prepare_holiday_values(self, employee):
+ return self._prepare_employees_holiday_values(employee)[0]
+
+ def _prepare_employees_holiday_values(self, employees):
self.ensure_one()
- values = {
+ work_days_data = employees._get_work_days_data_batch(self.date_from, self.date_to)
+ return [{
'name': self.name,
'holiday_type': 'employee',
'holiday_status_id': self.holiday_status_id.id,
@@ -898,11 +919,11 @@ class HolidaysRequest(models.Model):
'request_date_from': self.date_from,
'request_date_to': self.date_to,
'notes': self.notes,
- 'number_of_days': employee._get_work_days_data(self.date_from, self.date_to)['days'],
+ 'number_of_days': work_days_data[employee.id]['days'],
'parent_id': self.id,
- 'employee_id': employee.id
- }
- return values
+ 'employee_id': employee.id,
+ 'state': 'validate',
+ } for employee in employees]
def action_draft(self):
if any(holiday.state not in ['confirm', 'refuse'] for holiday in self):
@@ -988,18 +1009,20 @@ class HolidaysRequest(models.Model):
if holiday.leave_type_request_unit != 'day' or any(l.leave_type_request_unit == 'hour' for l in conflicting_leaves):
raise ValidationError(_('You can not have 2 time off that overlaps on the same day.'))
+ # keep track of conflicting leaves states before refusal
+ target_states = {l.id: l.state for l in conflicting_leaves}
+ conflicting_leaves.action_refuse()
+ split_leaves_vals = []
for conflicting_leave in conflicting_leaves:
if conflicting_leave.leave_type_request_unit == 'half_day' and conflicting_leave.request_unit_half:
- conflicting_leave.action_refuse()
continue
+
# Leaves in days
- split_leaves = self.env['hr.leave']
- target_state = conflicting_leave.state
- conflicting_leave.action_refuse()
if conflicting_leave.date_from < holiday.date_from:
before_leave_vals = conflicting_leave.copy_data({
'date_from': conflicting_leave.date_from.date(),
'date_to': holiday.date_from.date() + timedelta(days=-1),
+ 'state': target_states[conflicting_leave.id],
})[0]
before_leave = self.env['hr.leave'].new(before_leave_vals)
before_leave._compute_date_from_to()
@@ -1015,48 +1038,39 @@ class HolidaysRequest(models.Model):
# new instead of create. As the leave is not actually created yet, the sql
# constraint didn't check date_from < date_to yet.
if before_leave.date_from < before_leave.date_to:
- split_leaves |= self.env['hr.leave'].with_context(
- tracking_disable=True,
- mail_activity_automation_skip=True,
- leave_fast_create=True
- ).create(before_leave._convert_to_write(before_leave._cache))
+ split_leaves_vals.append(before_leave._convert_to_write(before_leave._cache))
if conflicting_leave.date_to > holiday.date_to:
after_leave_vals = conflicting_leave.copy_data({
'date_from': holiday.date_to.date() + timedelta(days=1),
'date_to': conflicting_leave.date_to.date(),
+ 'state': target_states[conflicting_leave.id],
})[0]
after_leave = self.env['hr.leave'].new(after_leave_vals)
after_leave._compute_date_from_to()
# Could happen for part-time contract, that time off is not necessary
# anymore.
if after_leave.date_from < after_leave.date_to:
- split_leaves |= self.env['hr.leave'].with_context(
- tracking_disable=True,
- mail_activity_automation_skip=True,
- leave_fast_create=True
- ).create(after_leave._convert_to_write(after_leave._cache))
- for split_leave in split_leaves:
- if target_state == 'draft':
- continue
- if target_state == 'confirm' and split_leave.state == 'draft':
- split_leave.action_confirm()
- elif target_state == 'validate1':
- split_leave.action_confirm()
- split_leave.action_approve()
- elif target_state == 'validate':
- split_leave.action_confirm()
- split_leave.action_validate()
-
- values = [holiday._prepare_holiday_values(employee) for employee in employees]
+ split_leaves_vals.append(after_leave._convert_to_write(after_leave._cache))
+
+ split_leaves = self.env['hr.leave'].with_context(
+ tracking_disable=True,
+ mail_activity_automation_skip=True,
+ leave_fast_create=True,
+ leave_skip_state_check=True
+ ).create(split_leaves_vals)
+
+ split_leaves.filtered(lambda l: l.state in 'validate')._validate_leave_request()
+
+ values = holiday._prepare_employees_holiday_values(employees)
leaves = self.env['hr.leave'].with_context(
tracking_disable=True,
mail_activity_automation_skip=True,
leave_fast_create=True,
+ leave_skip_state_check=True,
).create(values)
- leaves.action_approve()
- # FIXME RLi: This does not make sense, only the parent should be in validation_type both
- if leaves and leaves[0].validation_type == 'both':
- leaves.action_validate()
+
+ leaves._validate_leave_request()
+
employee_requests = self.filtered(lambda hol: hol.holiday_type == 'employee')
employee_requests._validate_leave_request()
if not self.env.context.get('leave_fast_create'):
@@ -1230,5 +1244,5 @@ class HolidaysRequest(models.Model):
dfrom = datetime.combine(fields.Date.from_string(date_from), time.min).replace(tzinfo=UTC)
dto = datetime.combine(fields.Date.from_string(date_to), time.max).replace(tzinfo=UTC)
- works = {d[0].date() for d in calendar._work_intervals(dfrom, dto)}
+ works = {d[0].date() for d in calendar._work_intervals_batch(dfrom, dto)[False]}
return {fields.Date.to_string(day.date()): (day.date() not in works) for day in rrule(DAILY, dfrom, until=dto)}
diff --git a/addons/hr_holidays/models/hr_leave_allocation.py b/addons/hr_holidays/models/hr_leave_allocation.py
index a71917c9044..82266cc7ea5 100644
--- a/addons/hr_holidays/models/hr_leave_allocation.py
+++ b/addons/hr_holidays/models/hr_leave_allocation.py
@@ -197,8 +197,15 @@ class HolidaysAllocation(models.Model):
if period_start <= start_date:
period_start = start_date
- worked = holiday.employee_id._get_work_days_data(period_start, period_end, domain=[('holiday_id.holiday_status_id.unpaid', '=', True), ('time_type', '=', 'leave')])['days']
- left = holiday.employee_id._get_leave_days_data(period_start, period_end, domain=[('holiday_id.holiday_status_id.unpaid', '=', True), ('time_type', '=', 'leave')])['days']
+ employee = holiday.employee_id
+ worked = employee._get_work_days_data_batch(
+ period_start, period_end,
+ domain=[('holiday_id.holiday_status_id.unpaid', '=', True), ('time_type', '=', 'leave')]
+ )[employee.id]['days']
+ left = employee._get_leave_days_data_batch(
+ period_start, period_end,
+ domain=[('holiday_id.holiday_status_id.unpaid', '=', True), ('time_type', '=', 'leave')]
+ )[employee.id]['days']
prorata = worked / (left + worked) if worked else 0
days_to_give = holiday.number_per_interval
@@ -206,7 +213,7 @@ class HolidaysAllocation(models.Model):
# As we encode everything in days in the database we need to convert
# the number of hours into days for this we use the
# mean number of hours set on the employee's calendar
- days_to_give = days_to_give / (holiday.employee_id.resource_calendar_id.hours_per_day or HOURS_PER_DAY)
+ days_to_give = days_to_give / (employee.resource_calendar_id.hours_per_day or HOURS_PER_DAY)
values['number_of_days'] = holiday.number_of_days + days_to_give * prorata
if holiday.accrual_limit > 0:
diff --git a/addons/hr_holidays/models/hr_leave_type.py b/addons/hr_holidays/models/hr_leave_type.py
index 772cde2ee93..48baf174ab6 100644
--- a/addons/hr_holidays/models/hr_leave_type.py
+++ b/addons/hr_holidays/models/hr_leave_type.py
@@ -188,24 +188,37 @@ class HolidaysType(models.Model):
return [('id', 'in', valid_leave_types.ids)]
+ # YTI TODO: Remove me in master
def get_days(self, employee_id):
- # need to use `dict` constructor to create a dict per id
- result = dict((id, dict(max_leaves=0, leaves_taken=0, remaining_leaves=0, virtual_remaining_leaves=0, virtual_leaves_taken=0)) for id in self.ids)
+ return self.get_employees_days([employee_id])[employee_id]
+
+ def get_employees_days(self, employee_ids):
+ result = {
+ employee_id: {
+ leave_type.id: {
+ 'max_leaves': 0,
+ 'leaves_taken': 0,
+ 'remaining_leaves': 0,
+ 'virtual_remaining_leaves': 0,
+ 'virtual_leaves_taken': 0,
+ } for leave_type in self
+ } for employee_id in employee_ids
+ }
requests = self.env['hr.leave'].search([
- ('employee_id', '=', employee_id),
+ ('employee_id', 'in', employee_ids),
('state', 'in', ['confirm', 'validate1', 'validate']),
('holiday_status_id', 'in', self.ids)
])
allocations = self.env['hr.leave.allocation'].search([
- ('employee_id', '=', employee_id),
+ ('employee_id', 'in', employee_ids),
('state', 'in', ['confirm', 'validate1', 'validate']),
('holiday_status_id', 'in', self.ids)
])
for request in requests:
- status_dict = result[request.holiday_status_id.id]
+ status_dict = result[request.employee_id.id][request.holiday_status_id.id]
status_dict['virtual_remaining_leaves'] -= (request.number_of_hours_display
if request.leave_type_request_unit == 'hour'
else request.number_of_days)
@@ -221,7 +234,7 @@ class HolidaysType(models.Model):
else request.number_of_days)
for allocation in allocations.sudo():
- status_dict = result[allocation.holiday_status_id.id]
+ status_dict = result[allocation.employee_id.id][allocation.holiday_status_id.id]
if allocation.state == 'validate':
# note: add only validated allocation even for the virtual
# count; otherwise pending then refused allocation allow
@@ -235,7 +248,6 @@ class HolidaysType(models.Model):
status_dict['remaining_leaves'] += (allocation.number_of_hours_display
if allocation.type_request_unit == 'hour'
else allocation.number_of_days)
-
return result
@api.model
@@ -265,7 +277,7 @@ class HolidaysType(models.Model):
employee_id = self._get_contextual_employee_id()
if employee_id:
- data_days = self.get_days(employee_id)
+ data_days = self.get_employees_days([employee_id])[employee_id]
for holiday_status in self:
result = data_days.get(holiday_status.id, {})