diff --git a/addons/hr_holidays/models/hr_holidays.py b/addons/hr_holidays/models/hr_holidays.py index 72cbd3e24c1..d2aa657de4e 100644 --- a/addons/hr_holidays/models/hr_holidays.py +++ b/addons/hr_holidays/models/hr_holidays.py @@ -163,10 +163,10 @@ class Holidays(models.Model): ('validate1', 'Second Approval'), ('validate', 'Approved') ], string='Status', readonly=True, track_visibility='onchange', copy=False, default='confirm', - help="The status is set to 'To Submit', when a holiday request is created.\ - \nThe status is 'To Approve', when holiday request is confirmed by user.\ - \nThe status is 'Refused', when holiday request is refused by manager.\ - \nThe status is 'Approved', when holiday request is approved by manager.") + help="The status is set to 'To Submit', when a holiday request is created." + + "\nThe status is 'To Approve', when holiday request is confirmed by user." + + "\nThe status is 'Refused', when holiday request is refused by manager." + + "\nThe status is 'Approved', when holiday request is approved by manager.") payslip_status = fields.Boolean('Reported in last payslips', help='Green this button when the leave has been taken into account in the payslip.') report_note = fields.Text('HR Comments') @@ -284,7 +284,7 @@ class Holidays(models.Model): uom_hour = resource.calendar_id.uom_id uom_day = self.env.ref('product.product_uom_day') if uom_hour and uom_day: - return self.env['product.uom']._compute_qty_obj(uom_hour, hours[0], uom_day) + return self.env['product.uom']._compute_qty_obj(uom_hour, hours, uom_day) time_delta = to_dt - from_dt return math.ceil(time_delta.days + float(time_delta.seconds) / 86400) diff --git a/addons/hr_payroll/models/hr_payroll.py b/addons/hr_payroll/models/hr_payroll.py index beb5aa0caff..fd8646f96c8 100644 --- a/addons/hr_payroll/models/hr_payroll.py +++ b/addons/hr_payroll/models/hr_payroll.py @@ -330,7 +330,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 = self.env['resource.calendar'].working_hours_on_day(contract.working_hours, day_from + timedelta(days=day)) + working_hours_on_day = contract.working_hours.working_hours_on_day(day_from + timedelta(days=day)) 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/project_issue/models/project_issue.py b/addons/project_issue/models/project_issue.py index 8d4dacd0caf..7c0598ea54e 100644 --- a/addons/project_issue/models/project_issue.py +++ b/addons/project_issue/models/project_issue.py @@ -94,35 +94,21 @@ class ProjectIssue(models.Model): @api.depends('create_date', 'date_closed', 'date_open') def _compute_day(self): for issue in self: - # if the working hours on the project are not defined, use default ones (8 -> 12 and 13 -> 17 * 5), represented by None - calendar_id = None - if issue.project_id and issue.project_id.resource_calendar_id: - calendar_id = issue.project_id.resource_calendar_id.id + # if the working hours on the project are not defined, use default ones (8 -> 12 and 13 -> 17 * 5) + calendar = issue.project_id.resource_calendar_id dt_create_date = fields.Datetime.from_string(issue.create_date) if issue.date_open: dt_date_open = fields.Datetime.from_string(issue.date_open) issue.day_open = (dt_date_open - dt_create_date).total_seconds() / (24.0 * 3600) - # FIXME when resource.calendar is migrated to new api - # Old api call because get_working_hours uses get_weekdays - # which has a different behavior if the given id is None. - issue.working_hours_open = self.pool['resource.calendar'].get_working_hours( - self.env.cr, self.env.uid, calendar_id, dt_create_date, dt_date_open, - compute_leaves=True, resource_id=False, default_interval=(8, 16), - context=self.env.context - ) + issue.working_hours_open = calendar.get_working_hours(dt_create_date, dt_date_open, + compute_leaves=True, resource_id=False, default_interval=(8, 16)) if issue.date_closed: dt_date_closed = fields.Datetime.from_string(issue.date_closed) issue.day_close = (dt_date_closed - dt_create_date).total_seconds() / (24.0 * 3600) - # FIXME when resource.calendar is migrated to new api - # Old api call because get_working_hours uses get_weekdays - # which has a different behavior if the given id is None. - issue.working_hours_close = self.pool['resource.calendar'].get_working_hours( - self.env.cr, self.env.uid, calendar_id, dt_create_date, dt_date_closed, - compute_leaves=True, resource_id=False, default_interval=(8, 16), - context=self.env.context - ) + issue.working_hours_close = calendar.get_working_hours(dt_create_date, dt_date_closed, + compute_leaves=True, resource_id=False, default_interval=(8, 16)) @api.multi @api.depends('create_date', 'date_action_last', 'date_last_stage_update') diff --git a/addons/resource/__init__.py b/addons/resource/__init__.py index 4ca401409b4..81fc81d29c9 100644 --- a/addons/resource/__init__.py +++ b/addons/resource/__init__.py @@ -1,4 +1,4 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -import resource +import models diff --git a/addons/resource/__openerp__.py b/addons/resource/__openerp__.py index 9ca5c246d5f..1c79b94ace0 100644 --- a/addons/resource/__openerp__.py +++ b/addons/resource/__openerp__.py @@ -2,10 +2,9 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. { - 'name' : 'Resource', - 'version' : '1.1', - 'category' : 'Hidden', - 'website' : 'http://www.openerp.com', + 'name': 'Resource', + 'version': '1.1', + 'category': 'Hidden', 'description': """ Module for resource management. =============================== @@ -18,13 +17,7 @@ associated to every resource. It also manages the leaves of every resource. 'data': [ 'security/ir.model.access.csv', 'security/resource_security.xml', - 'resource_view.xml', + 'views/resource_views.xml', ], - 'demo': ['resource_demo.xml'], - 'test': [ - 'test/resource.yml', - 'test/duplicate_resource.yml', - ], - 'installable': True, - 'auto_install': False, + 'demo': ['data/resource_demo.xml'], } diff --git a/addons/resource/resource_demo.xml b/addons/resource/data/resource_demo.xml similarity index 99% rename from addons/resource/resource_demo.xml rename to addons/resource/data/resource_demo.xml index 509e57ca262..7869468483c 100644 --- a/addons/resource/resource_demo.xml +++ b/addons/resource/data/resource_demo.xml @@ -1,6 +1,5 @@ - - + @@ -121,5 +120,4 @@ - - + diff --git a/addons/resource/models/__init__.py b/addons/resource/models/__init__.py new file mode 100644 index 00000000000..4ca401409b4 --- /dev/null +++ b/addons/resource/models/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import resource diff --git a/addons/resource/resource.py b/addons/resource/models/resource.py similarity index 68% rename from addons/resource/resource.py rename to addons/resource/models/resource.py index 3f41e2c1552..b10637cdbaa 100644 --- a/addons/resource/resource.py +++ b/addons/resource/models/resource.py @@ -2,21 +2,19 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. import datetime -import functools +import pytz + from datetime import timedelta from dateutil import rrule from dateutil.relativedelta import relativedelta -from openerp.tools import DEFAULT_SERVER_DATE_FORMAT from operator import itemgetter -from openerp import tools -from openerp.osv import fields, osv -from openerp.tools.float_utils import float_compare -from openerp.tools.translate import _ -from openerp.exceptions import UserError -import pytz +from odoo import api, fields, models, _ +from odoo.exceptions import ValidationError +from odoo.tools.float_utils import float_compare -class resource_calendar(osv.osv): + +class ResourceCalendar(models.Model): """ Calendar model for a resource. It has - attendance_ids: list of resource.calendar.attendance that are a working @@ -30,19 +28,15 @@ class resource_calendar(osv.osv): _name = "resource.calendar" _description = "Resource Calendar" - _columns = { - 'name': fields.char("Name", required=True), - 'company_id': fields.many2one('res.company', 'Company', required=False), - 'attendance_ids': fields.one2many('resource.calendar.attendance', 'calendar_id', 'Working Time', copy=True), - 'manager': fields.many2one('res.users', 'Workgroup Manager'), - 'leave_ids': fields.one2many( - 'resource.calendar.leaves', 'calendar_id', 'Leaves', - help='' - ), - } - _defaults = { - 'company_id': lambda self, cr, uid, context: self.pool.get('res.company')._company_default_get(cr, uid, 'resource.calendar', context=context) - } + name = fields.Char(required=True) + company_id = fields.Many2one('res.company', string='Company', + default=lambda self: self.env['res.company']._company_default_get()) + attendance_ids = fields.One2many( + 'resource.calendar.attendance', 'calendar_id', string='Working Time', + copy=True) + manager = fields.Many2one('res.users', string='Workgroup Manager') + leave_ids = fields.One2many( + 'resource.calendar.leaves', 'calendar_id', string='Leaves') # -------------------------------------------------- # Utility methods @@ -72,7 +66,8 @@ class resource_calendar(osv.osv): cleaned.append(tuple(working_interval)) return cleaned - def interval_remove_leaves(self, cr, uid, interval, leave_intervals, context=None): + @api.model + 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 @@ -112,7 +107,6 @@ class resource_calendar(osv.osv): current_interval[1] = leave[0] intervals.append((current_interval[0], current_interval[1])) current_interval = [leave[1], interval[1]] - # if current_interval[0] <= leave[1] <= current_interval[1]: if current_interval[0] <= leave[1]: current_interval[0] = leave[1] if current_interval and current_interval[0] < interval[1]: # remove intervals moved outside base interval due to leaves @@ -139,14 +133,14 @@ class resource_calendar(osv.osv): is greater than the possible scheduling in the intervals, no extra-scheduling is done, and results == intervals. """ results = [] - res = datetime.timedelta() - limit = datetime.timedelta(hours=hour) + res = timedelta() + limit = timedelta(hours=hour) for interval in intervals: res += interval[1] - interval[0] if res > limit and remove_at_end: - interval = (interval[0], interval[1] + relativedelta(seconds=seconds(limit-res))) + interval = (interval[0], interval[1] + relativedelta(seconds=seconds(limit - res))) elif res > limit: - interval = (interval[0] + relativedelta(seconds=seconds(res-limit)), interval[1]) + interval = (interval[0] + relativedelta(seconds=seconds(res - limit)), interval[1]) results.append(interval) if res > limit: break @@ -156,41 +150,40 @@ class resource_calendar(osv.osv): # Date and hours computation # -------------------------------------------------- - def get_attendances_for_weekday(self, cr, uid, id, date, context=None): + @api.multi + def get_attendances_for_weekday(self, date): """ Given a list of weekdays, return matching resource.calendar.attendance""" - calendar = self.browse(cr, uid, id, context=None) + self.ensure_one() weekday = date.weekday() - date = date.strftime(DEFAULT_SERVER_DATE_FORMAT) - res = [] - for att in calendar.attendance_ids: - if int(att.dayofweek) == weekday: - if not ((att.date_from and date < att.date_from) or (att.date_to and date > att.date_to)): - res.append(att) - return res + date = fields.Date.today() + attendances = self.env['resource.calendar.attendance'] + for attendance in self.attendance_ids.filtered(lambda att: int(att.dayofweek) == weekday and + not ((att.date_from and date < att.date_from) or (att.date_to and date > att.date_to))): + attendances |= attendance + return attendances - def get_weekdays(self, cr, uid, id, default_weekdays=None, context=None): + @api.multi + def get_weekdays(self, default_weekdays=None): """ Return the list of weekdays that contain at least one working interval. If no id is given (no calendar), return default weekdays. """ - if id is None: + if not self: return default_weekdays if default_weekdays is not None else [0, 1, 2, 3, 4] - calendar = self.browse(cr, uid, id, context=None) - weekdays = set() - for attendance in calendar.attendance_ids: - weekdays.add(int(attendance.dayofweek)) + self.ensure_one() + weekdays = set(map(int, (self.attendance_ids.mapped('dayofweek')))) return list(weekdays) - def get_next_day(self, cr, uid, id, day_date, context=None): + @api.multi + def get_next_day(self, day_date): """ Get following date of day_date, based on resource.calendar. If no calendar is provided, just return the next day. - :param int id: id of a resource.calendar. If not given, simply add one day - to the submitted date. :param date day_date: current day as a date :return date: next day of calendar, or just next day """ - if not id: + if not self: return day_date + relativedelta(days=1) - weekdays = self.get_weekdays(cr, uid, id, context) + self.ensure_one() + weekdays = self.get_weekdays() base_index = -1 for weekday in weekdays: @@ -205,18 +198,18 @@ class resource_calendar(osv.osv): return day_date + relativedelta(days=days) - def get_previous_day(self, cr, uid, id, day_date, context=None): + @api.multi + def get_previous_day(self, day_date): """ Get previous date of day_date, based on resource.calendar. If no calendar is provided, just return the previous day. - :param int id: id of a resource.calendar. If not given, simply remove - one day from the submitted date. :param date day_date: current day as a date :return date: previous day of calendar, or just previous day """ - if not id: + if not self: return day_date + relativedelta(days=-1) - weekdays = self.get_weekdays(cr, uid, id, context) + self.ensure_one() + weekdays = self.get_weekdays() weekdays.reverse() base_index = -1 @@ -232,9 +225,9 @@ class resource_calendar(osv.osv): return day_date + relativedelta(days=days) - def get_leave_intervals(self, cr, uid, id, resource_id=None, - start_datetime=None, end_datetime=None, - context=None): + @api.multi + 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. @@ -250,27 +243,27 @@ class resource_calendar(osv.osv): :return list leaves: list of tuples (start_datetime, end_datetime) of leave intervals """ - resource_calendar = self.browse(cr, uid, id, context=context) + self.ensure_one() leaves = [] - for leave in resource_calendar.leave_ids: + for leave in self.leave_ids: if leave.resource_id and not resource_id == leave.resource_id.id: continue - date_from = datetime.datetime.strptime(leave.date_from, tools.DEFAULT_SERVER_DATETIME_FORMAT) + date_from = fields.Datetime.from_string(leave.date_from) if end_datetime and date_from > end_datetime: continue - date_to = datetime.datetime.strptime(leave.date_to, tools.DEFAULT_SERVER_DATETIME_FORMAT) + date_to = fields.Datetime.from_string(leave.date_to) if start_datetime and date_to < start_datetime: continue leaves.append((date_from, date_to)) return leaves - def get_working_intervals_of_day(self, cr, uid, id, start_dt=None, end_dt=None, + @api.multi + def get_working_intervals_of_day(self, start_dt=None, end_dt=None, leaves=None, compute_leaves=False, resource_id=None, - default_interval=None, context=None): + default_interval=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. - :param int id: resource.calendar id; take the first one if is a list :param datetime start_dt: datetime object that is the beginning hours for the working intervals computation; any working interval beginning before start_dt @@ -300,8 +293,6 @@ class resource_calendar(osv.osv): :return list intervals: a list of tuples (start_datetime, end_datetime) of work intervals """ - if isinstance(id, (list, tuple)): - id = id[0] # Computes start_dt, end_dt (with default values if not set) + off-interval work limits work_limits = [] @@ -321,17 +312,17 @@ class resource_calendar(osv.osv): work_dt = start_dt.replace(hour=0, minute=0, second=0) # no calendar: try to use the default_interval, then return directly - if id is None: + if not self: working_interval = [] if default_interval: working_interval = (start_dt.replace(hour=default_interval[0], minute=0, second=0), start_dt.replace(hour=default_interval[1], minute=0, second=0)) - intervals = self.interval_remove_leaves(cr, uid, working_interval, work_limits, context=context) + intervals = self.interval_remove_leaves(working_interval, work_limits) return intervals working_intervals = [] - tz_info = fields.datetime.context_timestamp(cr, uid, work_dt, context=context).tzinfo - for calendar_working_day in self.get_attendances_for_weekday(cr, uid, id, start_dt, context=context): + tz_info = fields.Datetime.context_timestamp(self, work_dt).tzinfo + for calendar_working_day in self.get_attendances_for_weekday(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)) @@ -341,41 +332,42 @@ class resource_calendar(osv.osv): dt_t.replace(tzinfo=tz_info).astimezone(pytz.UTC).replace(tzinfo=None), calendar_working_day.id ) - working_intervals += self.interval_remove_leaves(cr, uid, working_interval, work_limits, context=context) + 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(cr, uid, id, resource_id=resource_id, context=context) + leaves = self.get_leave_intervals(resource_id=resource_id) # filter according to leaves for interval in working_intervals: - work_intervals = self.interval_remove_leaves(cr, uid, interval, leaves, context=context) + work_intervals = self.interval_remove_leaves(interval, leaves) intervals += work_intervals return intervals - def get_working_hours_of_date(self, cr, uid, id, start_dt=None, end_dt=None, + @api.multi + def get_working_hours_of_date(self, start_dt=None, end_dt=None, leaves=None, compute_leaves=False, resource_id=None, - default_interval=None, context=None): + default_interval=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 = datetime.timedelta() + res = timedelta() intervals = self.get_working_intervals_of_day( - cr, uid, id, start_dt, end_dt, leaves, compute_leaves, resource_id, - default_interval, context) + default_interval) for interval in intervals: res += interval[1] - interval[0] return seconds(res) / 3600.0 - def get_working_hours(self, cr, uid, id, start_dt, end_dt, compute_leaves=False, - resource_id=None, default_interval=None, context=None): + @api.multi + def get_working_hours(self, start_dt, end_dt, compute_leaves=False, + resource_id=None, default_interval=None): hours = 0.0 for day in rrule.rrule(rrule.DAILY, dtstart=start_dt, - until=(end_dt + datetime.timedelta(days=1)).replace(hour=0, minute=0, second=0), - byweekday=self.get_weekdays(cr, uid, id, context=context)): + until=(end_dt + timedelta(days=1)).replace(hour=0, minute=0, second=0), + 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 @@ -383,20 +375,19 @@ class resource_calendar(osv.osv): if end_dt and day.date() == end_dt.date(): day_end_dt = end_dt hours += self.get_working_hours_of_date( - cr, uid, id, start_dt=day_start_dt, end_dt=day_end_dt, + start_dt=day_start_dt, end_dt=day_end_dt, compute_leaves=compute_leaves, resource_id=resource_id, - default_interval=default_interval, - context=context) + default_interval=default_interval) return hours # -------------------------------------------------- # Hours scheduling # -------------------------------------------------- - - def _schedule_hours(self, cr, uid, id, hours, day_dt=None, + @api.multi + def _schedule_hours(self, hours, day_dt=None, compute_leaves=False, resource_id=None, - default_interval=None, context=None): + default_interval=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. @@ -436,7 +427,7 @@ class resource_calendar(osv.osv): iterations = 0 current_datetime = day_dt - call_args = dict(compute_leaves=compute_leaves, resource_id=resource_id, default_interval=default_interval, context=context) + call_args = dict(compute_leaves=compute_leaves, resource_id=resource_id, default_interval=default_interval) while float_compare(remaining_hours, 0.0, precision_digits=2) in (1, 0) and iterations < 1000: if backwards: @@ -444,9 +435,9 @@ class resource_calendar(osv.osv): else: call_args['start_dt'] = current_datetime - working_intervals = self.get_working_intervals_of_day(cr, uid, id, **call_args) + working_intervals = self.get_working_intervals_of_day(**call_args) - if id is None and not working_intervals: # no calendar -> consider working 8 hours + if not self and not working_intervals: # no calendar -> consider working 8 hours remaining_hours -= 8.0 elif working_intervals: if backwards: @@ -455,7 +446,7 @@ class resource_calendar(osv.osv): if backwards: new_working_intervals.reverse() - res = datetime.timedelta() + res = timedelta() for interval in working_intervals: res += interval[1] - interval[0] remaining_hours -= (seconds(res) / 3600.0) @@ -465,36 +456,38 @@ class resource_calendar(osv.osv): intervals = intervals + new_working_intervals # get next day if backwards: - current_datetime = datetime.datetime.combine(self.get_previous_day(cr, uid, id, current_datetime, context), datetime.time(23, 59, 59)) + current_datetime = datetime.datetime.combine(self.get_previous_day(current_datetime), datetime.time(23, 59, 59)) else: - current_datetime = datetime.datetime.combine(self.get_next_day(cr, uid, id, current_datetime, context), datetime.time()) + current_datetime = datetime.datetime.combine(self.get_next_day(current_datetime), datetime.time()) # avoid infinite loops iterations += 1 return intervals - def schedule_hours_get_date(self, cr, uid, id, hours, day_dt=None, + @api.multi + def schedule_hours_get_date(self, hours, day_dt=None, compute_leaves=False, resource_id=None, - default_interval=None, context=None): + default_interval=None): """ Wrapper on _schedule_hours: return the beginning/ending datetime of an hours scheduling. """ - res = self._schedule_hours(cr, uid, id, hours, day_dt, compute_leaves, resource_id, default_interval, context) + res = self._schedule_hours(hours, day_dt, compute_leaves, resource_id, default_interval) return res and res[0][0] or False - def schedule_hours(self, cr, uid, id, hours, day_dt=None, + @api.multi + def schedule_hours(self, hours, day_dt=None, compute_leaves=False, resource_id=None, - default_interval=None, context=None): + default_interval=None): """ Wrapper on _schedule_hours: return the working intervals of an hours scheduling. """ - return self._schedule_hours(cr, uid, id, hours, day_dt, compute_leaves, resource_id, default_interval, context) - + return self._schedule_hours(hours, day_dt, compute_leaves, resource_id, default_interval) # -------------------------------------------------- # Days scheduling # -------------------------------------------------- - def _schedule_days(self, cr, uid, id, days, day_date=None, compute_leaves=False, - resource_id=None, default_interval=None, context=None): + @api.multi + def _schedule_days(self, days, day_date=None, compute_leaves=False, + resource_id=None, default_interval=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. @@ -536,157 +529,165 @@ class resource_calendar(osv.osv): while planned_days < days and iterations < 100: working_intervals = self.get_working_intervals_of_day( - cr, uid, id, current_datetime, + current_datetime, compute_leaves=compute_leaves, resource_id=resource_id, - default_interval=default_interval, - context=context) - if id is None or working_intervals: # no calendar -> no working hours, but day is considered as worked + default_interval=default_interval) + if not self or working_intervals: # no calendar -> no working hours, but day is considered as worked planned_days += 1 intervals += working_intervals # get next day if backwards: - current_datetime = self.get_previous_day(cr, uid, id, current_datetime, context) + current_datetime = self.get_previous_day(current_datetime) else: - current_datetime = self.get_next_day(cr, uid, id, current_datetime, context) + current_datetime = self.get_next_day(current_datetime) # avoid infinite loops iterations += 1 return intervals - def schedule_days_get_date(self, cr, uid, id, days, day_date=None, compute_leaves=False, - resource_id=None, default_interval=None, context=None): + @api.multi + def schedule_days_get_date(self, days, day_date=None, compute_leaves=False, + resource_id=None, default_interval=None): """ Wrapper on _schedule_days: return the beginning/ending datetime of a days scheduling. """ - res = self._schedule_days(cr, uid, id, days, day_date, compute_leaves, resource_id, default_interval, context) + res = self._schedule_days(days, day_date, compute_leaves, resource_id, default_interval) return res and res[-1][1] or False - def schedule_days(self, cr, uid, id, days, day_date=None, compute_leaves=False, - resource_id=None, default_interval=None, context=None): + @api.multi + def schedule_days(self, days, day_date=None, compute_leaves=False, + resource_id=None, default_interval=None): """ Wrapper on _schedule_days: return the working intervals of a days scheduling. """ - return self._schedule_days(cr, uid, id, days, day_date, compute_leaves, resource_id, default_interval, context) + return self._schedule_days(days, day_date, compute_leaves, resource_id, default_interval) # -------------------------------------------------- # Compatibility / to clean / to remove # -------------------------------------------------- - def working_hours_on_day(self, cr, uid, resource_calendar_id, day, context=None): + @api.multi + def working_hours_on_day(self, day): """ Used in hr_payroll/hr_payroll.py - :deprecated: OpenERP saas-3. Use get_working_hours_of_date instead. Note: + :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(cr, uid, resource_calendar_id.id, start_dt=day, context=None) + return self.get_working_hours_of_date(start_dt=day) - def interval_min_get(self, cr, uid, id, dt_from, hours, resource=False): + @api.multi + def interval_min_get(self, dt_from, hours, resource=False): """ Schedule hours backwards. Used in mrp_operations/mrp_operations.py. - :deprecated: OpenERP saas-3. Use schedule_hours instead. Note: since + :deprecated: Odoo saas-3. Use schedule_hours instead. Note: since saas-3, counts leave hours instead of all-day leaves.""" return self.schedule_hours( - cr, uid, id, hours * -1.0, + hours * -1.0, day_dt=dt_from.replace(minute=0, second=0), compute_leaves=True, resource_id=resource, default_interval=(8, 16) ) - def interval_get_multi(self, cr, uid, date_and_hours_by_cal, resource=False, byday=True): + @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: OpenERP saas-3. Use schedule_hours instead. Note: + :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.schedule_hours( - cr, uid, calendar_id, hours, - day_dt=datetime.datetime.strptime(dt_str, '%Y-%m-%d %H:%M:%S').replace(second=0), + 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, default_interval=(8, 16) ) res[(dt_str, hours, calendar_id)] = result return res - def interval_get(self, cr, uid, id, dt_from, hours, resource=False, byday=True): + @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: OpenERP saas-3. Use get_working_hours instead.""" + :deprecated: Odoo saas-3. Use get_working_hours instead.""" + self.ensure_one() res = self.interval_get_multi( - cr, uid, [(dt_from.strftime('%Y-%m-%d %H:%M:%S'), hours, id)], resource, byday)[(dt_from.strftime('%Y-%m-%d %H:%M:%S'), hours, id)] + [(fields.Datetime.to_string(dt_from), hours, self.id)], resource, byday)[(fields.Datetime.to_string(dt_from), hours, self.id)] return res - def interval_hours_get(self, cr, uid, id, dt_from, dt_to, resource=False): + @api.multi + def interval_hours_get(self, dt_from, dt_to, resource=False): """ Unused wrapper. - :deprecated: OpenERP saas-3. Use get_working_hours instead.""" - return self._interval_hours_get(cr, uid, id, dt_from, dt_to, resource_id=resource) + :deprecated: Odoo saas-3. Use get_working_hours instead.""" + return self._interval_hours_get(dt_from, dt_to, resource_id=resource) - def _interval_hours_get(self, cr, uid, id, dt_from, dt_to, resource_id=False, timezone_from_uid=None, exclude_leaves=True, context=None): - """ Computes working hours between two dates, taking always same hour/minutes. - - :deprecated: OpenERP saas-3. Use get_working_hours instead. Note: since saas-3, + @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( - cr, uid, id, dt_from, dt_to, + dt_from, dt_to, compute_leaves=(not exclude_leaves), resource_id=resource_id, - default_interval=(8, 16), context=context) + default_interval=(8, 16)) -class resource_calendar_attendance(osv.osv): +class ResourceCalendarAttendance(models.Model): _name = "resource.calendar.attendance" _description = "Work Detail" - - _columns = { - 'name' : fields.char("Name", required=True), - 'dayofweek': fields.selection([('0','Monday'),('1','Tuesday'),('2','Wednesday'),('3','Thursday'),('4','Friday'),('5','Saturday'),('6','Sunday')], 'Day of Week', required=True, select=True), - 'date_from' : fields.date('Starting Date'), - 'date_to': fields.date('End Date'), - 'hour_from' : fields.float('Work from', required=True, help="Start and End time of working.", select=True), - 'hour_to' : fields.float("Work to", required=True), - 'calendar_id' : fields.many2one("resource.calendar", "Resource's Calendar", required=True), - } - _order = 'dayofweek, hour_from' - _defaults = { - 'dayofweek' : '0' - } + name = fields.Char(required=True) + dayofweek = fields.Selection([ + ('0', 'Monday'), + ('1', 'Tuesday'), + ('2', 'Wednesday'), + ('3', 'Thursday'), + ('4', 'Friday'), + ('5', 'Saturday'), + ('6', 'Sunday') + ], 'Day of Week', required=True, index=True, default='0') + date_from = fields.Date(string='Starting Date') + date_to = fields.Date(string='End Date') + hour_from = fields.Float(string='Work from', required=True, index=True, help="Start and End time of working.") + hour_to = fields.Float(string='Work to', required=True) + calendar_id = fields.Many2one("resource.calendar", string="Resource's Calendar", required=True) + 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 resource_resource(osv.osv): + +class ResourceResource(models.Model): _name = "resource.resource" _description = "Resource Detail" - _columns = { - 'name': fields.char("Name", required=True), - 'code': fields.char('Code', size=16, copy=False), - 'active' : fields.boolean('Active', track_visibility='onchange', - help="If the active field is set to False, it will allow you to hide the resource record without removing it."), - 'company_id' : fields.many2one('res.company', 'Company'), - 'resource_type': fields.selection([('user','Human'),('material','Material')], 'Resource Type', required=True), - 'user_id' : fields.many2one('res.users', 'User', help='Related user name for the resource to manage its access.'), - 'time_efficiency' : fields.float('Efficiency Factor', size=8, required=True, help="An efficiency of 50% means the resource is two times smaller than his usual speed."), - 'calendar_id' : fields.many2one("resource.calendar", "Working Time", help="Define the schedule of resource"), - } - _defaults = { - 'resource_type' : 'user', - 'time_efficiency' : 100, - 'active' : True, - 'company_id': lambda self, cr, uid, context: self.pool.get('res.company')._company_default_get(cr, uid, 'resource.resource', context=context) - } + name = fields.Char(required=True) + code = fields.Char(copy=False) + active = fields.Boolean(track_visibility='onchange', default=True, + help="If the active field is set to False, it will allow you to hide the resource record without removing it.") + company_id = fields.Many2one('res.company', string='Company', default=lambda self: self.env['res.company']._company_default_get()) + resource_type = fields.Selection([ + ('user', 'Human'), + ('material', 'Material') + ], string='Resource Type', required=True, default='user') + user_id = fields.Many2one('res.users', string='User', help='Related user name for the resource to manage its access.') + time_efficiency = fields.Float(string='Efficiency Factor', required=True, default=100, + help="This field depict the efficiency of the resource to complete tasks. e.g resource put alone on a phase of 5 days with 5 tasks assigned to him, will show a load of 100% for this phase by default, but if we put a efficiency of 200%, then his load will only be 50%.") + calendar_id = fields.Many2one("resource.calendar", string='Working Time', help="Define the schedule of resource") - def copy(self, cr, uid, id, default=None, context=None): + @api.multi + def copy(self, default=None): + self.ensure_one() if default is None: default = {} - if not default.get('name', False): - default.update(name=_('%s (copy)') % (self.browse(cr, uid, id, context=context).name)) - return super(resource_resource, self).copy(cr, uid, id, default, context) + if not default.get('name'): + default.update(name=_('%s (copy)') % (self.name)) + return super(ResourceResource, self).copy(default) def _is_work_day(self, date): """ Whether the provided date is a work day for the subject resource. @@ -719,37 +720,28 @@ class resource_resource(osv.osv): if intervals and intervals[0]: yield dt.date() -class resource_calendar_leaves(osv.osv): +class ResourceCalendarLeaves(models.Model): _name = "resource.calendar.leaves" _description = "Leave Detail" - _columns = { - 'name' : fields.char("Name"), - 'company_id' : fields.related('calendar_id','company_id',type='many2one',relation='res.company',string="Company", store=True, readonly=True), - 'calendar_id' : fields.many2one("resource.calendar", "Working Time"), - 'date_from' : fields.datetime('Start Date', required=True), - 'date_to' : fields.datetime('End Date', required=True), - 'resource_id' : fields.many2one("resource.resource", "Resource", help="If empty, this is a generic holiday for the company. If a resource is set, the holiday/leave is only for this resource"), - } - def check_dates(self, cr, uid, ids, context=None): - for leave in self.browse(cr, uid, ids, context=context): - if leave.date_from and leave.date_to and leave.date_from > leave.date_to: - return False - return True + name = fields.Char() + company_id = fields.Many2one('res.company', related='calendar_id.company_id', string="Company", store=True, readonly=True) + calendar_id = fields.Many2one('resource.calendar', string='Working Time') + date_from = fields.Datetime(string='Start Date', required=True) + date_to = fields.Datetime(string='End Date', required=True) + resource_id = fields.Many2one("resource.resource", string='Resource', + help="If empty, this is a generic holiday for the company. If a resource is set, the holiday/leave is only for this resource") - _constraints = [ - (check_dates, 'Error! leave start-date must be lower then leave end-date.', ['date_from', 'date_to']) - ] + @api.constrains('date_from', 'date_to') + def check_dates(self): + if self.filtered(lambda leave: leave.date_from > leave.date_to): + raise ValidationError(_('Error! leave start-date must be lower then leave end-date.')) - def onchange_resource(self, cr, uid, ids, resource, context=None): - result = {} - if resource: - resource_pool = self.pool.get('resource.resource') - result['calendar_id'] = resource_pool.browse(cr, uid, resource, context=context).calendar_id.id - return {'value': result} - return {'value': {'calendar_id': []}} + @api.onchange('resource_id') + def onchange_resource(self): + self.calendar_id = self.resource_id.calendar_id def seconds(td): - assert isinstance(td, datetime.timedelta) + assert isinstance(td, timedelta) return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10.**6 diff --git a/addons/resource/security/resource_security.xml b/addons/resource/security/resource_security.xml index 43bfa6c3a4b..d33fdebc296 100644 --- a/addons/resource/security/resource_security.xml +++ b/addons/resource/security/resource_security.xml @@ -1,5 +1,5 @@ - + @@ -13,4 +13,4 @@ - + diff --git a/addons/resource/test/duplicate_resource.yml b/addons/resource/test/duplicate_resource.yml deleted file mode 100644 index 5869530e2f4..00000000000 --- a/addons/resource/test/duplicate_resource.yml +++ /dev/null @@ -1,6 +0,0 @@ -- - I duplicate the resource "Analyst" -- - !python {model: resource.resource}: | - copied_id = self.copy(cr, uid, ref("resource_analyst")) - assert copied_id, "Unable to Duplicate Resource" diff --git a/addons/resource/test/resource.yml b/addons/resource/test/resource.yml deleted file mode 100644 index 40fa0cab7c4..00000000000 --- a/addons/resource/test/resource.yml +++ /dev/null @@ -1,53 +0,0 @@ -- - In order to test resource. -- - I assign working calendar '45 Hours/Week' to human resource. -- - !python {model: resource.resource}: | - self.write(cr, uid, [ref('resource_analyst'), ref('resource_designer'), ref('resource_developer')], {'calendar_id' : ref('timesheet_group1'), 'resource_type': 'user'}) - -- - I had Project of OpenERP Integration of 50 Hours with three human resource assigned on it. I have started project from this week start. -- - I check per day work hour availability of the Resource based on Working Calendar Assigned to each resource, for first day of the week. -- - !python {model: resource.resource}: | - from openerp.tools import float_compare - calendar_pool = self.pool.get('resource.calendar') - resources = self.browse(cr, uid, [ref('resource_analyst'), ref('resource_designer'), ref('resource_developer')], context) - from datetime import datetime, timedelta - now = datetime.now() - dt = now - timedelta(days=now.weekday()) - for resource in resources: - result = calendar_pool.working_hours_on_day(cr, uid, resource.calendar_id, dt, context) - assert float_compare(result, 8.0, precision_digits=2) == 0, 'Wrong calculation of day work hour availability of the Resource (found %d).' % result -- - Now, resource "Developer" drafted leave on Thursday in this week. -- - !python {model: resource.calendar.leaves}: | - from datetime import datetime,timedelta - now = datetime.now() - dt = (now - timedelta(days=now.weekday()) ) + timedelta(days=3) - self.write(cr, uid, [ref('resource_dummyleave')], {'resource_id': ref('resource_developer'), 'calendar_id': ref('timesheet_group1'), 'date_from': dt.strftime("%Y-%m-%d 09:00:00"), 'date_to': dt.strftime("%Y-%m-%d 18:00:00")}) - -- - I check Actual working hours on resource 'Developer' from this week -- - !python {model: resource.calendar}: | - from datetime import datetime - from dateutil.relativedelta import relativedelta - now = datetime.now() - dt_from = now - relativedelta(days=now.weekday(), hour=8, minute=30) - dt_to = dt_from + relativedelta(days=6, hour=17) - hours = self.interval_hours_get(cr, uid, ref('timesheet_group1'), dt_from, dt_to, resource=ref('resource_developer')) - assert hours > 27 , 'Invalid Total Week working hour calculated, got %r, expected > 27' % hours -- - Project Analysis work is of 20 hours which will start from Week start so i will calculate working schedule for resource Analyst for the same. -- - !python {model: resource.calendar}: | - - from datetime import datetime, timedelta - now = datetime.now() - work_intreval = self.interval_min_get(cr, uid, ref('timesheet_group1'), now, 20.0, resource=ref('resource_designer')) - assert len(work_intreval) >= 5, 'Wrong Schedule Calculated' - diff --git a/addons/resource/tests/common.py b/addons/resource/tests/common.py index adb813be3d3..686070dd27f 100644 --- a/addons/resource/tests/common.py +++ b/addons/resource/tests/common.py @@ -1,106 +1,102 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from datetime import datetime - -from openerp.tests import common +from odoo.fields import Datetime +from odoo.tests.common import TransactionCase -class TestResourceCommon(common.TransactionCase): +class TestResourceCommon(TransactionCase): def setUp(self): super(TestResourceCommon, self).setUp() - cr, uid = self.cr, self.uid self.context = context = dict(tz='UTC') - self.registry('res.users').write(cr, uid, uid, {'tz': 'UTC'}, context=context) + self.env['res.users'].browse(self.env.uid).with_context(context).write({'tz': 'UTC'}) # Usefull models - self.resource_resource = self.registry('resource.resource') - self.resource_calendar = self.registry('resource.calendar') - self.resource_attendance = self.registry('resource.calendar.attendance') - self.resource_leaves = self.registry('resource.calendar.leaves') + self.Resource = self.env['resource.resource'] + self.ResourceCalendar = self.env['resource.calendar'] + self.ResourceAttendance = self.env['resource.calendar.attendance'] + self.ResourceLeaves = self.env['resource.calendar.leaves'] # Some demo data - self.date1 = datetime.strptime('2013-02-12 09:08:07', '%Y-%m-%d %H:%M:%S') # weekday() returns 1, isoweekday() returns 2 - self.date2 = datetime.strptime('2013-02-15 10:11:12', '%Y-%m-%d %H:%M:%S') # weekday() returns 4, isoweekday() returns 5 + self.date1 = Datetime.from_string('2013-02-12 09:08:07') # weekday() returns 1, isoweekday() returns 2 + self.date2 = Datetime.from_string('2013-02-15 10:11:12') # weekday() returns 4, isoweekday() returns 5 # Leave1: 19/02/2013, from 9 to 12, is a day 1 - self.leave1_start = datetime.strptime('2013-02-19 09:00:00', '%Y-%m-%d %H:%M:%S') - self.leave1_end = datetime.strptime('2013-02-19 12:00:00', '%Y-%m-%d %H:%M:%S') + self.leave1_start = Datetime.from_string('2013-02-19 09:00:00') + self.leave1_end = Datetime.from_string('2013-02-19 12:00:00') # Leave2: 22/02/2013, from 9 to 15, is a day 4 - self.leave2_start = datetime.strptime('2013-02-22 09:00:00', '%Y-%m-%d %H:%M:%S') - self.leave2_end = datetime.strptime('2013-02-22 15:00:00', '%Y-%m-%d %H:%M:%S') + self.leave2_start = Datetime.from_string('2013-02-22 09:00:00') + self.leave2_end = Datetime.from_string('2013-02-22 15:00:00') # Leave3: 25/02/2013 (day0) -> 01/03/2013 (day4) - self.leave3_start = datetime.strptime('2013-02-25 13:00:00', '%Y-%m-%d %H:%M:%S') - self.leave3_end = datetime.strptime('2013-03-01 11:30:00', '%Y-%m-%d %H:%M:%S') + self.leave3_start = Datetime.from_string('2013-02-25 13:00:00') + self.leave3_end = Datetime.from_string('2013-03-01 11:30:00') # Resource data # Calendar working days: 1 (8-16 -> 8hours), 4 (8-13, 16-23 -> 12hours) - self.calendar_id = self.resource_calendar.create( - cr, uid, { + self.calendar = self.ResourceCalendar.with_context(context).create( + { 'name': 'TestCalendar', - }, context=context + } ) - self.att1_id = self.resource_attendance.create( - cr, uid, { + self.att1_id = self.ResourceAttendance.with_context(context).create( + { 'name': 'Att1', 'dayofweek': '1', 'hour_from': 8, 'hour_to': 16, - 'calendar_id': self.calendar_id, - }, context=context - ) - self.att2_id = self.resource_attendance.create( - cr, uid, { + 'calendar_id': self.calendar.id, + } + ).id + self.att2_id = self.ResourceAttendance.with_context(context).create( + { 'name': 'Att2', 'dayofweek': '4', 'hour_from': 8, 'hour_to': 13, - 'calendar_id': self.calendar_id, - }, context=context - ) - self.att3_id = self.resource_attendance.create( - cr, uid, { + 'calendar_id': self.calendar.id, + } + ).id + self.att3_id = self.ResourceAttendance.with_context(context).create( + { 'name': 'Att3', 'dayofweek': '4', 'hour_from': 16, 'hour_to': 23, - 'calendar_id': self.calendar_id, - }, context=context - ) - self.resource1_id = self.resource_resource.create( - cr, uid, { + 'calendar_id': self.calendar.id, + } + ).id + self.resource1_id = self.Resource.with_context(context).create( + { 'name': 'TestResource1', 'resource_type': 'user', 'time_efficiency': 150.0, - 'calendar_id': self.calendar_id, - }, context=context - ) - self.leave1_id = self.resource_leaves.create( - cr, uid, { + 'calendar_id': self.calendar.id, + } + ).id + self.leave1_id = self.ResourceLeaves.with_context(context).create( + { 'name': 'GenericLeave', - 'calendar_id': self.calendar_id, + 'calendar_id': self.calendar.id, 'date_from': self.leave1_start, 'date_to': self.leave1_end, - }, context=context - ) - self.leave2_id = self.resource_leaves.create( - cr, uid, { + } + ).id + self.leave2_id = self.ResourceLeaves.with_context(context).create( + { 'name': 'ResourceLeave', - 'calendar_id': self.calendar_id, + 'calendar_id': self.calendar.id, 'resource_id': self.resource1_id, 'date_from': self.leave2_start, 'date_to': self.leave2_end, - }, context=context - ) - self.leave3_id = self.resource_leaves.create( - cr, uid, { + } + ).id + self.leave3_id = self.ResourceLeaves.with_context(context).create( + { 'name': 'ResourceLeave2', - 'calendar_id': self.calendar_id, + 'calendar_id': self.calendar.id, 'resource_id': self.resource1_id, 'date_from': self.leave3_start, 'date_to': self.leave3_end, - }, context=context - ) - # Some browse data - self.calendar = self.resource_calendar.browse(cr, uid, self.calendar_id, context=context) + } + ).id diff --git a/addons/resource/tests/test_resource.py b/addons/resource/tests/test_resource.py index 208166a2108..3f2caa1d71e 100644 --- a/addons/resource/tests/test_resource.py +++ b/addons/resource/tests/test_resource.py @@ -6,7 +6,9 @@ from datetime import datetime, timedelta, date import babel.dates from dateutil.relativedelta import relativedelta -from openerp.addons.resource.tests.common import TestResourceCommon +from odoo.fields import Datetime +from odoo.tools import float_compare +from odoo.addons.resource.tests.common import TestResourceCommon from openerp.tests import TransactionCase @@ -14,93 +16,91 @@ from openerp.tests import TransactionCase class TestResource(TestResourceCommon): def test_00_intervals(self): - cr, uid = self.cr, self.uid intervals = [ ( - datetime.strptime('2013-02-04 09:00:00', '%Y-%m-%d %H:%M:%S'), - datetime.strptime('2013-02-04 11:00:00', '%Y-%m-%d %H:%M:%S') + Datetime.from_string('2013-02-04 09:00:00'), + Datetime.from_string('2013-02-04 11:00:00') ), ( - datetime.strptime('2013-02-04 08:00:00', '%Y-%m-%d %H:%M:%S'), - datetime.strptime('2013-02-04 12:00:00', '%Y-%m-%d %H:%M:%S') + Datetime.from_string('2013-02-04 08:00:00'), + Datetime.from_string('2013-02-04 12:00:00') ), ( - datetime.strptime('2013-02-04 11:00:00', '%Y-%m-%d %H:%M:%S'), - datetime.strptime('2013-02-04 14:00:00', '%Y-%m-%d %H:%M:%S') + Datetime.from_string('2013-02-04 11:00:00'), + Datetime.from_string('2013-02-04 14:00:00') ), ( - datetime.strptime('2013-02-04 17:00:00', '%Y-%m-%d %H:%M:%S'), - datetime.strptime('2013-02-04 21:00:00', '%Y-%m-%d %H:%M:%S') + Datetime.from_string('2013-02-04 17:00:00'), + Datetime.from_string('2013-02-04 21:00:00') ), ( - datetime.strptime('2013-02-03 08:00:00', '%Y-%m-%d %H:%M:%S'), - datetime.strptime('2013-02-03 10:00:00', '%Y-%m-%d %H:%M:%S') + Datetime.from_string('2013-02-03 08:00:00'), + Datetime.from_string('2013-02-03 10:00:00') ), ( - datetime.strptime('2013-02-04 18:00:00', '%Y-%m-%d %H:%M:%S'), - datetime.strptime('2013-02-04 19:00:00', '%Y-%m-%d %H:%M:%S') + Datetime.from_string('2013-02-04 18:00:00'), + Datetime.from_string('2013-02-04 19:00:00') ) ] # Test: interval cleaning - cleaned_intervals = self.resource_calendar.interval_clean(intervals) + cleaned_intervals = self.ResourceCalendar.interval_clean(intervals) self.assertEqual(len(cleaned_intervals), 3, 'resource_calendar: wrong interval cleaning') # First interval: 03, unchanged - self.assertEqual(cleaned_intervals[0][0], datetime.strptime('2013-02-03 08:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong interval cleaning') - self.assertEqual(cleaned_intervals[0][1], datetime.strptime('2013-02-03 10:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong interval cleaning') + self.assertEqual(cleaned_intervals[0][0], Datetime.from_string('2013-02-03 08:00:00'), 'resource_calendar: wrong interval cleaning') + self.assertEqual(cleaned_intervals[0][1], Datetime.from_string('2013-02-03 10:00:00'), 'resource_calendar: wrong interval cleaning') # Second intreval: 04, 08-14, combining 08-12 and 11-14, 09-11 being inside 08-12 - self.assertEqual(cleaned_intervals[1][0], datetime.strptime('2013-02-04 08:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong interval cleaning') - self.assertEqual(cleaned_intervals[1][1], datetime.strptime('2013-02-04 14:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong interval cleaning') + self.assertEqual(cleaned_intervals[1][0], Datetime.from_string('2013-02-04 08:00:00'), 'resource_calendar: wrong interval cleaning') + self.assertEqual(cleaned_intervals[1][1], Datetime.from_string('2013-02-04 14:00:00'), 'resource_calendar: wrong interval cleaning') # Third interval: 04, 17-21, 18-19 being inside 17-21 - self.assertEqual(cleaned_intervals[2][0], datetime.strptime('2013-02-04 17:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong interval cleaning') - self.assertEqual(cleaned_intervals[2][1], datetime.strptime('2013-02-04 21:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong interval cleaning') + self.assertEqual(cleaned_intervals[2][0], Datetime.from_string('2013-02-04 17:00:00'), 'resource_calendar: wrong interval cleaning') + self.assertEqual(cleaned_intervals[2][1], Datetime.from_string('2013-02-04 21:00:00'), 'resource_calendar: wrong interval cleaning') # Test: disjoint removal - working_interval = (datetime.strptime('2013-02-04 08:00:00', '%Y-%m-%d %H:%M:%S'), datetime.strptime('2013-02-04 18:00:00', '%Y-%m-%d %H:%M:%S')) - result = self.resource_calendar.interval_remove_leaves(cr, uid, working_interval, intervals) + working_interval = (Datetime.from_string('2013-02-04 08:00:00'), Datetime.from_string('2013-02-04 18:00:00')) + result = self.ResourceCalendar.interval_remove_leaves(working_interval, intervals) self.assertEqual(len(result), 1, 'resource_calendar: wrong leave removal from interval') # First interval: 04, 14-17 - self.assertEqual(result[0][0], datetime.strptime('2013-02-04 14:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong leave removal from interval') - self.assertEqual(result[0][1], datetime.strptime('2013-02-04 17:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong leave removal from interval') + self.assertEqual(result[0][0], Datetime.from_string('2013-02-04 14:00:00'), 'resource_calendar: wrong leave removal from interval') + self.assertEqual(result[0][1], Datetime.from_string('2013-02-04 17:00:00'), 'resource_calendar: wrong leave removal from interval') # Test: schedule hours on intervals - result = self.resource_calendar.interval_schedule_hours(cleaned_intervals, 5.5) + result = self.ResourceCalendar.interval_schedule_hours(cleaned_intervals, 5.5) self.assertEqual(len(result), 2, 'resource_calendar: wrong hours scheduling in interval') # First interval: 03, 8-10 untouches - self.assertEqual(result[0][0], datetime.strptime('2013-02-03 08:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong leave removal from interval') - self.assertEqual(result[0][1], datetime.strptime('2013-02-03 10:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong leave removal from interval') + self.assertEqual(result[0][0], Datetime.from_string('2013-02-03 08:00:00'), 'resource_calendar: wrong leave removal from interval') + self.assertEqual(result[0][1], Datetime.from_string('2013-02-03 10:00:00'), 'resource_calendar: wrong leave removal from interval') # First interval: 04, 08-11:30 - self.assertEqual(result[1][0], datetime.strptime('2013-02-04 08:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong leave removal from interval') - self.assertEqual(result[1][1], datetime.strptime('2013-02-04 11:30:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong leave removal from interval') + self.assertEqual(result[1][0], Datetime.from_string('2013-02-04 08:00:00'), 'resource_calendar: wrong leave removal from interval') + self.assertEqual(result[1][1], Datetime.from_string('2013-02-04 11:30:00'), 'resource_calendar: wrong leave removal from interval') # Test: schedule hours on intervals, backwards cleaned_intervals.reverse() - result = self.resource_calendar.interval_schedule_hours(cleaned_intervals, 5.5, remove_at_end=False) + result = self.ResourceCalendar._model.interval_schedule_hours(cleaned_intervals, 5.5, remove_at_end=False) self.assertEqual(len(result), 2, 'resource_calendar: wrong hours scheduling in interval') # First interval: 03, 8-10 untouches - self.assertEqual(result[0][0], datetime.strptime('2013-02-04 17:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong leave removal from interval') - self.assertEqual(result[0][1], datetime.strptime('2013-02-04 21:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong leave removal from interval') + self.assertEqual(result[0][0], Datetime.from_string('2013-02-04 17:00:00'), 'resource_calendar: wrong leave removal from interval') + self.assertEqual(result[0][1], Datetime.from_string('2013-02-04 21:00:00'), 'resource_calendar: wrong leave removal from interval') # First interval: 04, 08-11:30 - self.assertEqual(result[1][0], datetime.strptime('2013-02-04 12:30:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong leave removal from interval') - self.assertEqual(result[1][1], datetime.strptime('2013-02-04 14:00:00', '%Y-%m-%d %H:%M:%S'), 'resource_calendar: wrong leave removal from interval') + self.assertEqual(result[1][0], Datetime.from_string('2013-02-04 12:30:00'), 'resource_calendar: wrong leave removal from interval') + self.assertEqual(result[1][1], Datetime.from_string('2013-02-04 14:00:00'), 'resource_calendar: wrong leave removal from interval') def test_10_calendar_basics(self): """ Testing basic method of resource.calendar """ - cr, uid = self.cr, self.uid # -------------------------------------------------- # Test1: get_next_day # -------------------------------------------------- # Test: next day: next day after day1 is day4 - date = self.resource_calendar.get_next_day(cr, uid, self.calendar_id, day_date=self.date1.date()) + date = self.calendar.get_next_day(day_date=self.date1.date()) self.assertEqual(date, self.date2.date(), 'resource_calendar: wrong next day computing') # Test: next day: next day after day4 is (day1+7) - date = self.resource_calendar.get_next_day(cr, uid, self.calendar_id, day_date=self.date2.date()) + date = self.calendar.get_next_day(day_date=self.date2.date()) self.assertEqual(date, self.date1.date() + relativedelta(days=7), 'resource_calendar: wrong next day computing') # Test: next day: next day after day4+1 is (day1+7) - date = self.resource_calendar.get_next_day(cr, uid, self.calendar_id, day_date=self.date2.date() + relativedelta(days=1)) + date = self.calendar.get_next_day(day_date=self.date2.date() + relativedelta(days=1)) self.assertEqual(date, self.date1.date() + relativedelta(days=7), 'resource_calendar: wrong next day computing') # Test: next day: next day after day1-1 is day1 - date = self.resource_calendar.get_next_day(cr, uid, self.calendar_id, day_date=self.date1.date() + relativedelta(days=-1)) + date = self.calendar.get_next_day(day_date=self.date1.date() + relativedelta(days=-1)) self.assertEqual(date, self.date1.date(), 'resource_calendar: wrong next day computing') # -------------------------------------------------- @@ -108,174 +108,134 @@ class TestResource(TestResourceCommon): # -------------------------------------------------- # Test: previous day: previous day before day1 is (day4-7) - date = self.resource_calendar.get_previous_day(cr, uid, self.calendar_id, day_date=self.date1.date()) + date = self.calendar.get_previous_day(day_date=self.date1.date()) self.assertEqual(date, self.date2.date() + relativedelta(days=-7), 'resource_calendar: wrong previous day computing') # Test: previous day: previous day before day4 is day1 - date = self.resource_calendar.get_previous_day(cr, uid, self.calendar_id, day_date=self.date2.date()) + date = self.calendar.get_previous_day(day_date=self.date2.date()) self.assertEqual(date, self.date1.date(), 'resource_calendar: wrong previous day computing') # Test: previous day: previous day before day4+1 is day4 - date = self.resource_calendar.get_previous_day(cr, uid, self.calendar_id, day_date=self.date2.date() + relativedelta(days=1)) + date = self.calendar.get_previous_day(day_date=self.date2.date() + relativedelta(days=1)) self.assertEqual(date, self.date2.date(), 'resource_calendar: wrong previous day computing') # Test: previous day: previous day before day1-1 is (day4-7) - date = self.resource_calendar.get_previous_day(cr, uid, self.calendar_id, day_date=self.date1.date() + relativedelta(days=-1)) + date = self.calendar.get_previous_day(day_date=self.date1.date() + relativedelta(days=-1)) self.assertEqual(date, self.date2.date() + relativedelta(days=-7), 'resource_calendar: wrong previous day computing') # -------------------------------------------------- # Test3: misc # -------------------------------------------------- - weekdays = self.resource_calendar.get_weekdays(cr, uid, self.calendar_id) + weekdays = self.calendar.get_weekdays() self.assertEqual(weekdays, [1, 4], 'resource_calendar: wrong weekdays computing') -# attendances = self.resource_calendar.get_attendances_for_weekdays(cr, uid, self.calendar_id, [2, 3, 4, 5]) -# self.assertEqual(set([att.id for att in attendances]), set([self.att2_id, self.att3_id]), -# 'resource_calendar: wrong attendances filtering by weekdays computing') - def test_20_calendar_working_intervals(self): """ Testing working intervals computing method of resource.calendar """ - cr, uid = self.cr, self.uid - context = self.context - _format = '%Y-%m-%d %H:%M:%S' # Test: day0 without leaves: 1 interval - intervals = self.resource_calendar.get_working_intervals_of_day(cr, uid, self.calendar_id, start_dt=self.date1, context=context) + intervals = self.calendar.get_working_intervals_of_day(start_dt=self.date1) self.assertEqual(len(intervals), 1, 'resource_calendar: wrong working intervals') - self.assertEqual(intervals[0][0], datetime.strptime('2013-02-12 09:08:07', _format), 'resource_calendar: wrong working intervals') - self.assertEqual(intervals[0][1], datetime.strptime('2013-02-12 16:00:00', _format), 'resource_calendar: wrong working intervals') + self.assertEqual(intervals[0][0], Datetime.from_string('2013-02-12 09:08:07'), 'resource_calendar: wrong working intervals') + self.assertEqual(intervals[0][1], Datetime.from_string('2013-02-12 16:00:00'), 'resource_calendar: wrong working intervals') # Test: day3 without leaves: 2 interval - intervals = self.resource_calendar.get_working_intervals_of_day(cr, uid, self.calendar_id, start_dt=self.date2, context=context) + intervals = self.calendar.get_working_intervals_of_day(start_dt=self.date2) self.assertEqual(len(intervals), 2, 'resource_calendar: wrong working intervals') - self.assertEqual(intervals[0][0], datetime.strptime('2013-02-15 10:11:12', _format), 'resource_calendar: wrong working intervals') - self.assertEqual(intervals[0][1], datetime.strptime('2013-02-15 13:00:00', _format), 'resource_calendar: wrong working intervals') - self.assertEqual(intervals[1][0], datetime.strptime('2013-02-15 16:00:00', _format), 'resource_calendar: wrong working intervals') - self.assertEqual(intervals[1][1], datetime.strptime('2013-02-15 23:00:00', _format), 'resource_calendar: wrong working intervals') + self.assertEqual(intervals[0][0], Datetime.from_string('2013-02-15 10:11:12'), 'resource_calendar: wrong working intervals') + self.assertEqual(intervals[0][1], Datetime.from_string('2013-02-15 13:00:00'), 'resource_calendar: wrong working intervals') + self.assertEqual(intervals[1][0], Datetime.from_string('2013-02-15 16:00:00'), 'resource_calendar: wrong working intervals') + self.assertEqual(intervals[1][1], Datetime.from_string('2013-02-15 23:00:00'), 'resource_calendar: wrong working intervals') # Test: day0 with leaves outside range: 1 interval - intervals = self.resource_calendar.get_working_intervals_of_day(cr, uid, self.calendar_id, start_dt=self.date1.replace(hour=0), compute_leaves=True, context=context) + intervals = self.calendar.get_working_intervals_of_day(start_dt=self.date1.replace(hour=0), compute_leaves=True) self.assertEqual(len(intervals), 1, 'resource_calendar: wrong working intervals') - self.assertEqual(intervals[0][0], datetime.strptime('2013-02-12 08:00:00', _format), 'resource_calendar: wrong working intervals') - self.assertEqual(intervals[0][1], datetime.strptime('2013-02-12 16:00:00', _format), 'resource_calendar: wrong working intervals') + self.assertEqual(intervals[0][0], Datetime.from_string('2013-02-12 08:00:00'), 'resource_calendar: wrong working intervals') + self.assertEqual(intervals[0][1], Datetime.from_string('2013-02-12 16:00:00'), 'resource_calendar: wrong working intervals') # Test: day0 with leaves: 2 intervals because of leave between 9 ans 12, ending at 15:45:30 - intervals = self.resource_calendar.get_working_intervals_of_day(cr, uid, self.calendar_id, - start_dt=self.date1.replace(hour=8) + relativedelta(days=7), - end_dt=self.date1.replace(hour=15, minute=45, second=30) + relativedelta(days=7), - compute_leaves=True, context=context) + intervals = self.calendar.get_working_intervals_of_day(start_dt=self.date1.replace(hour=8) + relativedelta(days=7), + end_dt=self.date1.replace(hour=15, minute=45, second=30) + relativedelta(days=7), + compute_leaves=True) self.assertEqual(len(intervals), 2, 'resource_calendar: wrong working intervals') - self.assertEqual(intervals[0][0], datetime.strptime('2013-02-19 08:08:07', _format), 'resource_calendar: wrong working intervals') - self.assertEqual(intervals[0][1], datetime.strptime('2013-02-19 09:00:00', _format), 'resource_calendar: wrong working intervals') - self.assertEqual(intervals[1][0], datetime.strptime('2013-02-19 12:00:00', _format), 'resource_calendar: wrong working intervals') - self.assertEqual(intervals[1][1], datetime.strptime('2013-02-19 15:45:30', _format), 'resource_calendar: wrong working intervals') + self.assertEqual(intervals[0][0], Datetime.from_string('2013-02-19 08:08:07'), 'resource_calendar: wrong working intervals') + self.assertEqual(intervals[0][1], Datetime.from_string('2013-02-19 09:00:00'), 'resource_calendar: wrong working intervals') + self.assertEqual(intervals[1][0], Datetime.from_string('2013-02-19 12:00:00'), 'resource_calendar: wrong working intervals') + self.assertEqual(intervals[1][1], Datetime.from_string('2013-02-19 15:45:30'), 'resource_calendar: wrong working intervals') def test_30_calendar_working_days(self): """ Testing calendar hours computation on a working day """ - cr, uid = self.cr, self.uid - context = self.context - _format = '%Y-%m-%d %H:%M:%S' # Test: day1, beginning at 10:30 -> work from 10:30 (arrival) until 16:00 - intervals = self.resource_calendar.get_working_intervals_of_day(cr, uid, self.calendar_id, start_dt=self.date1.replace(hour=10, minute=30, second=0), context=context) + intervals = self.calendar.get_working_intervals_of_day(start_dt=self.date1.replace(hour=10, minute=30, second=0)) self.assertEqual(len(intervals), 1, 'resource_calendar: wrong working interval / day computing') - self.assertEqual(intervals[0][0], datetime.strptime('2013-02-12 10:30:00', _format), 'resource_calendar: wrong working interval / day computing') - self.assertEqual(intervals[0][1], datetime.strptime('2013-02-12 16:00:00', _format), 'resource_calendar: wrong working interval / day computing') + self.assertEqual(intervals[0][0], Datetime.from_string('2013-02-12 10:30:00'), 'resource_calendar: wrong working interval / day computing') + self.assertEqual(intervals[0][1], Datetime.from_string('2013-02-12 16:00:00'), 'resource_calendar: wrong working interval / day computing') # Test: hour computation for same interval, should give 5.5 - wh = self.resource_calendar.get_working_hours_of_date(cr, uid, self.calendar_id, start_dt=self.date1.replace(hour=10, minute=30, second=0), context=context) + wh = self.calendar.get_working_hours_of_date(start_dt=self.date1.replace(hour=10, minute=30, second=0)) self.assertEqual(wh, 5.5, 'resource_calendar: wrong working interval / day time computing') # Test: day1+7 on leave, without leave computation - intervals = self.resource_calendar.get_working_intervals_of_day( - cr, uid, self.calendar_id, - start_dt=self.date1.replace(hour=7, minute=0, second=0) + relativedelta(days=7), context=context + intervals = self.calendar.get_working_intervals_of_day( + start_dt=self.date1.replace(hour=7, minute=0, second=0) + relativedelta(days=7) ) # Result: day1 (08->16) self.assertEqual(len(intervals), 1, 'resource_calendar: wrong working interval/day computing') - self.assertEqual(intervals[0][0], datetime.strptime('2013-02-19 08:00:00', _format), 'resource_calendar: wrong working interval / day computing') - self.assertEqual(intervals[0][1], datetime.strptime('2013-02-19 16:00:00', _format), 'resource_calendar: wrong working interval / day computing') + self.assertEqual(intervals[0][0], Datetime.from_string('2013-02-19 08:00:00'), 'resource_calendar: wrong working interval / day computing') + self.assertEqual(intervals[0][1], Datetime.from_string('2013-02-19 16:00:00'), 'resource_calendar: wrong working interval / day computing') # Test: day1+7 on leave, with generic leave computation - intervals = self.resource_calendar.get_working_intervals_of_day( - cr, uid, self.calendar_id, + intervals = self.calendar.get_working_intervals_of_day( start_dt=self.date1.replace(hour=7, minute=0, second=0) + relativedelta(days=7), - compute_leaves=True, context=context + compute_leaves=True ) # Result: day1 (08->09 + 12->16) self.assertEqual(len(intervals), 2, 'resource_calendar: wrong working interval/day computing') - self.assertEqual(intervals[0][0], datetime.strptime('2013-02-19 08:00:00', _format), 'resource_calendar: wrong working interval / day computing') - self.assertEqual(intervals[0][1], datetime.strptime('2013-02-19 09:00:00', _format), 'resource_calendar: wrong working interval / day computing') - self.assertEqual(intervals[1][0], datetime.strptime('2013-02-19 12:00:00', _format), 'resource_calendar: wrong working interval / day computing') - self.assertEqual(intervals[1][1], datetime.strptime('2013-02-19 16:00:00', _format), 'resource_calendar: wrong working interval / day computing') + self.assertEqual(intervals[0][0], Datetime.from_string('2013-02-19 08:00:00'), 'resource_calendar: wrong working interval / day computing') + self.assertEqual(intervals[0][1], Datetime.from_string('2013-02-19 09:00:00'), 'resource_calendar: wrong working interval / day computing') + self.assertEqual(intervals[1][0], Datetime.from_string('2013-02-19 12:00:00'), 'resource_calendar: wrong working interval / day computing') + self.assertEqual(intervals[1][1], Datetime.from_string('2013-02-19 16:00:00'), 'resource_calendar: wrong working interval / day computing') # Test: day1+14 on leave, with generic leave computation - intervals = self.resource_calendar.get_working_intervals_of_day( - cr, uid, self.calendar_id, + intervals = self.calendar.get_working_intervals_of_day( start_dt=self.date1.replace(hour=7, minute=0, second=0) + relativedelta(days=14), - compute_leaves=True, context=context + compute_leaves=True ) # Result: day1 (08->16) self.assertEqual(len(intervals), 1, 'resource_calendar: wrong working interval/day computing') - self.assertEqual(intervals[0][0], datetime.strptime('2013-02-26 08:00:00', _format), 'resource_calendar: wrong working interval / day computing') - self.assertEqual(intervals[0][1], datetime.strptime('2013-02-26 16:00:00', _format), 'resource_calendar: wrong working interval / day computing') + self.assertEqual(intervals[0][0], Datetime.from_string('2013-02-26 08:00:00'), 'resource_calendar: wrong working interval / day computing') + self.assertEqual(intervals[0][1], Datetime.from_string('2013-02-26 16:00:00'), 'resource_calendar: wrong working interval / day computing') # Test: day1+14 on leave, with resource leave computation - intervals = self.resource_calendar.get_working_intervals_of_day( - cr, uid, self.calendar_id, + intervals = self.calendar.get_working_intervals_of_day( start_dt=self.date1.replace(hour=7, minute=0, second=0) + relativedelta(days=14), compute_leaves=True, - resource_id=self.resource1_id, context=context + resource_id=self.resource1_id ) # Result: nothing, because on leave self.assertEqual(len(intervals), 0, 'resource_calendar: wrong working interval/day computing') def test_40_calendar_hours_scheduling(self): """ Testing calendar hours scheduling """ - cr, uid = self.cr, self.uid - context = self.context - _format = '%Y-%m-%d %H:%M:%S' - # -------------------------------------------------- - # Test0: schedule hours backwards (old interval_min_get) - # Done without calendar - # -------------------------------------------------- - - # Done without calendar - # res = self.resource_calendar.interval_min_get(cr, uid, None, self.date1, 40, resource=False) - # res: (datetime.datetime(2013, 2, 7, 9, 8, 7), datetime.datetime(2013, 2, 12, 9, 8, 7)) - - # -------------------------------------------------- - # Test1: schedule hours backwards (old interval_min_get) - # -------------------------------------------------- - - # res = self.resource_calendar.interval_min_get(cr, uid, self.calendar_id, self.date1, 40, resource=False) - # (datetime.datetime(2013, 1, 29, 9, 0), datetime.datetime(2013, 1, 29, 16, 0)) - # (datetime.datetime(2013, 2, 1, 8, 0), datetime.datetime(2013, 2, 1, 13, 0)) - # (datetime.datetime(2013, 2, 1, 16, 0), datetime.datetime(2013, 2, 1, 23, 0)) - # (datetime.datetime(2013, 2, 5, 8, 0), datetime.datetime(2013, 2, 5, 16, 0)) - # (datetime.datetime(2013, 2, 8, 8, 0), datetime.datetime(2013, 2, 8, 13, 0)) - # (datetime.datetime(2013, 2, 8, 16, 0), datetime.datetime(2013, 2, 8, 23, 0)) - # (datetime.datetime(2013, 2, 12, 8, 0), datetime.datetime(2013, 2, 12, 9, 0)) - - res = self.resource_calendar.schedule_hours(cr, uid, self.calendar_id, -40, day_dt=self.date1.replace(minute=0, second=0), context=context) + res = self.calendar.schedule_hours(-40, day_dt=self.date1.replace(minute=0, second=0)) # current day, limited at 09:00 because of day_dt specified -> 1 hour - self.assertEqual(res[-1][0], datetime.strptime('2013-02-12 08:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[-1][1], datetime.strptime('2013-02-12 09:00:00', _format), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[-1][0], Datetime.from_string('2013-02-12 08:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[-1][1], Datetime.from_string('2013-02-12 09:00:00'), 'resource_calendar: wrong hours scheduling') # previous days: 5+7 hours / 8 hours / 5+7 hours -> 32 hours - self.assertEqual(res[-2][0], datetime.strptime('2013-02-08 16:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[-2][1], datetime.strptime('2013-02-08 23:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[-3][0], datetime.strptime('2013-02-08 08:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[-3][1], datetime.strptime('2013-02-08 13:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[-4][0], datetime.strptime('2013-02-05 08:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[-4][1], datetime.strptime('2013-02-05 16:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[-5][0], datetime.strptime('2013-02-01 16:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[-5][1], datetime.strptime('2013-02-01 23:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[-6][0], datetime.strptime('2013-02-01 08:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[-6][1], datetime.strptime('2013-02-01 13:00:00', _format), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[-2][0], Datetime.from_string('2013-02-08 16:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[-2][1], Datetime.from_string('2013-02-08 23:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[-3][0], Datetime.from_string('2013-02-08 08:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[-3][1], Datetime.from_string('2013-02-08 13:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[-4][0], Datetime.from_string('2013-02-05 08:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[-4][1], Datetime.from_string('2013-02-05 16:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[-5][0], Datetime.from_string('2013-02-01 16:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[-5][1], Datetime.from_string('2013-02-01 23:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[-6][0], Datetime.from_string('2013-02-01 08:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[-6][1], Datetime.from_string('2013-02-01 13:00:00'), 'resource_calendar: wrong hours scheduling') # 7 hours remaining - self.assertEqual(res[-7][0], datetime.strptime('2013-01-29 09:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[-7][1], datetime.strptime('2013-01-29 16:00:00', _format), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[-7][0], Datetime.from_string('2013-01-29 09:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[-7][1], Datetime.from_string('2013-01-29 16:00:00'), 'resource_calendar: wrong hours scheduling') # Compute scheduled hours td = timedelta() for item in res: @@ -283,74 +243,53 @@ class TestResource(TestResourceCommon): self.assertEqual(seconds(td) / 3600.0, 40.0, 'resource_calendar: wrong hours scheduling') # -------------------------------------------------- - # Test2: schedule hours forward (old interval_get) + # Test2: schedule hours forward # -------------------------------------------------- - # res = self.resource_calendar.interval_get(cr, uid, self.calendar_id, self.date1, 40, resource=False, byday=True) - # (datetime.datetime(2013, 2, 12, 9, 0), datetime.datetime(2013, 2, 12, 16, 0)) - # (datetime.datetime(2013, 2, 15, 8, 0), datetime.datetime(2013, 2, 15, 13, 0)) - # (datetime.datetime(2013, 2, 15, 16, 0), datetime.datetime(2013, 2, 15, 23, 0)) - # (datetime.datetime(2013, 2, 22, 8, 0), datetime.datetime(2013, 2, 22, 13, 0)) - # (datetime.datetime(2013, 2, 22, 16, 0), datetime.datetime(2013, 2, 22, 23, 0)) - # (datetime.datetime(2013, 2, 26, 8, 0), datetime.datetime(2013, 2, 26, 16, 0)) - # (datetime.datetime(2013, 3, 1, 8, 0), datetime.datetime(2013, 3, 1, 9, 0)) - - res = self.resource_calendar.schedule_hours( - cr, uid, self.calendar_id, 40, - day_dt=self.date1.replace(minute=0, second=0), context=context + res = self.calendar.schedule_hours( + 40, day_dt=self.date1.replace(minute=0, second=0) ) - self.assertEqual(res[0][0], datetime.strptime('2013-02-12 09:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[0][1], datetime.strptime('2013-02-12 16:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[1][0], datetime.strptime('2013-02-15 08:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[1][1], datetime.strptime('2013-02-15 13:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[2][0], datetime.strptime('2013-02-15 16:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[2][1], datetime.strptime('2013-02-15 23:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[3][0], datetime.strptime('2013-02-19 08:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[3][1], datetime.strptime('2013-02-19 16:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[4][0], datetime.strptime('2013-02-22 08:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[4][1], datetime.strptime('2013-02-22 13:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[5][0], datetime.strptime('2013-02-22 16:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[5][1], datetime.strptime('2013-02-22 23:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[6][0], datetime.strptime('2013-02-26 08:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[6][1], datetime.strptime('2013-02-26 09:00:00', _format), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[0][0], Datetime.from_string('2013-02-12 09:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[0][1], Datetime.from_string('2013-02-12 16:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[1][0], Datetime.from_string('2013-02-15 08:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[1][1], Datetime.from_string('2013-02-15 13:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[2][0], Datetime.from_string('2013-02-15 16:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[2][1], Datetime.from_string('2013-02-15 23:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[3][0], Datetime.from_string('2013-02-19 08:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[3][1], Datetime.from_string('2013-02-19 16:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[4][0], Datetime.from_string('2013-02-22 08:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[4][1], Datetime.from_string('2013-02-22 13:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[5][0], Datetime.from_string('2013-02-22 16:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[5][1], Datetime.from_string('2013-02-22 23:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[6][0], Datetime.from_string('2013-02-26 08:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[6][1], Datetime.from_string('2013-02-26 09:00:00'), 'resource_calendar: wrong hours scheduling') td = timedelta() for item in res: td += item[1] - item[0] self.assertEqual(seconds(td) / 3600.0, 40.0, 'resource_calendar: wrong hours scheduling') - # res = self.resource_calendar.interval_get(cr, uid, self.calendar_id, self.date1, 40, resource=self.resource1_id, byday=True) - # (datetime.datetime(2013, 2, 12, 9, 0), datetime.datetime(2013, 2, 12, 16, 0)) - # (datetime.datetime(2013, 2, 15, 8, 0), datetime.datetime(2013, 2, 15, 13, 0)) - # (datetime.datetime(2013, 2, 15, 16, 0), datetime.datetime(2013, 2, 15, 23, 0)) - # (datetime.datetime(2013, 3, 1, 8, 0), datetime.datetime(2013, 3, 1, 13, 0)) - # (datetime.datetime(2013, 3, 1, 16, 0), datetime.datetime(2013, 3, 1, 23, 0)) - # (datetime.datetime(2013, 3, 5, 8, 0), datetime.datetime(2013, 3, 5, 16, 0)) - # (datetime.datetime(2013, 3, 8, 8, 0), datetime.datetime(2013, 3, 8, 9, 0)) - - res = self.resource_calendar.schedule_hours( - cr, uid, self.calendar_id, 40, - day_dt=self.date1.replace(minute=0, second=0), - compute_leaves=True, - resource_id=self.resource1_id, context=context + res = self.calendar.schedule_hours( + 40, day_dt=self.date1.replace(minute=0, second=0), + compute_leaves=True, resource_id=self.resource1_id ) - self.assertEqual(res[0][0], datetime.strptime('2013-02-12 09:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[0][1], datetime.strptime('2013-02-12 16:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[1][0], datetime.strptime('2013-02-15 08:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[1][1], datetime.strptime('2013-02-15 13:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[2][0], datetime.strptime('2013-02-15 16:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[2][1], datetime.strptime('2013-02-15 23:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[3][0], datetime.strptime('2013-02-19 08:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[3][1], datetime.strptime('2013-02-19 09:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[4][0], datetime.strptime('2013-02-19 12:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[4][1], datetime.strptime('2013-02-19 16:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[5][0], datetime.strptime('2013-02-22 08:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[5][1], datetime.strptime('2013-02-22 09:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[6][0], datetime.strptime('2013-02-22 16:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[6][1], datetime.strptime('2013-02-22 23:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[7][0], datetime.strptime('2013-03-01 11:30:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[7][1], datetime.strptime('2013-03-01 13:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[8][0], datetime.strptime('2013-03-01 16:00:00', _format), 'resource_calendar: wrong hours scheduling') - self.assertEqual(res[8][1], datetime.strptime('2013-03-01 22:30:00', _format), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[0][0], Datetime.from_string('2013-02-12 09:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[0][1], Datetime.from_string('2013-02-12 16:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[1][0], Datetime.from_string('2013-02-15 08:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[1][1], Datetime.from_string('2013-02-15 13:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[2][0], Datetime.from_string('2013-02-15 16:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[2][1], Datetime.from_string('2013-02-15 23:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[3][0], Datetime.from_string('2013-02-19 08:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[3][1], Datetime.from_string('2013-02-19 09:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[4][0], Datetime.from_string('2013-02-19 12:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[4][1], Datetime.from_string('2013-02-19 16:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[5][0], Datetime.from_string('2013-02-22 08:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[5][1], Datetime.from_string('2013-02-22 09:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[6][0], Datetime.from_string('2013-02-22 16:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[6][1], Datetime.from_string('2013-02-22 23:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[7][0], Datetime.from_string('2013-03-01 11:30:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[7][1], Datetime.from_string('2013-03-01 13:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[8][0], Datetime.from_string('2013-03-01 16:00:00'), 'resource_calendar: wrong hours scheduling') + self.assertEqual(res[8][1], Datetime.from_string('2013-03-01 22:30:00'), 'resource_calendar: wrong hours scheduling') td = timedelta() for item in res: td += item[1] - item[0] @@ -362,38 +301,34 @@ class TestResource(TestResourceCommon): # old API: resource without leaves # res: 2 weeks -> 40 hours - res = self.resource_calendar._interval_hours_get( - cr, uid, self.calendar_id, + res = self.calendar._interval_hours_get( self.date1.replace(hour=6, minute=0), self.date2.replace(hour=23, minute=0) + relativedelta(days=7), - resource_id=self.resource1_id, exclude_leaves=True, context=context) + resource_id=self.resource1_id, exclude_leaves=True) self.assertEqual(res, 40.0, 'resource_calendar: wrong _interval_hours_get compatibility computation') # new API: resource without leaves # res: 2 weeks -> 40 hours - res = self.resource_calendar.get_working_hours( - cr, uid, self.calendar_id, + res = self.calendar.get_working_hours( self.date1.replace(hour=6, minute=0), self.date2.replace(hour=23, minute=0) + relativedelta(days=7), - compute_leaves=False, resource_id=self.resource1_id, context=context) + compute_leaves=False, resource_id=self.resource1_id) self.assertEqual(res, 40.0, 'resource_calendar: wrong get_working_hours computation') # old API: resource and leaves # res: 2 weeks -> 40 hours - (3+4) leave hours - res = self.resource_calendar._interval_hours_get( - cr, uid, self.calendar_id, + res = self.calendar._interval_hours_get( self.date1.replace(hour=6, minute=0), self.date2.replace(hour=23, minute=0) + relativedelta(days=7), - resource_id=self.resource1_id, exclude_leaves=False, context=context) + resource_id=self.resource1_id, exclude_leaves=False) self.assertEqual(res, 33.0, 'resource_calendar: wrong _interval_hours_get compatibility computation') # new API: resource and leaves # res: 2 weeks -> 40 hours - (3+4) leave hours - res = self.resource_calendar.get_working_hours( - cr, uid, self.calendar_id, + res = self.calendar.get_working_hours( self.date1.replace(hour=6, minute=0), self.date2.replace(hour=23, minute=0) + relativedelta(days=7), - compute_leaves=True, resource_id=self.resource1_id, context=context) + compute_leaves=True, resource_id=self.resource1_id) self.assertEqual(res, 33.0, 'resource_calendar: wrong get_working_hours computation') # -------------------------------------------------- @@ -401,69 +336,105 @@ class TestResource(TestResourceCommon): # -------------------------------------------------- # Test without calendar and default_interval - res = self.resource_calendar.get_working_hours( - cr, uid, None, + res = self.ResourceCalendar.with_context(self.context).get_working_hours( self.date1.replace(hour=6, minute=0), self.date2.replace(hour=23, minute=0), compute_leaves=True, resource_id=self.resource1_id, - default_interval=(8, 16), context=context) + default_interval=(8, 16)) self.assertEqual(res, 32.0, 'resource_calendar: wrong get_working_hours computation') - self.att0_0_id = self.resource_attendance.create( - cr, uid, { + self.att0_0_id = self.ResourceAttendance.with_context(self.context).create( + { 'name': 'Att0', 'dayofweek': '0', 'hour_from': 7.5, 'hour_to': 12.5, - 'calendar_id': self.calendar_id, - }, context=context + 'calendar_id': self.calendar.id, + } ) - self.att0_1_id = self.resource_attendance.create( - cr, uid, { + self.att0_1_id = self.ResourceAttendance.with_context(self.context).create( + { 'name': 'Att0', 'dayofweek': '0', 'hour_from': 13, 'hour_to': 14, - 'calendar_id': self.calendar_id, - }, context=context + 'calendar_id': self.calendar.id, + } ) - date1 = datetime.strptime('2013-02-11 07:30:00', '%Y-%m-%d %H:%M:%S') - date2 = datetime.strptime('2013-02-11 14:00:00', '%Y-%m-%d %H:%M:%S') - res = self.resource_calendar.get_working_hours( - cr, uid, self.calendar_id, + date1 = Datetime.from_string('2013-02-11 07:30:00') + date2 = Datetime.from_string('2013-02-11 14:00:00') + res = self.calendar.get_working_hours( date1, date2, - compute_leaves=False, resource_id=self.resource1_id, context=context) + compute_leaves=False, resource_id=self.resource1_id) # 7h30 -> 12h30 = 5 / 13h -> 14h = 1 / -> 6h self.assertEqual(res, 6, 'resource_calendar: wrong get_working_hours computation') - def test_50_calendar_schedule_days(self): """ Testing calendar days scheduling """ - cr, uid = self.cr, self.uid - _format = '%Y-%m-%d %H:%M:%S' # -------------------------------------------------- # Test1: with calendar # -------------------------------------------------- - res = self.resource_calendar.schedule_days_get_date(cr, uid, self.calendar_id, 5, day_date=self.date1, context={'tz': 'UTC'}) - self.assertEqual(res.date(), datetime.strptime('2013-02-26 00:0:00', _format).date(), 'resource_calendar: wrong days scheduling') - res = self.resource_calendar.schedule_days_get_date(cr, uid, self.calendar_id, -2, day_date=self.date1, context={'tz': 'UTC'}) - self.assertEqual(res.date(), datetime.strptime('2013-02-08 00:00:00', _format).date(), 'resource_calendar: wrong days scheduling') + res = self.calendar.schedule_days_get_date(5, day_date=self.date1) + 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=self.date1) + self.assertEqual(res.date(), Datetime.from_string('2013-02-08 00:00:00').date(), 'resource_calendar: wrong days scheduling') - res = self.resource_calendar.schedule_days_get_date( - cr, uid, self.calendar_id, 5, day_date=self.date1, - compute_leaves=True, resource_id=self.resource1_id, context={'tz': 'UTC'}) - self.assertEqual(res.date(), datetime.strptime('2013-03-01 00:0:00', _format).date(), 'resource_calendar: wrong days scheduling') + res = self.calendar.schedule_days_get_date( + 5, day_date=self.date1, + 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') # -------------------------------------------------- # Test2: misc # -------------------------------------------------- # Without calendar, should only count days -> 12 -> 16, 5 days with default intervals - res = self.resource_calendar.schedule_days_get_date(cr, uid, None, 5, day_date=self.date1, default_interval=(8, 16), context={'tz': 'UTC'}) - self.assertEqual(res, datetime.strptime('2013-02-16 16:00:00', _format), 'resource_calendar: wrong days scheduling') + res = self.ResourceCalendar.with_context(self.context).schedule_days_get_date(5, day_date=self.date1, default_interval=(8, 16)) + self.assertEqual(res, Datetime.from_string('2013-02-16 16:00:00'), 'resource_calendar: wrong days scheduling') + + def test_60_project(self): + # I assign working calendar '45 Hours/Week' to human resource. + resources = self.env.ref('resource.resource_analyst') + self.env.ref('resource.resource_designer') + self.env.ref('resource.resource_developer') + resources.write({'calendar_id': self.ref('resource.timesheet_group1'), 'resource_type': 'user'}) + + # I had Project of Odoo Integration of 50 Hours with three human resource assigned on it. I have started project from this week start. + # I check per day work hour availability of the Resource based on Working Calendar Assigned to each resource, for first day of the week. + now = datetime.now() + dt = now - timedelta(days=now.weekday()) + for resource in resources: + result = resource.calendar_id.working_hours_on_day(dt) + self.assertEqual(float_compare(result, 8.0, precision_digits=2), 0, 'Wrong calculation of day work hour availability of the Resource (found %d).' % result) + + # Now, resource "Developer" drafted leave on Thursday in this week. + now = datetime.now() + dt = (now - timedelta(days=now.weekday())) + timedelta(days=3) + vals = { + 'resource_id': self.ref('resource.resource_developer'), + 'calendar_id': self.ref('resource.timesheet_group1'), + 'date_from': dt.strftime("%Y-%m-%d 09:00:00"), + 'date_to': dt.strftime("%Y-%m-%d 18:00:00") + } + self.env.ref('resource.resource_dummyleave').write(vals) + + # I check Actual working hours on resource 'Developer' from this week + now = datetime.now() + dt_from = now - relativedelta(days=now.weekday(), hour=8, minute=30) + dt_to = dt_from + relativedelta(days=6, hour=17) + hours = self.env.ref('resource.timesheet_group1').interval_hours_get(dt_from, dt_to, resource=self.ref('resource.resource_developer')) + self.assertGreater(hours, 27, 'Invalid Total Week working hour calculated, got %r, expected > 27' % hours) + + # Project Analysis work is of 20 hours which will start from Week start so i will calculate working schedule for resource Analyst for the same. + now = datetime.now() + work_intreval = self.env.ref('resource.timesheet_group1').interval_min_get(now, 20.0, resource=self.ref('resource.resource_designer')) + self.assertGreaterEqual(len(work_intreval), 5, 'Wrong Schedule Calculated') + + def test_70_duplicate_resource(self): + resource_id = self.env.ref('resource.resource_analyst').copy() + self.assertTrue(resource_id, 'Unable to Duplicate Resource') + WAR_START = date(1932, 11, 2) WAR_END = date(1932, 12, 10) @@ -569,10 +540,8 @@ class TestWorkDays(TransactionCase): weekdays = [d for d in self._days if d.weekday() not in (5, 6)] self.assertEqual(weekdays, list(r1._iter_work_days(WAR_START, WAR_END))) - self.assertEqual( - [d for d in weekdays - if d < date(1932, 11, 9) or d > date(1932, 11, 12) - ], + self.assertEqual([ + d for d in weekdays if d < date(1932, 11, 9) or d > date(1932, 11, 12)], list(r2._iter_work_days(WAR_START, WAR_END)) ) @@ -593,12 +562,11 @@ class TestWorkDays(TransactionCase): 'resource_id': r.id }) - self.assertEqual( - [d for d in self._days - if d.weekday() not in (5, 6) - if d < date(1932, 11, 9) or d > date(1932, 11, 12) - if d < date(1932, 12, 2) - ], + self.assertEqual([ + d for d in self._days + if d.weekday() not in (5, 6) + if d < date(1932, 11, 9) or d > date(1932, 11, 12) + if d < date(1932, 12, 2)], list(r._iter_work_days(WAR_START, WAR_END)) ) @@ -608,11 +576,11 @@ class TestWorkDays(TransactionCase): self.assertTrue(r._is_work_day(date(1932, 11, 14))) self.assertTrue(r._is_work_day(date(1932, 12, 1))) - self.assertFalse(r._is_work_day(date(1932, 11, 11))) # global leave - self.assertFalse(r._is_work_day(date(1932, 11, 13))) # sun - 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 + self.assertFalse(r._is_work_day(date(1932, 11, 11))) # global leave + self.assertFalse(r._is_work_day(date(1932, 11, 13))) # sun + 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) diff --git a/addons/resource/resource_view.xml b/addons/resource/views/resource_views.xml similarity index 98% rename from addons/resource/resource_view.xml rename to addons/resource/views/resource_views.xml index 5eeec8aaf05..6dbb2c29a91 100644 --- a/addons/resource/resource_view.xml +++ b/addons/resource/views/resource_views.xml @@ -1,6 +1,5 @@ - - + @@ -212,7 +211,7 @@
- + @@ -259,5 +258,4 @@ - - + diff --git a/addons/stock_calendar/models/resource.py b/addons/stock_calendar/models/resource.py index e0e2c22dc07..0ddec1b0cd5 100644 --- a/addons/stock_calendar/models/resource.py +++ b/addons/stock_calendar/models/resource.py @@ -1,10 +1,8 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -import datetime from odoo import api, fields, models -from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT class ResourceCalendarAttendance(models.Model): @@ -16,16 +14,16 @@ class ResourceCalendarAttendance(models.Model): class ResourceCalendarLeaves(models.Model): _inherit = "resource.calendar.leaves" - group_id = fields.Many2one('procurement.group', 'Procurement Group') + group_id = fields.Many2one('procurement.group', string="Procurement Group") class ResourceCalendar(models.Model): _inherit = "resource.calendar" # Keep as it takes into account times - def get_leave_intervals(self, cr, uid, id, resource_id=None, - start_datetime=None, end_datetime=None, - context=None): + @api.multi + 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. @@ -43,15 +41,15 @@ class ResourceCalendar(models.Model): """ # TDE FIXME: waw, overriding completely a method + changing its result # and its behavior, very nice. Please FIXME. - resource_calendar = self.browse(cr, uid, id, context=context) + self.ensure_one() leaves = [] - for leave in resource_calendar.leave_ids: + for leave in self.leave_ids: if leave.resource_id and not resource_id == leave.resource_id.id: continue - date_from = datetime.datetime.strptime(leave.date_from, DEFAULT_SERVER_DATETIME_FORMAT) + date_from = fields.Datetime.from_string(leave.date_from) if end_datetime and date_from > end_datetime: continue - date_to = datetime.datetime.strptime(leave.date_to, DEFAULT_SERVER_DATETIME_FORMAT) + date_to = fields.Datetime.from_string(leave.date_to) if start_datetime and date_to < start_datetime: continue leaves.append((date_from, date_to, leave.group_id.id)) @@ -61,7 +59,8 @@ class ResourceCalendar(models.Model): # Utility methods # -------------------------------------------------- - def interval_remove_leaves(self, cr, uid, interval, leave_intervals, context=None): + @api.model + 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 @@ -101,7 +100,7 @@ class ResourceCalendar(models.Model): att_obj = self.pool.get("resource.calendar.attendance") if leave[2]: if len(current_interval) > 2: - current_group = current_interval[2] and att_obj.browse(cr, uid, current_interval[2], context=context).group_id.id or False + current_group = current_interval[2] and att_obj.browse(current_interval[2]).group_id.id or False if leave[2] != current_group: continue if leave[1] <= current_interval[0]: diff --git a/addons/stock_calendar/models/stock.py b/addons/stock_calendar/models/stock.py index 660bd42bc05..01768f43d0d 100644 --- a/addons/stock_calendar/models/stock.py +++ b/addons/stock_calendar/models/stock.py @@ -68,7 +68,7 @@ class StockWarehouseOrderpoint(models.Model): purchase_date = False delivery_date = start_date if self.calendar_id and self.calendar_id.attendance_ids: - res = self.calendar_id._schedule_days(-1, start_date, compute_leaves=True)[0] # CLEANME + res = self.calendar_id._schedule_days(-1, start_date, compute_leaves=True) if res and res[0][0] < start_date: group_to_find = res[0][2] and Attendance.browse(res[0][2]).group_id.id delivery_date = res[0][0] @@ -76,7 +76,7 @@ class StockWarehouseOrderpoint(models.Model): if self.purchase_calendar_id and self.purchase_calendar_id.attendance_ids: while not purchase_date: found_date = found_date + relativedelta(days=-1) # won't allow to deliver within the day - res = self.purchase_calendar_id._schedule_days(-1, found_date, compute_leaves=True)[0] # CLEANME + res = self.purchase_calendar_id._schedule_days(-1, found_date, compute_leaves=True) for re in res: group = re[2] and Attendance.browse(re[2]).group_id.id found_date = re[0] @@ -94,7 +94,7 @@ class StockWarehouseOrderpoint(models.Model): now_date = datetime.utcnow() # Search first calendar day (without group) - res = self.calendar_id._schedule_days(1, new_date, compute_leaves=True)[0] # CLEANME + res = self.calendar_id._schedule_days(1, new_date, compute_leaves=True) att_group = res and res[0][2] and Attendance.browse(res[0][2]).group_id.id # If hours are smaller than the current date, search a day further if res and res[0][0] < now_date: @@ -112,7 +112,7 @@ class StockWarehouseOrderpoint(models.Model): while res and group and att_group != group and number < 100: number += 1 new_date = res[0][1] + relativedelta(days=1) - res = self.calendar_id._schedule_days(1, new_date, compute_leaves=True)[0] + res = self.calendar_id._schedule_days(1, new_date, compute_leaves=True) att_group = False for re in res: if re[2]: @@ -128,7 +128,7 @@ class StockWarehouseOrderpoint(models.Model): if res: date1 = res[0][1] new_date = res[0][1] + relativedelta(days=1) - res = self.calendar_id._schedule_days(1, new_date, compute_leaves=True)[0] + res = self.calendar_id._schedule_days(1, new_date, compute_leaves=True) if res: return (date1, res[0][1]) return (False, False)