diff --git a/addons/base_automation/models/base_automation.py b/addons/base_automation/models/base_automation.py index a03ff7678bc..24267f72821 100644 --- a/addons/base_automation/models/base_automation.py +++ b/addons/base_automation/models/base_automation.py @@ -299,11 +299,11 @@ class BaseAutomation(models.Model): @api.model def _check_delay(self, action, record, record_dt): if action.trg_date_calendar_id and action.trg_date_range_type == 'day': - return action.trg_date_calendar_id.schedule_days_get_date( + return action.trg_date_calendar_id.plan_days( action.trg_date_range, day_date=fields.Datetime.from_string(record_dt), compute_leaves=True, - )[0] + ) else: delay = DATE_RANGE_FUNCTION[action.trg_date_range_type](action.trg_date_range) return fields.Datetime.from_string(record_dt) + delay diff --git a/addons/hr_holidays/models/hr_holidays.py b/addons/hr_holidays/models/hr_holidays.py index b074517ddb6..84a37f09c9a 100644 --- a/addons/hr_holidays/models/hr_holidays.py +++ b/addons/hr_holidays/models/hr_holidays.py @@ -285,7 +285,7 @@ class Holidays(models.Model): employee = self.env['hr.employee'].browse(employee_id) resource = employee.resource_id if resource and resource.calendar_id: - hours = resource.calendar_id.get_working_hours(from_dt, to_dt, resource_id=resource.id, compute_leaves=True) + hours = resource.calendar_id.get_work_hours_count(from_dt, to_dt, resource_id=resource.id, compute_leaves=True) uom_hour = resource.calendar_id.uom_id uom_day = self.env.ref('product.product_uom_day') if uom_hour and uom_day: diff --git a/addons/hr_payroll/models/hr_payroll.py b/addons/hr_payroll/models/hr_payroll.py index f104c46de04..4be849c9b9a 100644 --- a/addons/hr_payroll/models/hr_payroll.py +++ b/addons/hr_payroll/models/hr_payroll.py @@ -334,7 +334,7 @@ class HrPayslip(models.Model): day_to = fields.Datetime.from_string(date_to) nb_of_days = (day_to - day_from).days + 1 for day in range(0, nb_of_days): - working_hours_on_day = contract.working_hours.working_hours_on_day(day_from + timedelta(days=day)) + working_hours_on_day = contract.working_hours.get_work_hours_count(day_from + timedelta(days=day), False) if working_hours_on_day: #the employee had to work leave_type = was_on_leave(contract.employee_id.id, day_from + timedelta(days=day)) diff --git a/addons/mrp/models/mrp_workcenter.py b/addons/mrp/models/mrp_workcenter.py index a46dc2b193e..91f73ea9c83 100644 --- a/addons/mrp/models/mrp_workcenter.py +++ b/addons/mrp/models/mrp_workcenter.py @@ -206,7 +206,7 @@ class MrpWorkcenterProductivity(models.Model): d2 = fields.Datetime.from_string(blocktime.date_end) diff = d2 - d1 if (blocktime.loss_type not in ('productive', 'performance')) and blocktime.workcenter_id.calendar_id: - r = blocktime.workcenter_id.calendar_id.get_working_hours(d1, d2, resource_id=blocktime.workcenter_id.resource_id.id) + r = blocktime.workcenter_id.calendar_id.get_work_hours_count(d1, d2, resource_id=blocktime.workcenter_id.resource_id.id) blocktime.duration = round(r * 60, 2) else: blocktime.duration = round(diff.total_seconds() / 60.0, 2) diff --git a/addons/project_issue/models/project_issue.py b/addons/project_issue/models/project_issue.py index f5a77a745f4..024ab4e81b4 100644 --- a/addons/project_issue/models/project_issue.py +++ b/addons/project_issue/models/project_issue.py @@ -90,7 +90,7 @@ class ProjectIssue(models.Model): dt_date_open = fields.Datetime.from_string(issue.date_open) issue.day_open = (dt_date_open - dt_create_date).total_seconds() / (24.0 * 3600) if issue.project_id.resource_calendar_id: - issue.working_hours_open = issue.project_id.resource_calendar_id.get_working_hours( + issue.working_hours_open = issue.project_id.resource_calendar_id.get_work_hours_count( dt_create_date, dt_date_open, compute_leaves=True, resource_id=False) else: @@ -100,7 +100,7 @@ class ProjectIssue(models.Model): dt_date_closed = fields.Datetime.from_string(issue.date_closed) issue.day_close = (dt_date_closed - dt_create_date).total_seconds() / (24.0 * 3600) if issue.project_id.resource_calendar_id: - issue.working_hours_close = issue.project_id.resource_calendar_id.get_working_hours( + issue.working_hours_close = issue.project_id.resource_calendar_id.get_work_hours_count( dt_create_date, dt_date_closed, compute_leaves=True, resource_id=False) else: diff --git a/addons/resource/models/resource.py b/addons/resource/models/resource.py index 4867ca77294..b594df319cc 100644 --- a/addons/resource/models/resource.py +++ b/addons/resource/models/resource.py @@ -14,6 +14,11 @@ from odoo.exceptions import ValidationError from odoo.tools.float_utils import float_compare +def seconds(td): + assert isinstance(td, timedelta) + return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10.**6 + + class ResourceCalendar(models.Model): """ Calendar model for a resource. It has @@ -67,7 +72,7 @@ class ResourceCalendar(models.Model): # Utility methods # -------------------------------------------------- - def interval_clean(self, intervals): + def _interval_clean(self, intervals): """ Utility method that sorts and removes overlapping inside datetime intervals. The intervals are sorted based on increasing starting datetime. Overlapping intervals are merged into a single one. @@ -92,7 +97,7 @@ class ResourceCalendar(models.Model): return cleaned @api.model - def interval_remove_leaves(self, interval, leave_intervals): + def _interval_remove_leaves(self, interval, leave_intervals): """ Utility method that remove leave intervals from a base interval: - clean the leave intervals, to have an ordered list of not-overlapping @@ -121,7 +126,7 @@ class ResourceCalendar(models.Model): if leave_intervals is None: leave_intervals = [] intervals = [] - leave_intervals = self.interval_clean(leave_intervals) + leave_intervals = self._interval_clean(leave_intervals) current_interval = [interval[0], interval[1]] for leave in leave_intervals: if leave[1] <= current_interval[0]: @@ -138,7 +143,8 @@ class ResourceCalendar(models.Model): intervals.append((current_interval[0], current_interval[1])) return intervals - def interval_schedule_hours(self, intervals, hour, remove_at_end=True): + @api.model + def _interval_schedule_hours(self, intervals, hour, remove_at_end=True): """ Schedule hours in intervals. The last matching interval is truncated to match the specified hours. @@ -176,7 +182,7 @@ class ResourceCalendar(models.Model): # -------------------------------------------------- @api.multi - def get_attendances_for_weekday(self, day_dt): + def _get_day_attendances(self, day_dt): """ Given a day datetime, return matching attendances """ self.ensure_one() weekday = day_dt.weekday() @@ -191,7 +197,7 @@ class ResourceCalendar(models.Model): return attendances @api.multi - def get_weekdays(self): + def _get_weekdays(self): """ Return the list of weekdays that contain at least one working interval. """ self.ensure_one() @@ -199,7 +205,7 @@ class ResourceCalendar(models.Model): return list(weekdays) @api.multi - def get_next_day(self, day_date): + def _get_next_work_day(self, day_date): """ Get following date of day_date, based on resource.calendar. If no calendar is provided, just return the next day. @@ -207,7 +213,7 @@ class ResourceCalendar(models.Model): :return date: next day of calendar, or just next day """ self.ensure_one() - weekdays = self.get_weekdays() + weekdays = self._get_weekdays() base_index = -1 for weekday in weekdays: @@ -223,15 +229,15 @@ class ResourceCalendar(models.Model): return day_date + relativedelta(days=days) @api.multi - def get_previous_day(self, day_date): - """ Get previous date of day_date, based on resource.calendar. If no + def _get_previous_work_day(self, day_date): + """ Get previous date of day_date, based on work.calendar. If no calendar is provided, just return the previous day. :param date day_date: current day as a date :return date: previous day of calendar, or just previous day """ self.ensure_one() - weekdays = self.get_weekdays() + weekdays = self._get_weekdays() weekdays.reverse() base_index = -1 @@ -248,8 +254,8 @@ 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): """Get the leaves of the calendar. Leaves can be filtered on the resource, the start datetime or the end datetime. @@ -280,8 +286,8 @@ class ResourceCalendar(models.Model): return leaves @api.multi - def get_working_intervals_of_day(self, start_dt=None, end_dt=None, - leaves=None, compute_leaves=False, resource_id=None): + def _get_day_work_intervals(self, start_dt=None, end_dt=None, + leaves=None, compute_leaves=False, resource_id=None): """ Get the working intervals of the day based on calendar. This method handle leaves that come directly from the leaves parameter or can be computed. @@ -321,14 +327,14 @@ class ResourceCalendar(models.Model): end_dt = start_dt.replace(hour=23, minute=59, second=59) else: work_limits.append((end_dt, end_dt.replace(hour=23, minute=59, second=59))) - assert start_dt.date() == end_dt.date(), 'get_working_intervals_of_day is restricted to one day' + assert start_dt.date() == end_dt.date(), '_get_day_work_intervals is restricted to one day' intervals = [] work_dt = start_dt.replace(hour=0, minute=0, second=0) working_intervals = [] tz_info = fields.Datetime.context_timestamp(self, work_dt).tzinfo - for calendar_working_day in self.get_attendances_for_weekday(start_dt): + for calendar_working_day in self._get_day_attendances(start_dt): dt_f = work_dt.replace(hour=0, minute=0, second=0) + timedelta(seconds=(calendar_working_day.hour_from * 3600)) dt_t = work_dt.replace(hour=0, minute=0, second=0) + timedelta(seconds=(calendar_working_day.hour_to * 3600)) @@ -338,54 +344,48 @@ class ResourceCalendar(models.Model): dt_t.replace(tzinfo=tz_info).astimezone(pytz.UTC).replace(tzinfo=None), calendar_working_day.id ) - working_intervals += self.interval_remove_leaves(working_interval, work_limits) + working_intervals += self._interval_remove_leaves(working_interval, work_limits) # find leave intervals if leaves is None and compute_leaves: - leaves = self.get_leave_intervals(resource_id=resource_id) + leaves = self._get_leave_intervals(resource_id=resource_id) # filter according to leaves for interval in working_intervals: - work_intervals = self.interval_remove_leaves(interval, leaves) + work_intervals = self._interval_remove_leaves(interval, leaves) intervals += work_intervals return intervals - @api.multi - def get_working_hours_of_date(self, start_dt=None, end_dt=None, - leaves=None, compute_leaves=False, resource_id=None): - """ Get the working hours of the day based on calendar. This method uses - get_working_intervals_of_day to have the work intervals of the day. It - then calculates the number of hours contained in those intervals. """ - res = timedelta() - intervals = self.get_working_intervals_of_day( - start_dt, end_dt, leaves, - compute_leaves, resource_id) - for interval in intervals: - res += interval[1] - interval[0] - return seconds(res) / 3600.0 + # -------------------------------------------------- + # Main computation API + # -------------------------------------------------- @api.multi - def get_working_hours(self, start_dt, end_dt, compute_leaves=False, - resource_id=None): - hours = 0.0 + def get_work_hours_count(self, start_dt, end_dt, compute_leaves=False, resource_id=None): + if not end_dt: + end_dt = start_dt.replace(hour=23, minute=59, second=59) + res = timedelta() for day in rrule.rrule(rrule.DAILY, dtstart=start_dt, until=end_dt, - byweekday=self.get_weekdays()): + byweekday=self._get_weekdays()): day_start_dt = day.replace(hour=0, minute=0, second=0) if start_dt and day.date() == start_dt.date(): day_start_dt = start_dt day_end_dt = day.replace(hour=23, minute=59, second=59) if end_dt and day.date() == end_dt.date(): day_end_dt = end_dt - hours += self.get_working_hours_of_date( + intervals = self._get_day_work_intervals( start_dt=day_start_dt, end_dt=day_end_dt, compute_leaves=compute_leaves, resource_id=resource_id) - return hours + for interval in intervals: + res += interval[1] - interval[0] + + return seconds(res) / 3600.0 # -------------------------------------------------- - # Hours scheduling + # Scheduling API # -------------------------------------------------- @api.multi @@ -433,12 +433,12 @@ class ResourceCalendar(models.Model): else: call_args['start_dt'] = current_datetime - working_intervals = self.get_working_intervals_of_day(**call_args) + working_intervals = self._get_day_work_intervals(**call_args) if working_intervals: if backwards: working_intervals.reverse() - new_working_intervals = self.interval_schedule_hours(working_intervals, remaining_hours, not backwards) + new_working_intervals = self._interval_schedule_hours(working_intervals, remaining_hours, not backwards) if backwards: new_working_intervals.reverse() @@ -452,33 +452,20 @@ class ResourceCalendar(models.Model): intervals = intervals + new_working_intervals # get next day if backwards: - current_datetime = datetime.datetime.combine(self.get_previous_day(current_datetime), datetime.time(23, 59, 59)) + current_datetime = datetime.datetime.combine(self._get_previous_work_day(current_datetime), datetime.time(23, 59, 59)) else: - current_datetime = datetime.datetime.combine(self.get_next_day(current_datetime), datetime.time()) + current_datetime = datetime.datetime.combine(self._get_next_work_day(current_datetime), datetime.time()) # avoid infinite loops iterations += 1 return intervals @api.multi - def schedule_hours_get_date(self, hours, day_dt=None, - compute_leaves=False, resource_id=None): - """ Wrapper on _schedule_hours: return the beginning/ending datetime of - an hours scheduling. """ + def plan_hours(self, hours, day_dt=None, compute_leaves=False, resource_id=None): + """ Return datetime after having planned hours """ res = self._schedule_hours(hours, day_dt, compute_leaves, resource_id) return res and res[0][0] or False - @api.multi - def schedule_hours(self, hours, day_dt=None, - compute_leaves=False, resource_id=None): - """ Wrapper on _schedule_hours: return the working intervals of an hours - scheduling. """ - return self._schedule_hours(hours, day_dt, compute_leaves, resource_id) - - # -------------------------------------------------- - # Days scheduling - # -------------------------------------------------- - @api.multi def _schedule_days(self, days, day_date=None, compute_leaves=False, resource_id=None): @@ -516,7 +503,7 @@ class ResourceCalendar(models.Model): current_datetime = day_date.replace(hour=0, minute=0, second=0) while planned_days < days and iterations < 100: - working_intervals = self.get_working_intervals_of_day( + working_intervals = self._get_day_work_intervals( current_datetime, compute_leaves=compute_leaves, resource_id=resource_id) if not self or working_intervals: # no calendar -> no working hours, but day is considered as worked @@ -524,98 +511,20 @@ class ResourceCalendar(models.Model): intervals += working_intervals # get next day if backwards: - current_datetime = self.get_previous_day(current_datetime) + current_datetime = self._get_previous_work_day(current_datetime) else: - current_datetime = self.get_next_day(current_datetime) + current_datetime = self._get_next_work_day(current_datetime) # avoid infinite loops iterations += 1 return intervals @api.multi - def schedule_days_get_date(self, days, day_date=None, compute_leaves=False, resource_id=None): - """ Wrapper on _schedule_days: return the beginning/ending datetime of - a days scheduling. """ + def plan_days(self, days, day_date=None, compute_leaves=False, resource_id=None): + """ Returns the datetime of a days scheduling. """ res = self._schedule_days(days, day_date, compute_leaves, resource_id) return res and res[-1][1] or False - @api.multi - def schedule_days(self, days, day_date=None, compute_leaves=False, resource_id=None): - """ Wrapper on _schedule_days: return the working intervals of a days - scheduling. """ - return self._schedule_days(days, day_date, compute_leaves, resource_id) - - # -------------------------------------------------- - # Compatibility / to clean / to remove - # -------------------------------------------------- - - @api.multi - def working_hours_on_day(self, day): - """ Used in hr_payroll/hr_payroll.py - - :deprecated: Odoo saas-3. Use get_working_hours_of_date instead. Note: - since saas-3, take hour/minutes into account, not just the whole day.""" - if isinstance(day, datetime.datetime): - day = day.replace(hour=0, minute=0) - return self.get_working_hours_of_date(start_dt=day) - - @api.multi - def interval_min_get(self, dt_from, hours, resource=False): - """ Schedule hours backwards. Used in mrp_operations/mrp_operations.py. - - :deprecated: Odoo saas-3. Use schedule_hours instead. Note: since - saas-3, counts leave hours instead of all-day leaves.""" - return self.schedule_hours( - hours * -1.0, - day_dt=dt_from.replace(minute=0, second=0), - compute_leaves=True, resource_id=resource - ) - - @api.model - def interval_get_multi(self, date_and_hours_by_cal, resource=False, byday=True): - """ Used in mrp_operations/mrp_operations.py (default parameters) and in - interval_get() - - :deprecated: Odoo saas-3. Use schedule_hours instead. Note: - Byday was not used. Since saas-3, counts Leave hours instead of all-day leaves.""" - res = {} - for dt_str, hours, calendar_id in date_and_hours_by_cal: - result = self.browse(calendar_id).schedule_hours( - hours, - day_dt=fields.Datetime.from_string(dt_str).replace(second=0), - compute_leaves=True, resource_id=resource, - ) - res[(dt_str, hours, calendar_id)] = result - return res - - @api.multi - def interval_get(self, dt_from, hours, resource=False, byday=True): - """ Unifier of interval_get_multi. Used in: mrp_operations/mrp_operations.py, - crm/crm_lead.py (res given). - - :deprecated: Odoo saas-3. Use get_working_hours instead.""" - self.ensure_one() - res = self.interval_get_multi( - [(fields.Datetime.to_string(dt_from), hours, self.id)], resource, byday)[(fields.Datetime.to_string(dt_from), hours, self.id)] - return res - - @api.multi - def interval_hours_get(self, dt_from, dt_to, resource=False): - """ Unused wrapper. - - :deprecated: Odoo saas-3. Use get_working_hours instead.""" - return self._interval_hours_get(dt_from, dt_to, resource_id=resource) - - @api.multi - def _interval_hours_get(self, dt_from, dt_to, resource_id=False, timezone_from_uid=None, exclude_leaves=True): - """ Computes working hours between two dates, taking always same hour/minuts. - :deprecated: Odoo saas-3. Use get_working_hours instead. Note: since saas-3, - now resets hour/minuts. Now counts leave hours instead of all-day leaves.""" - return self.get_working_hours( - dt_from, dt_to, - compute_leaves=(not exclude_leaves), resource_id=resource_id, - ) - class ResourceCalendarAttendance(models.Model): _name = "resource.calendar.attendance" @@ -639,12 +548,6 @@ class ResourceCalendarAttendance(models.Model): calendar_id = fields.Many2one("resource.calendar", string="Resource's Calendar", required=True, ondelete='cascade') -def hours_time_string(hours): - """ convert a number of hours (float) into a string with format '%H:%M' """ - minutes = int(round(hours * 60)) - return "%02d:%02d" % divmod(minutes, 60) - - class ResourceResource(models.Model): _name = "resource.resource" _description = "Resource Detail" @@ -718,7 +621,7 @@ class ResourceResource(models.Model): days (inclusive) :rtype: list(datetime.date) """ - working_intervals = self.calendar_id.get_working_intervals_of_day + working_intervals = self.calendar_id._get_day_work_intervals # rrule coerces date inputs to datetimes (with time=0) and yields # datetimes (with time=0 if freq >= daily) for dt in rrule.rrule(rrule.DAILY, dtstart=from_date, until=to_date): @@ -753,8 +656,3 @@ class ResourceCalendarLeaves(models.Model): def onchange_resource(self): if self.resource_id: self.calendar_id = self.resource_id.calendar_id - -def seconds(td): - assert isinstance(td, timedelta) - - return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10.**6 diff --git a/addons/resource/tests/test_resource.py b/addons/resource/tests/test_resource.py index 528e5fac854..3190c6c8345 100644 --- a/addons/resource/tests/test_resource.py +++ b/addons/resource/tests/test_resource.py @@ -7,9 +7,8 @@ from datetime import datetime, timedelta, date from dateutil.relativedelta import relativedelta from odoo.fields import Date, Datetime -from odoo.tools import float_compare +from odoo.addons.resource.models.resource import seconds from odoo.addons.resource.tests.common import TestResourceCommon -from odoo.tests import TransactionCase class TestIntervals(TestResourceCommon): @@ -45,7 +44,7 @@ class TestIntervals(TestResourceCommon): ] def test_interval_clean(self): - cleaned_intervals = self.env['resource.calendar'].interval_clean(self.intervals) + cleaned_intervals = self.env['resource.calendar']._interval_clean(self.intervals) self.assertEqual(len(cleaned_intervals), 3) # First interval: 03, unchanged self.assertEqual(cleaned_intervals[0], (Datetime.from_string('2013-02-03 08:00:00'), Datetime.from_string('2013-02-03 10:00:00'))) @@ -56,14 +55,14 @@ class TestIntervals(TestResourceCommon): def test_interval_remove(self): working_interval = (Datetime.from_string('2013-02-04 08:00:00'), Datetime.from_string('2013-02-04 18:00:00')) - result = self.env['resource.calendar'].interval_remove_leaves(working_interval, self.intervals) + result = self.env['resource.calendar']._interval_remove_leaves(working_interval, self.intervals) self.assertEqual(len(result), 1) # First interval: 04, 14-17 self.assertEqual(result[0], (Datetime.from_string('2013-02-04 14:00:00'), Datetime.from_string('2013-02-04 17:00:00'))) def test_interval_schedule_hours(self): - cleaned_intervals = self.env['resource.calendar'].interval_clean(self.intervals) - result = self.env['resource.calendar'].interval_schedule_hours(cleaned_intervals, 5.5) + cleaned_intervals = self.env['resource.calendar']._interval_clean(self.intervals) + result = self.env['resource.calendar']._interval_schedule_hours(cleaned_intervals, 5.5) self.assertEqual(len(result), 2) # First interval: 03, 8-10 untouched self.assertEqual(result[0], (Datetime.from_string('2013-02-03 08:00:00'), Datetime.from_string('2013-02-03 10:00:00'))) @@ -71,9 +70,9 @@ class TestIntervals(TestResourceCommon): self.assertEqual(result[1], (Datetime.from_string('2013-02-04 08:00:00'), Datetime.from_string('2013-02-04 11:30:00'))) def test_interval_schedule_hours_backwards(self): - cleaned_intervals = self.env['resource.calendar'].interval_clean(self.intervals) + cleaned_intervals = self.env['resource.calendar']._interval_clean(self.intervals) cleaned_intervals.reverse() - result = self.env['resource.calendar'].interval_schedule_hours(cleaned_intervals, 5.5, remove_at_end=False) + result = self.env['resource.calendar']._interval_schedule_hours(cleaned_intervals, 5.5, remove_at_end=False) self.assertEqual(len(result), 2) # First interval: 03, 8-10 untouched self.assertEqual(result[0], (Datetime.from_string('2013-02-04 17:00:00'), Datetime.from_string('2013-02-04 21:00:00'))) @@ -84,68 +83,68 @@ class TestIntervals(TestResourceCommon): class TestCalendarBasics(TestResourceCommon): def test_calendar_weekdays(self): - weekdays = self.calendar.get_weekdays() + weekdays = self.calendar._get_weekdays() self.assertEqual(weekdays, [1, 4]) def test_calendar_next_day(self): # Test: next day: next day after day1 is day4 - date = self.calendar.get_next_day(day_date=Date.from_string('2013-02-12')) + date = self.calendar._get_next_work_day(day_date=Date.from_string('2013-02-12')) self.assertEqual(date, self.date2.date()) # Test: next day: next day after day4 is (day1+7) - date = self.calendar.get_next_day(day_date=Date.from_string('2013-02-15')) + date = self.calendar._get_next_work_day(day_date=Date.from_string('2013-02-15')) self.assertEqual(date, self.date1.date() + relativedelta(days=7)) # Test: next day: next day after day4+1 is (day1+7) - date = self.calendar.get_next_day(day_date=Date.from_string('2013-02-15') + relativedelta(days=1)) + date = self.calendar._get_next_work_day(day_date=Date.from_string('2013-02-15') + relativedelta(days=1)) self.assertEqual(date, self.date1.date() + relativedelta(days=7)) # Test: next day: next day after day1-1 is day1 - date = self.calendar.get_next_day(day_date=Date.from_string('2013-02-12') + relativedelta(days=-1)) + date = self.calendar._get_next_work_day(day_date=Date.from_string('2013-02-12') + relativedelta(days=-1)) self.assertEqual(date, self.date1.date()) def test_calendar_previous_day(self): # Test: previous day: previous day before day1 is (day4-7) - date = self.calendar.get_previous_day(day_date=Date.from_string('2013-02-12')) + date = self.calendar._get_previous_work_day(day_date=Date.from_string('2013-02-12')) self.assertEqual(date, self.date2.date() + relativedelta(days=-7)) # Test: previous day: previous day before day4 is day1 - date = self.calendar.get_previous_day(day_date=Date.from_string('2013-02-15')) + date = self.calendar._get_previous_work_day(day_date=Date.from_string('2013-02-15')) self.assertEqual(date, self.date1.date()) # Test: previous day: previous day before day4+1 is day4 - date = self.calendar.get_previous_day(day_date=Date.from_string('2013-02-15') + relativedelta(days=1)) + date = self.calendar._get_previous_work_day(day_date=Date.from_string('2013-02-15') + relativedelta(days=1)) self.assertEqual(date, self.date2.date()) # Test: previous day: previous day before day1-1 is (day4-7) - date = self.calendar.get_previous_day(day_date=Date.from_string('2013-02-12') + relativedelta(days=-1)) + date = self.calendar._get_previous_work_day(day_date=Date.from_string('2013-02-12') + relativedelta(days=-1)) self.assertEqual(date, self.date2.date() + relativedelta(days=-7)) def test_calendar_working_day_intervals_no_leaves(self): # Test: day0 without leaves: 1 interval - intervals = self.calendar.get_working_intervals_of_day(start_dt=Datetime.from_string('2013-02-12 09:08:07')) + intervals = self.calendar._get_day_work_intervals(start_dt=Datetime.from_string('2013-02-12 09:08:07')) self.assertEqual(len(intervals), 1) self.assertEqual(intervals[0], (Datetime.from_string('2013-02-12 09:08:07'), Datetime.from_string('2013-02-12 16:00:00'))) # Test: day1, beginning at 10:30 -> work from 10:30 (arrival) until 16:00 - intervals = self.calendar.get_working_intervals_of_day(start_dt=Datetime.from_string('2013-02-19 10:30:00')) + intervals = self.calendar._get_day_work_intervals(start_dt=Datetime.from_string('2013-02-19 10:30:00')) self.assertEqual(len(intervals), 1) self.assertEqual(intervals[0], (Datetime.from_string('2013-02-19 10:30:00'), Datetime.from_string('2013-02-19 16:00:00'))) # Test: day3 without leaves: 2 interval - intervals = self.calendar.get_working_intervals_of_day(start_dt=Datetime.from_string('2013-02-15 10:11:12')) + intervals = self.calendar._get_day_work_intervals(start_dt=Datetime.from_string('2013-02-15 10:11:12')) self.assertEqual(len(intervals), 2) self.assertEqual(intervals[0], (Datetime.from_string('2013-02-15 10:11:12'), Datetime.from_string('2013-02-15 13:00:00'))) self.assertEqual(intervals[1], (Datetime.from_string('2013-02-15 16:00:00'), Datetime.from_string('2013-02-15 23:00:00'))) def test_calendar_working_day_intervals_leaves_generic(self): # Test: day0 with leaves outside range: 1 interval - intervals = self.calendar.get_working_intervals_of_day(start_dt=Datetime.from_string('2013-02-12 07:00:00'), compute_leaves=True) + intervals = self.calendar._get_day_work_intervals(start_dt=Datetime.from_string('2013-02-12 07:00:00'), compute_leaves=True) self.assertEqual(len(intervals), 1) self.assertEqual(intervals[0], (Datetime.from_string('2013-02-12 08:00:00'), Datetime.from_string('2013-02-12 16:00:00'))) # Test: day0 with leaves: 2 intervals because of leave between 9 ans 12, ending at 15:45:30 - intervals = self.calendar.get_working_intervals_of_day(start_dt=Datetime.from_string('2013-02-19 08:15:00'), + intervals = self.calendar._get_day_work_intervals(start_dt=Datetime.from_string('2013-02-19 08:15:00'), end_dt=Datetime.from_string('2013-02-19 15:45:30'), compute_leaves=True) self.assertEqual(len(intervals), 2) @@ -154,7 +153,7 @@ class TestCalendarBasics(TestResourceCommon): def test_calendar_working_day_intervals_leaves_resource(self): # Test: day1+14 on leave, with resource leave computation - intervals = self.calendar.get_working_intervals_of_day( + intervals = self.calendar._get_day_work_intervals( Datetime.from_string('2013-02-26 07:00:00'), compute_leaves=True, resource_id=self.resource1_id @@ -170,76 +169,60 @@ class TestCalendarBasics(TestResourceCommon): 'date_from': self.date2 + relativedelta(days=7), 'date_to': False, }) - intervals = self.calendar.get_working_intervals_of_day(start_dt=self.date2) + intervals = self.calendar._get_day_work_intervals(start_dt=self.date2) self.assertEqual(intervals, [(Datetime.from_string('2013-02-15 10:11:12'), Datetime.from_string('2013-02-15 13:00:00'))]) attendance.write({ 'date_from': False, 'date_to': self.date2 - relativedelta(days=7), }) - intervals = self.calendar.get_working_intervals_of_day(start_dt=self.date2) + intervals = self.calendar._get_day_work_intervals(start_dt=self.date2) self.assertEqual(intervals, [(Datetime.from_string('2013-02-15 10:11:12'), Datetime.from_string('2013-02-15 13:00:00'))]) attendance.write({ 'date_from': self.date2 + relativedelta(days=7), 'date_to': self.date2 - relativedelta(days=7), }) - intervals = self.calendar.get_working_intervals_of_day(start_dt=self.date2) + intervals = self.calendar._get_day_work_intervals(start_dt=self.date2) self.assertEqual(intervals, [(Datetime.from_string('2013-02-15 10:11:12'), Datetime.from_string('2013-02-15 13:00:00'))]) attendance.write({ 'date_from': self.date2, 'date_to': self.date2, }) - intervals = self.calendar.get_working_intervals_of_day(start_dt=self.date2) + intervals = self.calendar._get_day_work_intervals(start_dt=self.date2) self.assertEqual(len(intervals), 2) self.assertEqual(intervals[0], (Datetime.from_string('2013-02-15 10:11:12'), Datetime.from_string('2013-02-15 13:00:00'))) self.assertEqual(intervals[1], (Datetime.from_string('2013-02-15 16:00:00'), Datetime.from_string('2013-02-15 23:00:00'))) def test_calendar_working_hours_of_date(self): # Test: day1, beginning at 10:30 -> work from 10:30 (arrival) until 16:00 - wh = self.calendar.get_working_hours_of_date(start_dt=Datetime.from_string('2013-02-19 10:30:00')) + wh = self.calendar.get_work_hours_count(Datetime.from_string('2013-02-19 10:30:00'), Datetime.from_string('2013-02-19 18:00:00')) self.assertEqual(wh, 5.5, 'resource_calendar: wrong working interval / day time computing') class ResourceWorkingHours(TestResourceCommon): def test_calendar_working_hours(self): - # old API: resource without leaves - # res: 2 weeks -> 40 hours - res = self.calendar._interval_hours_get( - Datetime.from_string('2013-02-12 06:00:00'), - Datetime.from_string('2013-02-22 23:00:00'), - resource_id=self.resource1_id, exclude_leaves=True) - self.assertEqual(res, 40.0) - # new API: resource without leaves # res: 2 weeks -> 40 hours - res = self.calendar.get_working_hours( + res = self.calendar.get_work_hours_count( Datetime.from_string('2013-02-12 06:00:00'), Datetime.from_string('2013-02-22 23:00:00'), compute_leaves=False, resource_id=self.resource1_id) self.assertEqual(res, 40.0) def test_calendar_working_hours_leaves(self): - # old API: resource and leaves - # res: 2 weeks -> 40 hours - (3+4) leave hours - res = self.calendar._interval_hours_get( - Datetime.from_string('2013-02-12 06:00:00'), - Datetime.from_string('2013-02-22 23:00:00'), - resource_id=self.resource1_id, exclude_leaves=False) - self.assertEqual(res, 33.0) - # new API: resource and leaves # res: 2 weeks -> 40 hours - (3+4) leave hours - res = self.calendar.get_working_hours( + res = self.calendar.get_work_hours_count( Datetime.from_string('2013-02-12 06:00:00'), Datetime.from_string('2013-02-22 23:00:00'), compute_leaves=True, resource_id=self.resource1_id) self.assertEqual(res, 33.0) def test_calendar_hours_scheduling_backward(self): - res = self.calendar.schedule_hours(-40, day_dt=Datetime.from_string('2013-02-12 09:00:00')) + res = self.calendar._schedule_hours(-40, day_dt=Datetime.from_string('2013-02-12 09:00:00')) # current day, limited at 09:00 because of day_dt specified -> 1 hour self.assertEqual(res[-1], (Datetime.from_string('2013-02-12 08:00:00'), Datetime.from_string('2013-02-12 09:00:00'))) # previous days: 5+7 hours / 8 hours / 5+7 hours -> 32 hours @@ -258,7 +241,7 @@ class ResourceWorkingHours(TestResourceCommon): self.assertEqual(seconds(td) / 3600.0, 40.0) def test_calendar_hours_scheduling_forward(self): - res = self.calendar.schedule_hours(40, day_dt=Datetime.from_string('2013-02-12 09:00:00')) + res = self.calendar._schedule_hours(40, day_dt=Datetime.from_string('2013-02-12 09:00:00')) self.assertEqual(res[0], (Datetime.from_string('2013-02-12 09:00:00'), Datetime.from_string('2013-02-12 16:00:00'))) self.assertEqual(res[1], (Datetime.from_string('2013-02-15 08:00:00'), Datetime.from_string('2013-02-15 13:00:00'))) self.assertEqual(res[2], (Datetime.from_string('2013-02-15 16:00:00'), Datetime.from_string('2013-02-15 23:00:00'))) @@ -273,7 +256,7 @@ class ResourceWorkingHours(TestResourceCommon): self.assertEqual(seconds(td) / 3600.0, 40.0) def test_calendar_hours_scheduling_forward_leaves_resource(self): - res = self.calendar.schedule_hours( + res = self.calendar._schedule_hours( 40, day_dt=Datetime.from_string('2013-02-12 09:00:00'), compute_leaves=True, resource_id=self.resource1_id ) @@ -293,12 +276,12 @@ class ResourceWorkingHours(TestResourceCommon): self.assertEqual(seconds(td) / 3600.0, 40.0) def test_calendar_days_scheduling(self): - res = self.calendar.schedule_days_get_date(5, day_date=Datetime.from_string('2013-02-12 09:08:07') ) + res = self.calendar.plan_days(5, day_date=Datetime.from_string('2013-02-12 09:08:07') ) self.assertEqual(res.date(), Datetime.from_string('2013-02-26 00:00:00').date(), 'resource_calendar: wrong days scheduling') - res = self.calendar.schedule_days_get_date(-2, day_date=Datetime.from_string('2013-02-12 09:08:07') ) + res = self.calendar.plan_days(-2, day_date=Datetime.from_string('2013-02-12 09:08:07') ) self.assertEqual(res.date(), Datetime.from_string('2013-02-08 00:00:00').date(), 'resource_calendar: wrong days scheduling') - res = self.calendar.schedule_days_get_date( + res = self.calendar.plan_days( 5, day_date=Datetime.from_string('2013-02-12 09:08:07'), compute_leaves=True, resource_id=self.resource1_id) self.assertEqual(res.date(), Datetime.from_string('2013-03-01 00:00:00').date(), 'resource_calendar: wrong days scheduling') @@ -439,8 +422,3 @@ class TestWorkDays(TestResourceCommon): self.assertFalse(r._is_work_day(date(1932, 11, 19))) # sat self.assertFalse(r._is_work_day(date(1932, 11, 20))) # sun self.assertFalse(r._is_work_day(date(1932, 12, 6))) # personal leave - -def seconds(td): - assert isinstance(td, timedelta) - - return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10.**6 diff --git a/addons/stock_calendar/models/resource.py b/addons/stock_calendar/models/resource.py index d63b82a3fb7..519a8e3d5e0 100644 --- a/addons/stock_calendar/models/resource.py +++ b/addons/stock_calendar/models/resource.py @@ -22,8 +22,8 @@ class ResourceCalendar(models.Model): # Keep as it takes into account times @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): """Get the leaves of the calendar. Leaves can be filtered on the resource, the start datetime or the end datetime. @@ -60,7 +60,7 @@ class ResourceCalendar(models.Model): # -------------------------------------------------- @api.model - def interval_remove_leaves(self, interval, leave_intervals): + def _interval_remove_leaves(self, interval, leave_intervals): """ Utility method that remove leave intervals from a base interval: - clean the leave intervals, to have an ordered list of not-overlapping @@ -92,7 +92,7 @@ class ResourceCalendar(models.Model): if leave_intervals is None: leave_intervals = [] intervals = [] - #leave_intervals = self.interval_clean(leave_intervals) NOT NECESSARY TO CLEAN HERE AS IT WOULD REMOVE GROUP INFO + #leave_intervals = self._interval_clean(leave_intervals) NOT NECESSARY TO CLEAN HERE AS IT WOULD REMOVE GROUP INFO current_interval = list(interval) for leave in leave_intervals: if len(leave) > 2: