[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
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user