[FIX] hr_work_entry: make _error_checking faster

Calls to `_error_checking()` would look for every work entries between 2
dates, even if we were only modifying one employee's.

Because of that the leave creation on big production database would take
a long time.

Now the method allows for filtering to the employees.

task-3142610

closes odoo/odoo#110987

X-original-commit: f54b7c34bc89140e2d31f0b602911ec9cda3ed0d
Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
Signed-off-by: Kevin Baptiste <kba@odoo.com>
This commit is contained in:
Kevin Baptiste
2023-01-25 17:50:14 +01:00
parent 93ad98bc6f
commit d534bdc975
2 changed files with 20 additions and 8 deletions
+13 -5
View File
@@ -8,6 +8,7 @@ import itertools
from psycopg2 import OperationalError
from odoo import api, fields, models, tools, _
from odoo.osv import expression
class HrWorkEntry(models.Model):
@@ -182,18 +183,22 @@ class HrWorkEntry(models.Model):
if 'active' in vals:
vals['state'] = 'draft' if vals['active'] else 'cancelled'
with self._error_checking(skip=skip_check):
employee_ids = self.employee_id.ids
if 'employee_id' in vals and vals['employee_id']:
employee_ids += vals['employee_id']
with self._error_checking(skip=skip_check, employee_ids=employee_ids):
return super(HrWorkEntry, self).write(vals)
def unlink(self):
with self._error_checking():
employee_ids = self.employee_id.ids
with self._error_checking(employee_ids=employee_ids):
return super().unlink()
def _reset_conflicting_state(self):
self.filtered(lambda w: w.state == 'conflict').write({'state': 'draft'})
@contextmanager
def _error_checking(self, start=None, stop=None, skip=False):
def _error_checking(self, start=None, stop=None, skip=False, employee_ids=False):
"""
Context manager used for conflicts checking.
When exiting the context manager, conflicts are checked
@@ -209,11 +214,14 @@ class HrWorkEntry(models.Model):
start = start or min(self.mapped('date_start'), default=False)
stop = stop or max(self.mapped('date_stop'), default=False)
if not skip and start and stop:
work_entries = self.sudo().with_context(hr_work_entry_no_check=True).search([
domain = [
('date_start', '<', stop),
('date_stop', '>', start),
('state', 'not in', ('validated', 'cancelled')),
])
]
if employee_ids:
domain = expression.AND([domain, [('employee_id', 'in', list(employee_ids))]])
work_entries = self.sudo().with_context(hr_work_entry_no_check=True).search(domain)
work_entries._reset_conflicting_state()
yield
except OperationalError:
@@ -169,7 +169,10 @@ Contracts:
start = min(self.mapped('date_from') + [fields.Datetime.from_string(vals.get('date_from', False)) or datetime.max])
stop = max(self.mapped('date_to') + [fields.Datetime.from_string(vals.get('date_to', False)) or datetime.min])
with self.env['hr.work.entry']._error_checking(start=start, stop=stop, skip=skip_check):
employee_ids = self.employee_id.ids
if 'employee_id' in vals and vals['employee_id']:
employee_ids += vals['employee_id']
with self.env['hr.work.entry']._error_checking(start=start, stop=stop, skip=skip_check, employee_ids=employee_ids):
return super().write(vals)
@api.model_create_multi
@@ -178,13 +181,14 @@ Contracts:
stop_dates = [v.get('date_to') for v in vals_list if v.get('date_to')]
if any(vals.get('holiday_type', 'employee') == 'employee' and not vals.get('multi_employee', False) and not vals.get('employee_id', False) for vals in vals_list):
raise ValidationError(_("There is no employee set on the time off. Please make sure you're logged in the correct company."))
with self.env['hr.work.entry']._error_checking(start=min(start_dates, default=False), stop=max(stop_dates, default=False)):
employee_ids = {v['employee_id'] for v in vals_list if v.get('employee_id')}
with self.env['hr.work.entry']._error_checking(start=min(start_dates, default=False), stop=max(stop_dates, default=False), employee_ids=employee_ids):
return super().create(vals_list)
def action_confirm(self):
start = min(self.mapped('date_from'), default=False)
stop = max(self.mapped('date_to'), default=False)
with self.env['hr.work.entry']._error_checking(start=start, stop=stop):
with self.env['hr.work.entry']._error_checking(start=start, stop=stop, employee_ids=self.employee_id.ids):
return super().action_confirm()
def _get_leaves_on_public_holiday(self):