summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRomainLibert <rli@odoo.com>2018-02-01 09:46:32 +0100
committerRomainLibert <rli@odoo.com>2018-02-19 10:43:25 +0100
commit6d870463d020c6d66ec60fa9ded6ffafbdbd4aa3 (patch)
tree2b184b7e9bd4e2e03e95c355b62aec0212c1606b
parent813065cb5b72fe1b5c43704377afd7e1a96487db (diff)
[IMP] resource: Add possibility to pass in a domain
It will enable to retrieve data from the resource module based on a domain that we pass to the model. It can be used in order to filter on certain leave types only. * In resource_mixin and resource add a way to use a domain in order to filter the leaves * In resource_mixin add a method to get the work/leaves hours count
-rw-r--r--addons/resource/models/resource.py55
-rw-r--r--addons/resource/models/resource_mixin.py54
-rw-r--r--addons/resource/tests/test_resource.py42
3 files changed, 110 insertions, 41 deletions
diff --git a/addons/resource/models/resource.py b/addons/resource/models/resource.py
index c5c010374c5..6bba1a1911a 100644
--- a/addons/resource/models/resource.py
+++ b/addons/resource/models/resource.py
@@ -291,7 +291,7 @@ class ResourceCalendar(models.Model):
return day_date + relativedelta(days=days)
@api.multi
- def _get_leave_intervals(self, resource_id=None, start_datetime=None, end_datetime=None):
+ def _get_leave_intervals(self, resource_id=None, start_datetime=None, end_datetime=None, domain=None):
"""Get the leaves of the calendar. Leaves can be filtered on the resource,
and on a start and end datetime.
@@ -303,16 +303,18 @@ class ResourceCalendar(models.Model):
:return list leaves: list of time intervals """
self.ensure_one()
if resource_id:
- domain = ['|', ('resource_id', '=', resource_id), ('resource_id', '=', False)]
+ search_domain = ['|', ('resource_id', '=', resource_id), ('resource_id', '=', False)]
else:
- domain = [('resource_id', '=', False)]
+ search_domain = [('resource_id', '=', False)]
if start_datetime:
# domain += [('date_to', '>', fields.Datetime.to_string(to_naive_utc(start_datetime, self.env.user)))]
- domain += [('date_to', '>', fields.Datetime.to_string(start_datetime + timedelta(days=-1)))]
+ search_domain += [('date_to', '>', fields.Datetime.to_string(start_datetime + timedelta(days=-1)))]
if end_datetime:
# domain += [('date_from', '<', fields.Datetime.to_string(to_naive_utc(end_datetime, self.env.user)))]
- domain += [('date_from', '<', fields.Datetime.to_string(end_datetime + timedelta(days=1)))]
- leaves = self.env['resource.calendar.leaves'].search(domain + [('calendar_id', '=', self.id)])
+ search_domain += [('date_from', '<', fields.Datetime.to_string(end_datetime + timedelta(days=1)))]
+ if domain:
+ search_domain += domain
+ leaves = self.env['resource.calendar.leaves'].search(search_domain + [('calendar_id', '=', self.id)])
filtered_leaves = self.env['resource.calendar.leaves']
for leave in leaves:
@@ -343,7 +345,7 @@ class ResourceCalendar(models.Model):
yield self._interval_new(dt_f, dt_t, {'attendances': calendar_working_day})
@api.multi
- def _get_day_work_intervals(self, day_date, start_time=None, end_time=None, compute_leaves=False, resource_id=None):
+ def _get_day_work_intervals(self, day_date, start_time=None, end_time=None, compute_leaves=False, resource_id=None, domain=None):
""" Get the working intervals of the day given by day_date based on
current calendar. Input should be given in current user timezone and
output is given in naive UTC, ready to be used by the orm or webclient.
@@ -371,7 +373,8 @@ class ResourceCalendar(models.Model):
leaves = self._get_leave_intervals(
resource_id=resource_id,
start_datetime=datetime.datetime.combine(day_date, start_time),
- end_datetime=datetime.datetime.combine(day_date, end_time))
+ end_datetime=datetime.datetime.combine(day_date, end_time),
+ domain=domain)
working_intervals = [
sub_interval
for interval in working_intervals
@@ -383,7 +386,7 @@ class ResourceCalendar(models.Model):
to_naive_utc(interval[1], self.env.user),
interval[2]) for interval in working_intervals]
- def _get_day_leave_intervals(self, day_date, start_time, end_time, resource_id):
+ def _get_day_leave_intervals(self, day_date, start_time, end_time, resource_id, domain=None):
""" Get the leave intervals of the day given by day_date based on current
calendar. Input should be given in current user timezone and
output is given in naive UTC, ready to be used by the orm or webclient.
@@ -406,7 +409,8 @@ class ResourceCalendar(models.Model):
leaves_intervals = self._get_leave_intervals(
resource_id=resource_id,
start_datetime=datetime.datetime.combine(day_date, start_time),
- end_datetime=datetime.datetime.combine(day_date, end_time))
+ end_datetime=datetime.datetime.combine(day_date, end_time),
+ domain=domain)
final_intervals = [i for i in
[self._interval_and(leave_interval, work_interval)
@@ -423,7 +427,7 @@ class ResourceCalendar(models.Model):
# Main computation API
# --------------------------------------------------
- def _iter_work_intervals(self, start_dt, end_dt, resource_id, compute_leaves=True):
+ def _iter_work_intervals(self, start_dt, end_dt, resource_id, compute_leaves=True, domain=None):
""" Lists the current resource's work intervals between the two provided
datetimes (inclusive) expressed in UTC, for each worked day. """
if not end_dt:
@@ -448,11 +452,12 @@ class ResourceCalendar(models.Model):
start_time=start_time,
end_time=end_time,
compute_leaves=compute_leaves,
- resource_id=resource_id)
+ resource_id=resource_id,
+ domain=domain)
if intervals:
yield intervals
- def _iter_leave_intervals(self, start_dt, end_dt, resource_id):
+ def _iter_leave_intervals(self, start_dt, end_dt, resource_id, domain=None):
""" Lists the current resource's leave intervals between the two provided
datetimes (inclusive) expressed in UTC. """
if not end_dt:
@@ -476,22 +481,23 @@ class ResourceCalendar(models.Model):
day.date(),
start_time,
end_time,
- resource_id)
+ resource_id,
+ domain=domain)
if intervals:
yield intervals
- def _iter_work_hours_count(self, from_datetime, to_datetime, resource_id):
+ def _iter_work_hours_count(self, from_datetime, to_datetime, resource_id, domain=None):
""" Lists the current resource's work hours count between the two provided
datetime expressed in naive UTC. """
- for interval in self._iter_work_intervals(from_datetime, to_datetime, resource_id):
+ for interval in self._iter_work_intervals(from_datetime, to_datetime, resource_id, domain=domain):
td = timedelta()
for work_interval in interval:
td += work_interval[1] - work_interval[0]
yield (interval[0][0].date(), td.total_seconds() / 3600.0)
- def _iter_work_days(self, from_date, to_date, resource_id):
+ def _iter_work_days(self, from_date, to_date, resource_id, domain=None):
""" Lists the current resource's work days between the two provided
dates (inclusive) expressed in naive UTC.
@@ -507,7 +513,7 @@ class ResourceCalendar(models.Model):
for interval in self._iter_work_intervals(
datetime.datetime(from_date.year, from_date.month, from_date.day),
datetime.datetime(to_date.year, to_date.month, to_date.day),
- resource_id):
+ resource_id, domain=domain):
yield interval[0][0].date()
@api.multi
@@ -519,11 +525,11 @@ class ResourceCalendar(models.Model):
return bool(next(self._iter_work_days(date, date, resource_id), False))
@api.multi
- def get_work_hours_count(self, start_dt, end_dt, resource_id, compute_leaves=True):
+ def get_work_hours_count(self, start_dt, end_dt, resource_id, compute_leaves=True, domain=None):
""" Count number of work hours between two datetimes. For compute_leaves,
resource_id: see _get_day_work_intervals. """
res = timedelta()
- for intervals in self._iter_work_intervals(start_dt, end_dt, resource_id, compute_leaves=compute_leaves):
+ for intervals in self._iter_work_intervals(start_dt, end_dt, resource_id, compute_leaves=compute_leaves, domain=domain):
for interval in intervals:
res += interval[1] - interval[0]
return res.total_seconds() / 3600.0
@@ -533,7 +539,7 @@ class ResourceCalendar(models.Model):
# --------------------------------------------------
@api.multi
- def _schedule_hours(self, hours, day_dt, compute_leaves=False, resource_id=None):
+ def _schedule_hours(self, hours, day_dt, compute_leaves=False, resource_id=None, domain=None):
""" Schedule hours of work, using a calendar and an optional resource to
compute working and leave days. This method can be used backwards, i.e.
scheduling days before a deadline. For compute_leaves, resource_id:
@@ -555,7 +561,7 @@ class ResourceCalendar(models.Model):
day_dt_tz = to_naive_user_tz(day_dt, self.env.user)
current_datetime = day_dt_tz
- call_args = dict(compute_leaves=compute_leaves, resource_id=resource_id)
+ call_args = dict(compute_leaves=compute_leaves, resource_id=resource_id, domain=domain)
while float_compare(remaining_hours, 0.0, precision_digits=2) in (1, 0) and iterations < 1000:
if backwards:
@@ -595,7 +601,7 @@ class ResourceCalendar(models.Model):
return False
@api.multi
- def _schedule_days(self, days, day_dt, compute_leaves=False, resource_id=None):
+ def _schedule_days(self, days, day_dt, compute_leaves=False, resource_id=None, domain=None):
"""Schedule days of work, using a calendar and an optional resource to
compute working and leave days. This method can be used backwards, i.e.
scheduling days before a deadline. For compute_leaves, resource_id:
@@ -619,7 +625,8 @@ class ResourceCalendar(models.Model):
while planned_days < abs(days) and iterations < 100:
working_intervals = self._get_day_work_intervals(
current_datetime.date(),
- compute_leaves=compute_leaves, resource_id=resource_id)
+ compute_leaves=compute_leaves, resource_id=resource_id,
+ domain=domain)
if not self or working_intervals: # no calendar -> no working hours, but day is considered as worked
planned_days += 1
intervals += working_intervals
diff --git a/addons/resource/models/resource_mixin.py b/addons/resource/models/resource_mixin.py
index 416bd2875e7..20a641ede26 100644
--- a/addons/resource/models/resource_mixin.py
+++ b/addons/resource/models/resource_mixin.py
@@ -41,19 +41,25 @@ class ResourceMixin(models.AbstractModel):
default['resource_calendar_id'] = resource.calendar_id.id
return super(ResourceMixin, self).copy_data(default)
- def get_work_days_count(self, from_datetime, to_datetime, calendar=None):
+ def get_work_days_count(self, from_datetime, to_datetime, calendar=None, domain=None):
""" Return the number of work days for the resource, taking into account
leaves. An optional calendar can be given in case multiple calendars can
be used on the resource. """
- return self.get_work_days_data(from_datetime, to_datetime, calendar=calendar)['days']
+ return self.get_work_days_data(from_datetime, to_datetime, calendar=calendar, domain=domain)['days']
- def get_work_days_data(self, from_datetime, to_datetime, calendar=None):
+ def get_work_hours_count(self, from_datetime, to_datetime, calendar=None, domain=None):
+ """ Return the number of work hours for the resource, taking into account
+ leaves. An optional calendar can be given in case multiple calendars can
+ be used on the resource. """
+ return self.get_work_days_data(from_datetime, to_datetime, calendar=calendar, domain=domain)['hours']
+
+ def get_work_days_data(self, from_datetime, to_datetime, calendar=None, domain=None):
days_count = 0.0
total_work_time = timedelta()
calendar = calendar or self.resource_calendar_id
for day_intervals in calendar._iter_work_intervals(
from_datetime, to_datetime, self.resource_id.id,
- compute_leaves=True):
+ compute_leaves=True, domain=domain):
theoric_hours = self.get_day_work_hours_count(day_intervals[0][0].date(), calendar=calendar)
work_time = sum((interval[1] - interval[0] for interval in day_intervals), timedelta())
total_work_time += work_time
@@ -63,38 +69,52 @@ class ResourceMixin(models.AbstractModel):
'hours': total_work_time.total_seconds() / 3600,
}
- def iter_works(self, from_datetime, to_datetime, calendar=None):
+ def iter_works(self, from_datetime, to_datetime, calendar=None, domain=None):
calendar = calendar or self.resource_calendar_id
- return calendar._iter_work_intervals(from_datetime, to_datetime, self.resource_id.id)
+ return calendar._iter_work_intervals(from_datetime, to_datetime, self.resource_id.id, domain=domain)
- def iter_work_hours_count(self, from_datetime, to_datetime, calendar=None):
+ def iter_work_hours_count(self, from_datetime, to_datetime, calendar=None, domain=None):
calendar = calendar or self.resource_calendar_id
- return calendar._iter_work_hours_count(from_datetime, to_datetime, self.resource_id.id)
+ return calendar._iter_work_hours_count(from_datetime, to_datetime, self.resource_id.id, domain=domain)
- def get_leaves_day_count(self, from_datetime, to_datetime, calendar=None):
+ def get_leaves_day_count(self, from_datetime, to_datetime, calendar=None, domain=None):
""" Return the number of leave days for the resource, taking into account
attendances. An optional calendar can be given in case multiple calendars
can be used on the resource. """
+ return self.get_leaves_days_data(from_datetime, to_datetime, calendar=calendar, domain=domain)['days']
+
+ def get_leaves_hours_count(self, from_datetime, to_datetime, calendar=None, domain=None):
+ """ Return the number of leave hours for the resource, taking into account
+ attendances. An optional calendar can be given in case multiple calendars can
+ be used on the resource. """
+ return self.get_leaves_days_data(from_datetime, to_datetime, calendar=calendar, domain=domain)['hours']
+
+ def get_leaves_days_data(self, from_datetime, to_datetime, calendar=None, domain=None):
days_count = 0.0
+ total_leave_time = timedelta()
calendar = calendar or self.resource_calendar_id
- for day_intervals in calendar._iter_leave_intervals(from_datetime, to_datetime, self.resource_id.id):
+ for day_intervals in calendar._iter_leave_intervals(from_datetime, to_datetime, self.resource_id.id, domain=domain):
theoric_hours = self.get_day_work_hours_count(day_intervals[0][0].date(), calendar=calendar)
leave_time = sum((interval[1] - interval[0] for interval in day_intervals), timedelta())
+ total_leave_time += leave_time
days_count += float_utils.round((leave_time.total_seconds() / 3600 / theoric_hours) * 4) / 4
- return days_count
+ return {
+ 'days': days_count,
+ 'hours': total_leave_time.total_seconds() / 3600,
+ }
- def iter_leaves(self, from_datetime, to_datetime, calendar=None):
+ def iter_leaves(self, from_datetime, to_datetime, calendar=None, domain=None):
calendar = calendar or self.resource_calendar_id
- return calendar._iter_leave_intervals(from_datetime, to_datetime, self.resource_id.id)
+ return calendar._iter_leave_intervals(from_datetime, to_datetime, self.resource_id.id, domain=domain)
- def get_start_work_hour(self, day_dt, calendar=None):
+ def get_start_work_hour(self, day_dt, calendar=None, domain=None):
calendar = calendar or self.resource_calendar_id
- work_intervals = calendar._get_day_work_intervals(day_dt, resource_id=self.resource_id.id)
+ work_intervals = calendar._get_day_work_intervals(day_dt, resource_id=self.resource_id.id, domain=domain)
return work_intervals and work_intervals[0][0]
- def get_end_work_hour(self, day_dt, calendar=None):
+ def get_end_work_hour(self, day_dt, calendar=None, domain=None):
calendar = calendar or self.resource_calendar_id
- work_intervals = calendar._get_day_work_intervals(day_dt, resource_id=self.resource_id.id)
+ work_intervals = calendar._get_day_work_intervals(day_dt, resource_id=self.resource_id.id, domain=domain)
return work_intervals and work_intervals[-1][1]
def get_day_work_hours_count(self, day_date, calendar=None):
diff --git a/addons/resource/tests/test_resource.py b/addons/resource/tests/test_resource.py
index 39861cf9805..ed1d81fd54f 100644
--- a/addons/resource/tests/test_resource.py
+++ b/addons/resource/tests/test_resource.py
@@ -698,6 +698,48 @@ class TestResourceMixin(TestResourceCommon):
self.assertEqual(res['days'], 0.75)
self.assertEqual(res['hours'], 6.0)
+ def test_days_count_with_domain(self):
+ self.test.resource_id.write({
+ 'user_id': self.lost_user.id,
+ })
+
+ self.env['resource.calendar.leaves'].sudo(self.lost_user).create({
+ 'name': 'first',
+ 'calendar_id': self.test.resource_calendar_id.id,
+ 'resource_id': self.test.resource_id.id,
+ 'date_from': to_naive_utc(Datetime.from_string('2018-02-05 08:00:00'), self.lost_user),
+ 'date_to': to_naive_utc(Datetime.from_string('2018-02-09 18:00:00'), self.lost_user)
+ })
+
+ self.env['resource.calendar.leaves'].sudo(self.lost_user).create({
+ 'name': 'second',
+ 'calendar_id': self.test.resource_calendar_id.id,
+ 'resource_id': self.test.resource_id.id,
+ 'date_from': to_naive_utc(Datetime.from_string('2018-01-12 08:00:00'), self.lost_user),
+ 'date_to': to_naive_utc(Datetime.from_string('2018-01-13 18:00:00'), self.lost_user)
+ })
+
+ res = self.test.get_work_days_count(
+ to_naive_utc(Datetime.from_string('2018-02-04 06:00:00'), self.env.user),
+ to_naive_utc(Datetime.from_string('2018-02-14 20:00:00'), self.env.user),
+ domain=[('name', '=', '')]
+ )
+ self.assertEqual(res, 3.0)
+
+ res = self.test.get_work_days_count(
+ to_naive_utc(Datetime.from_string('2018-02-04 06:00:00'), self.env.user),
+ to_naive_utc(Datetime.from_string('2018-02-14 20:00:00'), self.env.user),
+ domain=[('name', '=', 'first')]
+ )
+ self.assertEqual(res, 1.0)
+
+ res = self.test.get_leaves_day_count(
+ to_naive_utc(Datetime.from_string('2018-02-04 06:00:00'), self.env.user),
+ to_naive_utc(Datetime.from_string('2018-02-14 20:00:00'), self.env.user),
+ domain=[('name', '=', 'first')]
+ )
+ self.assertEqual(res, 2.0)
+
class TestGlobalLeaves(TestResourceCommon):
def setUp(self):