summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjem-odoo <jem@openerp.com>2018-12-03 12:38:42 +0000
committerjem-odoo <jem@openerp.com>2019-08-13 12:16:26 +0000
commitf499166df0a6392c7a74d4e09d02a946089c4b0a (patch)
tree3194de4a7b2099f724d6fc6cfc8b3849322c71d6
parentf9fafcdcfbbb562d61ad85c99729d921be2aa98d (diff)
[REF] resource: move code from mixin to calendar
This commit simply moves methods from the resource mixin to the calendar, so it can be use without having a resource. Indeed, in some case, we want to know the duration (in days and hours) according to a working calendar without any resource attached (typically services using a working calendar). Task-37561
-rw-r--r--addons/resource/models/resource.py71
-rw-r--r--addons/resource/models/resource_mixin.py49
2 files changed, 74 insertions, 46 deletions
diff --git a/addons/resource/models/resource.py b/addons/resource/models/resource.py
index 15c39e25792..ea84de93764 100644
--- a/addons/resource/models/resource.py
+++ b/addons/resource/models/resource.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
+from collections import defaultdict
import math
from datetime import datetime, time, timedelta
from dateutil.relativedelta import relativedelta
@@ -14,12 +15,15 @@ from odoo.addons.base.models.res_partner import _tz_get
from odoo.exceptions import ValidationError
from odoo.osv import expression
from odoo.tools.float_utils import float_round
-from odoo.tools import date_utils
+
+from odoo.tools import date_utils, float_utils
# Default hour per day value. The one should
# only be used when the one from the calendar
# is not available.
HOURS_PER_DAY = 8
+# This will generate 16th of days
+ROUNDING_FACTOR = 16
def make_aware(dt):
@@ -397,6 +401,45 @@ class ResourceCalendar(models.Model):
self._leave_intervals(start_dt, end_dt, resource, domain))
# --------------------------------------------------
+ # Private Methods / Helpers
+ # --------------------------------------------------
+
+ def _get_days_data(self, intervals, day_total):
+ """
+ helper function to compute duration of `intervals`
+ expressed in days and hours.
+ `day_total` is a dict {date: n_hours} with the number of hours for each day.
+ """
+ day_hours = defaultdict(float)
+ for start, stop, meta in intervals:
+ day_hours[start.date()] += (stop - start).total_seconds() / 3600
+
+ # compute number of days as quarters
+ days = sum(
+ float_utils.round(ROUNDING_FACTOR * day_hours[day] / day_total[day]) / ROUNDING_FACTOR
+ for day in day_hours
+ )
+ return {
+ 'days': days,
+ 'hours': sum(day_hours.values()),
+ }
+
+ def _get_day_total(self, from_datetime, to_datetime, resource=None):
+ """
+ @return dict with hours of attendance in each day between `from_datetime` and `to_datetime`
+ """
+ self.ensure_one()
+ # total hours per day: retrieve attendances with one extra day margin,
+ # in order to compute the total hours on the first and last days
+ from_full = from_datetime - timedelta(days=1)
+ to_full = to_datetime + timedelta(days=1)
+ intervals = self._attendance_intervals(from_full, to_full, resource=resource)
+ day_total = defaultdict(float)
+ for start, stop, meta in intervals:
+ day_total[start.date()] += (stop - start).total_seconds() / 3600
+ return day_total
+
+ # --------------------------------------------------
# External API
# --------------------------------------------------
@@ -426,6 +469,32 @@ class ResourceCalendar(models.Model):
for start, stop, meta in intervals
)
+ def get_work_duration_data(self, from_datetime, to_datetime, compute_leaves=True, domain=None):
+ """
+ Get the working duration (in days and hours) for a given period, only
+ based on the current calendar. This method does not use resource to
+ compute it.
+
+ `domain` is used in order to recognise the leaves to take,
+ None means default value ('time_type', '=', 'leave')
+
+ Returns a dict {'days': n, 'hours': h} containing the
+ quantity of working time expressed as days and as hours.
+ """
+ # naive datetimes are made explicit in UTC
+ from_datetime, dummy = make_aware(from_datetime)
+ to_datetime, dummy = make_aware(to_datetime)
+
+ day_total = self._get_day_total(from_datetime, to_datetime)
+
+ # actual hours per day
+ if compute_leaves:
+ intervals = self._work_intervals(from_datetime, to_datetime, domain=domain)
+ else:
+ intervals = self._attendance_intervals(from_datetime, to_datetime)
+
+ return self._get_days_data(intervals, day_total)
+
def plan_hours(self, hours, day_dt, compute_leaves=False, domain=None, resource=None):
"""
`compute_leaves` controls whether or not this method is taking into
diff --git a/addons/resource/models/resource_mixin.py b/addons/resource/models/resource_mixin.py
index 46caea0c24b..1358ffd1f7a 100644
--- a/addons/resource/models/resource_mixin.py
+++ b/addons/resource/models/resource_mixin.py
@@ -2,14 +2,9 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from collections import defaultdict
-from datetime import timedelta
from pytz import utc
from odoo import api, fields, models
-from odoo.tools import float_utils
-
-# This will generate 16th of days
-ROUNDING_FACTOR = 16
def timezone_datetime(time):
@@ -58,41 +53,6 @@ class ResourceMixin(models.AbstractModel):
default['resource_calendar_id'] = resource.calendar_id.id
return super(ResourceMixin, self).copy_data(default)
- def _get_days_data(self, intervals, day_total):
- """
- helper function to compute duration of `intervals`
- expressed in days and hours.
- `day_total` is a dict {date: n_hours} with the number of hours for each day.
- """
- day_hours = defaultdict(float)
- for start, stop, meta in intervals:
- day_hours[start.date()] += (stop - start).total_seconds() / 3600
-
- # compute number of days as quarters
- days = sum(
- float_utils.round(ROUNDING_FACTOR * day_hours[day] / day_total[day]) / ROUNDING_FACTOR
- for day in day_hours
- )
- return {
- 'days': days,
- 'hours': sum(day_hours.values()),
- }
-
- def _get_day_total(self, from_datetime, to_datetime, calendar, resource):
- """
- :return: dict with hours of attendance in each day between `from_datetime` and `to_datetime`
- """
-
- # total hours per day: retrieve attendances with one extra day margin,
- # in order to compute the total hours on the first and last days
- from_full = from_datetime - timedelta(days=1)
- to_full = to_datetime + timedelta(days=1)
- intervals = calendar._attendance_intervals(from_full, to_full, resource)
- day_total = defaultdict(float)
- for start, stop, meta in intervals:
- day_total[start.date()] += (stop - start).total_seconds() / 3600
- return day_total
-
def _get_work_days_data(self, from_datetime, to_datetime, compute_leaves=True, calendar=None, domain=None):
"""
By default the resource calendar is used, but it can be
@@ -111,7 +71,7 @@ class ResourceMixin(models.AbstractModel):
from_datetime = timezone_datetime(from_datetime)
to_datetime = timezone_datetime(to_datetime)
- day_total = self._get_day_total(from_datetime, to_datetime, calendar, resource)
+ day_total = calendar._get_day_total(from_datetime, to_datetime, resource)
# actual hours per day
if compute_leaves:
@@ -119,7 +79,7 @@ class ResourceMixin(models.AbstractModel):
else:
intervals = calendar._attendance_intervals(from_datetime, to_datetime, resource)
- return self._get_days_data(intervals, day_total)
+ return calendar._get_days_data(intervals, day_total)
def _get_leave_days_data(self, from_datetime, to_datetime, calendar=None, domain=None):
"""
@@ -139,14 +99,13 @@ class ResourceMixin(models.AbstractModel):
from_datetime = timezone_datetime(from_datetime)
to_datetime = timezone_datetime(to_datetime)
- day_total = self._get_day_total(from_datetime, to_datetime, calendar, resource)
+ day_total = calendar._get_day_total(from_datetime, to_datetime, resource)
# compute actual hours per day
attendances = calendar._attendance_intervals(from_datetime, to_datetime, resource)
leaves = calendar._leave_intervals(from_datetime, to_datetime, resource, domain)
- return self._get_days_data(attendances & leaves, day_total)
-
+ return calendar._get_days_data(attendances & leaves, day_total)
def list_work_time_per_day(self, from_datetime, to_datetime, calendar=None, domain=None):
"""