Skip to content
Snippets Groups Projects
Commit 4807ec38 authored by Yannick Tivisse's avatar Yannick Tivisse
Browse files

[FIX] hr_work_entry: Compute work entries duration in batch

X-original-commit: ae165f48178d89ad1b74961c7d4829f1ff5ca0c4
parent 53bacb11
No related branches found
No related tags found
No related merge requests found
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from collections import defaultdict
from contextlib import contextmanager
from dateutil.relativedelta import relativedelta
import itertools
......@@ -77,19 +78,36 @@ class HrWorkEntry(models.Model):
@api.depends('date_stop', 'date_start')
def _compute_duration(self):
durations = self._get_duration_batch()
for work_entry in self:
work_entry.duration = work_entry._get_duration(work_entry.date_start, work_entry.date_stop)
work_entry.duration = durations[work_entry.id]
@api.depends('date_start', 'duration')
def _compute_date_stop(self):
for work_entry in self.filtered(lambda w: w.date_start and w.duration):
work_entry.date_stop = work_entry.date_start + relativedelta(hours=work_entry.duration)
def _get_duration_batch(self):
result = {}
cached_periods = defaultdict(float)
for work_entry in self:
date_start = work_entry.date_start
date_stop = work_entry.date_stop
if not date_start or not date_stop:
result[work_entry.id] = 0.0
continue
if (date_start, date_stop) in cached_periods:
result[work_entry.id] = cached_periods[(date_start, date_stop)]
else:
dt = date_stop - date_start
duration = dt.days * 24 + dt.seconds / 3600 # Number of hours
cached_periods[(date_start, date_stop)] = duration
result[work_entry.id] = duration
return result
# YTI TODO: Remove me in master: Deprecated, use _get_duration_batch instead
def _get_duration(self, date_start, date_stop):
if not date_start or not date_stop:
return 0
dt = date_stop - date_start
return dt.days * 24 + dt.seconds / 3600 # Number of hours
return self._get_duration_batch()[self.id]
def action_validate(self):
"""
......
......@@ -73,19 +73,42 @@ class HrWorkEntry(models.Model):
continue
super(HrWorkEntry, work_entry)._compute_date_stop()
def _get_duration(self, date_start, date_stop):
if not date_start or not date_stop:
return 0
if self._get_duration_is_valid():
calendar = self.contract_id.resource_calendar_id
def _is_duration_computed_from_calendar(self):
self.ensure_one()
return self._get_duration_is_valid()
def _get_duration_batch(self):
super_work_entries = self.env['hr.work.entry']
result = {}
# {(date_start, date_stop): {calendar: employees}}
mapped_periods = defaultdict(lambda: defaultdict(lambda: self.env['hr.employee']))
for work_entry in self:
if not work_entry.date_start or not work_entry.date_stop or not work_entry._is_duration_computed_from_calendar():
super_work_entries |= work_entry
continue
date_start = work_entry.date_start
date_stop = work_entry.date_stop
calendar = work_entry.contract_id.resource_calendar_id
if not calendar:
return 0
employee = self.contract_id.employee_id
contract_data = employee._get_work_days_data_batch(
date_start, date_stop, compute_leaves=False, calendar=calendar
)[employee.id]
return contract_data.get('hours', 0)
return super()._get_duration(date_start, date_stop)
result[work_entry.id] = 0.0
continue
employee = work_entry.contract_id.employee_id
mapped_periods[(date_start, date_stop)][calendar] |= employee
# {(date_start, date_stop): {calendar: {'hours': foo}}}
mapped_contract_data = defaultdict(lambda: defaultdict(lambda: {'hours': 0.0}))
for (date_start, date_stop), employees_by_calendar in mapped_periods.items():
for calendar, employees in employees_by_calendar.items():
mapped_contract_data[(date_start, date_stop)][calendar] = employees._get_work_days_data_batch(
date_start, date_stop, compute_leaves=False, calendar=calendar)
result = super(HrWorkEntry, super_work_entries)._get_duration_batch()
for work_entry in self - super_work_entries:
date_start = work_entry.date_start
date_stop = work_entry.date_stop
calendar = work_entry.contract_id.resource_calendar_id
employee = work_entry.contract_id.employee_id
result[work_entry.id] = mapped_contract_data[(date_start, date_stop)][calendar][employee.id]['hours']
return result
@api.model
def _set_current_contract(self, vals):
......
......@@ -10,16 +10,8 @@ class HrWorkEntry(models.Model):
leave_id = fields.Many2one('hr.leave', string='Time Off')
leave_state = fields.Selection(related='leave_id.state')
def _get_duration(self, date_start, date_stop):
if not date_start or not date_stop:
return 0
if not self.work_entry_type_id and self.leave_id:
calendar = self.contract_id.resource_calendar_id
employee = self.contract_id.employee_id
contract_data = employee._get_work_days_data_batch(
date_start, date_stop, compute_leaves=False, calendar=calendar)[employee.id]
return contract_data.get('hours', 0)
return super()._get_duration(date_start, date_stop)
def _is_duration_computed_from_calendar(self):
return super()._is_duration_computed_from_calendar() or bool(not self.work_entry_type_id and self.leave_id)
def write(self, vals):
if 'state' in vals and vals['state'] == 'cancelled':
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment