From c46f1f9fc039ca97931818d28c1bf61d8e8d3c93 Mon Sep 17 00:00:00 2001 From: Chris Biersbach Date: Mon, 29 Oct 2012 13:54:17 +0100 Subject: [PATCH 1/4] [FIX] This fixes the project_issue issue analysis report. Values on the Extra Info tab on issues are now correct. bzr revid: cbi@openerp.com-20121029125417-2zql6d3xa8p7zke3 --- addons/project_issue/project_issue.py | 40 +++--- .../report/project_issue_report.py | 12 +- .../report/project_issue_report_view.xml | 2 +- addons/resource/resource.py | 128 +++++++++++++----- 4 files changed, 118 insertions(+), 64 deletions(-) diff --git a/addons/project_issue/project_issue.py b/addons/project_issue/project_issue.py index f0d78f53dfc..3742a53d1a0 100644 --- a/addons/project_issue/project_issue.py +++ b/addons/project_issue/project_issue.py @@ -1,4 +1,4 @@ - #-*- coding: utf-8 -*- +#-*- coding: utf-8 -*- ############################################################################## # # OpenERP, Open Source Management Solution @@ -65,7 +65,9 @@ class project_issue(crm.crm_case, osv.osv): """ res = super(project_issue, self).case_open(cr, uid, ids, *args) - self.write(cr, uid, ids, {'date_open': time.strftime('%Y-%m-%d %H:%M:%S'), 'user_id' : uid}) + for issue in self.browse(cr, uid, ids): + if not issue.date_open: + self.write(cr, uid, ids, {'date_open': time.strftime('%Y-%m-%d %H:%M:%S'), 'user_id' : uid}) for (id, name) in self.name_get(cr, uid, ids): message = _("Issue '%s' has been opened.") % name self.log(cr, uid, id, message) @@ -96,9 +98,16 @@ class project_issue(crm.crm_case, osv.osv): """ cal_obj = self.pool.get('resource.calendar') res_obj = self.pool.get('resource.resource') - + res = {} for issue in self.browse(cr, uid, ids, context=context): + + # if the working hours on the project are not defined, use default ones (8 -> 12 and 13 -> 17 * 5), represented by None + if not issue.project_id or not issue.project_id.resource_calendar_id: + working_hours = None + else: + working_hours = issue.project_id.resource_calendar_id.id + res[issue.id] = {} for field in fields: duration = 0 @@ -112,7 +121,7 @@ class project_issue(crm.crm_case, osv.osv): ans = date_open - date_create date_until = issue.date_open #Calculating no. of working hours to open the issue - hours = cal_obj.interval_hours_get(cr, uid, issue.project_id.resource_calendar_id.id, + hours = cal_obj.interval_hours_get(cr, issue.user_id.id or uid, working_hours, date_create, date_open) elif field in ['working_hours_close','day_close']: @@ -121,7 +130,7 @@ class project_issue(crm.crm_case, osv.osv): date_until = issue.date_closed ans = date_close - date_create #Calculating no. of working hours to close the issue - hours = cal_obj.interval_hours_get(cr, uid, issue.project_id.resource_calendar_id.id, + hours = cal_obj.interval_hours_get(cr, issue.user_id.id or uid, working_hours, date_create, date_close) elif field in ['days_since_creation']: @@ -142,27 +151,12 @@ class project_issue(crm.crm_case, osv.osv): resource_ids = res_obj.search(cr, uid, [('user_id','=',issue.user_id.id)]) if resource_ids and len(resource_ids): resource_id = resource_ids[0] - duration = float(ans.days) - if issue.project_id and issue.project_id.resource_calendar_id: - duration = float(ans.days) * 24 - - new_dates = cal_obj.interval_min_get(cr, uid, - issue.project_id.resource_calendar_id.id, - date_create, - duration, resource=resource_id) - no_days = [] - date_until = datetime.strptime(date_until, '%Y-%m-%d %H:%M:%S') - for in_time, out_time in new_dates: - if in_time.date not in no_days: - no_days.append(in_time.date) - if out_time > date_until: - break - duration = len(no_days) + duration = float(ans.days) + float(ans.seconds)/(24*3600) if field in ['working_hours_open','working_hours_close']: res[issue.id][field] = hours - else: - res[issue.id][field] = abs(float(duration)) + elif field in ['day_open','day_close']: + res[issue.id][field] = duration return res diff --git a/addons/project_issue/report/project_issue_report.py b/addons/project_issue/report/project_issue_report.py index ee0712f3cac..f426b536b75 100644 --- a/addons/project_issue/report/project_issue_report.py +++ b/addons/project_issue/report/project_issue_report.py @@ -50,13 +50,13 @@ class project_issue_report(osv.osv): 'opening_date': fields.date('Date of Opening', readonly=True), 'creation_date': fields.date('Creation Date', readonly=True), 'date_closed': fields.date('Date of Closing', readonly=True), - 'categ_id': fields.many2one('crm.case.categ', 'Category', domain="[('section_id','=',section_id),('object_id.model', '=', 'project.issue')]"), + 'categ_id': fields.many2one('crm.case.categ', 'Category', domain="['&',('section_id','=',section_id),('object_id.model', '=', 'project.issue')]"), 'type_id': fields.many2one('project.task.type', 'Stage'), 'nbr': fields.integer('# of Issues', readonly=True), 'working_hours_open': fields.float('Avg. Working Hours to Open', readonly=True, group_operator="avg"), 'working_hours_close': fields.float('Avg. Working Hours to Close', readonly=True, group_operator="avg"), 'delay_open': fields.float('Avg. Delay to Open', digits=(16,2), readonly=True, group_operator="avg", - help="Number of Days to close the project issue"), + help="Number of Days to open the project issue"), 'delay_close': fields.float('Avg. Delay to Close', digits=(16,2), readonly=True, group_operator="avg", help="Number of Days to close the project issue"), 'company_id' : fields.many2one('res.company', 'Company'), @@ -64,9 +64,9 @@ class project_issue_report(osv.osv): 'project_id':fields.many2one('project.project', 'Project',readonly=True), 'version_id': fields.many2one('project.issue.version', 'Version'), 'user_id' : fields.many2one('res.users', 'Assigned to',readonly=True), - 'partner_id': fields.many2one('res.partner','Partner',domain="[('object_id.model', '=', 'project.issue')]"), + 'partner_id': fields.many2one('res.partner','Partner'), 'channel_id': fields.many2one('crm.case.channel', 'Channel',readonly=True), - 'task_id': fields.many2one('project.task', 'Task',domain="[('object_id.model', '=', 'project.issue')]" ), + 'task_id': fields.many2one('project.task', 'Task'), 'email': fields.integer('# Emails', size=128, readonly=True), } @@ -98,8 +98,8 @@ class project_issue_report(osv.osv): c.channel_id, c.task_id, date_trunc('day',c.create_date) as create_date, - extract('epoch' from (c.date_open-c.create_date))/(3600*24) as delay_open, - extract('epoch' from (c.date_closed-c.date_open))/(3600*24) as delay_close, + c.day_open as delay_open, + c.day_close as delay_close, (SELECT count(id) FROM mail_message WHERE model='project.issue' AND res_id=c.id) AS email FROM diff --git a/addons/project_issue/report/project_issue_report_view.xml b/addons/project_issue/report/project_issue_report_view.xml index 1695fa3469a..a649a4ac3e8 100644 --- a/addons/project_issue/report/project_issue_report_view.xml +++ b/addons/project_issue/report/project_issue_report_view.xml @@ -81,7 +81,7 @@ - + diff --git a/addons/resource/resource.py b/addons/resource/resource.py index fb3d8c0980e..fd3b7ed03f9 100644 --- a/addons/resource/resource.py +++ b/addons/resource/resource.py @@ -28,6 +28,7 @@ from tools.translate import _ from itertools import groupby from operator import itemgetter +import pytz class resource_calendar(osv.osv): _name = "resource.calendar" @@ -199,7 +200,7 @@ class resource_calendar(osv.osv): 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)] return res - def interval_hours_get(self, cr, uid, id, dt_from, dt_to, resource=False): + def interval_hours_get(self, cr, uid, id, dt_from, dt_to, resource=False, context=None): """ Calculates the Total Working hours based on given start_date to end_date, If resource id is supplied that it will consider the source leaves also in calculating the hours. @@ -212,45 +213,104 @@ class resource_calendar(osv.osv): @return : Total number of working hours based dt_from and dt_end and resource if supplied. """ - if not id: - return 0.0 - dt_leave = self._get_leaves(cr, uid, id, resource) + hours = 0.0 + + dt_to_hours = dt_to.hour + dt_to.minute / 60.0 + dt_to.second / 3600.0 - current_hour = dt_from.hour + users_obj = self.pool.get('res.users') + user = users_obj.browse(cr, uid, uid, context=context) + utc = pytz.timezone('UTC') + + if user.context_tz: + context_tz = pytz.timezone(user.context_tz) + else: + context_tz = utc + + # gap between UTC and user timezone + tz_gap = (utc.localize(dt_from) - context_tz.localize(dt_from)).seconds / 3600 - while (dt_from <= dt_to): - cr.execute("select hour_from,hour_to from resource_calendar_attendance where dayofweek='%s' and calendar_id=%s order by hour_from", (dt_from.weekday(),id)) - der = cr.fetchall() - for (hour_from,hour_to) in der: - if hours != 0.0:#For first time of the loop only,hours will be 0 - current_hour = hour_from - leave_flag = False - if (hour_to>=current_hour): - dt_check = dt_from.strftime('%Y-%m-%d') - for leave in dt_leave: - if dt_check == leave: - dt_check = datetime.strptime(dt_check, "%Y-%m-%d") + timedelta(days=1) - leave_flag = True + orig_dt_from = dt_from - if leave_flag: - break + while dt_from <= dt_to: + # if the working hours are None, use the default ones + if id: + cr.execute("select hour_from,hour_to from resource_calendar_attendance where dayofweek='%s' and calendar_id=%s order by hour_from", (dt_from.weekday(),id)) + slots = cr.fetchall() + elif dt_from.weekday() not in [5, 6]: + slots = [(8, 12), (13, 17)] + else: + slots = [] + + for (hour_from, hour_to) in slots: + + hour_from = hour_from - tz_gap + if hour_from < 0: + hour_from = 0 + if hour_from > 24: + hour_from = 24 + hour_to = hour_to - tz_gap + if hour_to < 0: + hour_to = 0 + if hour_to > 24: + hour_to = 24 + + dt_from_hours = dt_from.hour + dt_from.minute / 60.0 + dt_from.second / 3600.0 + + first_day = dt_from.year == orig_dt_from.year and dt_from.month == orig_dt_from.month and dt_from.day == orig_dt_from.day + last_day = dt_from.year == dt_to.year and dt_from.month == dt_to.month and dt_from.day == dt_to.day + + # special case: the ticket is closed the same day it is opened: + if first_day and last_day: + # no overlap (beginning time after end of current slot or ending time before beginning of current slot) + if dt_from_hours >= hour_to or dt_to_hours <= hour_from: + continue + # beginning of working hours is after beginning time and ending time is after end of working hours: add the entire slot + elif dt_from_hours <= hour_from and dt_to_hours >= hour_to: + hours += hour_to - hour_from + # add only the overlap (left) + elif dt_from_hours >= hour_from and dt_to_hours >= hour_to: + hours += hour_to - dt_from_hours + # add only the overlap (right) + elif dt_from_hours <= hour_from and dt_to_hours <= hour_to: + hours += dt_to_hours - hour_from + # add only the overlap (both sides) else: - d1 = dt_from - d2 = datetime(dt_from.year, dt_from.month, dt_from.day, int(math.floor(hour_to)), int((hour_to%1) * 60)) + hours += dt_to_hours - dt_from_hours + + # first day: only add from beginning time to end of working hours + elif first_day: + # no overlap (beginning time after end of current slot) + if dt_from_hours >= hour_to: + continue + # beginning of working hours is after beginning time: add the entire slot + elif dt_from_hours <= hour_from: + hours += hour_to - hour_from + # add only the overlap + else: + hours += hour_to - dt_from_hours - if hours != 0.0:#For first time of the loop only,hours will be 0 - d1 = datetime(dt_from.year, dt_from.month, dt_from.day, int(math.floor(current_hour)), int((current_hour%1) * 60)) - - if dt_from.day == dt_to.day: - if hour_from <= dt_to.hour <= hour_to: - d2 = dt_to - dt_from = d2 - hours += (d2-d1).seconds - dt_from = datetime(dt_from.year, dt_from.month, dt_from.day, int(math.floor(current_hour)), int((current_hour%1) * 60)) + timedelta(days=1) - current_hour = 0.0 - - return (hours/3600) + + # last day: only add from beginning of working hours to ending time + elif last_day: + # no overlap (ending time before beginning of current slot) + if dt_to_hours <= hour_from: + continue + # ending time is after end of working hours: add the entire slot + elif dt_to_hours >= hour_to: + hours += hour_to - hour_from + # add only the overlap + else: + hours += dt_to_hours - hour_from + + # complete day in the middle: add complete working hours + else: + hours += hour_to - hour_from + + dt_from += timedelta(days=1) + dt_from = datetime(dt_from.year, dt_from.month, dt_from.day) + + return hours resource_calendar() From 45ca6f1773dab66a66b2d94640636ba078957cb3 Mon Sep 17 00:00:00 2001 From: Xavier ALT Date: Tue, 30 Oct 2012 18:53:03 +0100 Subject: [PATCH 2/4] [IMP] resource: _interval_hours_get(): keep previous method signature, re-add basic support for leaves, simply interval intesection code bzr revid: xal@openerp.com-20121030175303-x09m6wjl3ah7pu9x --- addons/project_issue/project_issue.py | 18 ++- addons/resource/resource.py | 196 +++++++++++++------------- 2 files changed, 112 insertions(+), 102 deletions(-) diff --git a/addons/project_issue/project_issue.py b/addons/project_issue/project_issue.py index 3742a53d1a0..9d3de2c4f86 100644 --- a/addons/project_issue/project_issue.py +++ b/addons/project_issue/project_issue.py @@ -98,10 +98,10 @@ class project_issue(crm.crm_case, osv.osv): """ cal_obj = self.pool.get('resource.calendar') res_obj = self.pool.get('resource.resource') - + res = {} for issue in self.browse(cr, uid, ids, context=context): - + # if the working hours on the project are not defined, use default ones (8 -> 12 and 13 -> 17 * 5), represented by None if not issue.project_id or not issue.project_id.resource_calendar_id: working_hours = None @@ -121,18 +121,24 @@ class project_issue(crm.crm_case, osv.osv): ans = date_open - date_create date_until = issue.date_open #Calculating no. of working hours to open the issue - hours = cal_obj.interval_hours_get(cr, issue.user_id.id or uid, working_hours, + hours = cal_obj._interval_hours_get(cr, uid, working_hours, date_create, - date_open) + date_open, + timezone_from_uid=issue.user_id.id or uid, + exclude_leaves=False, + context=context) elif field in ['working_hours_close','day_close']: if issue.date_closed: date_close = datetime.strptime(issue.date_closed, "%Y-%m-%d %H:%M:%S") date_until = issue.date_closed ans = date_close - date_create #Calculating no. of working hours to close the issue - hours = cal_obj.interval_hours_get(cr, issue.user_id.id or uid, working_hours, + hours = cal_obj._interval_hours_get(cr, uid, working_hours, date_create, - date_close) + date_close, + timezone_from_uid=issue.user_id.id or uid, + exclude_leaves=False, + context=context) elif field in ['days_since_creation']: if issue.create_date: days_since_creation = datetime.today() - datetime.strptime(issue.create_date, "%Y-%m-%d %H:%M:%S") diff --git a/addons/resource/resource.py b/addons/resource/resource.py index fd3b7ed03f9..254895b2068 100644 --- a/addons/resource/resource.py +++ b/addons/resource/resource.py @@ -19,7 +19,9 @@ # ############################################################################## +import pytz from datetime import datetime, timedelta +from dateutil import rrule import math from faces import * from osv import fields, osv @@ -28,8 +30,6 @@ from tools.translate import _ from itertools import groupby from operator import itemgetter -import pytz - class resource_calendar(osv.osv): _name = "resource.calendar" _description = "Resource Calendar" @@ -200,7 +200,7 @@ class resource_calendar(osv.osv): 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)] return res - def interval_hours_get(self, cr, uid, id, dt_from, dt_to, resource=False, context=None): + def interval_hours_get(self, cr, uid, id, dt_from, dt_to, resource=False): """ Calculates the Total Working hours based on given start_date to end_date, If resource id is supplied that it will consider the source leaves also in calculating the hours. @@ -213,104 +213,108 @@ class resource_calendar(osv.osv): @return : Total number of working hours based dt_from and dt_end and resource if supplied. """ - - hours = 0.0 - - dt_to_hours = dt_to.hour + dt_to.minute / 60.0 + dt_to.second / 3600.0 + if not id: + return 0.0 + return self._internal_hours_get(cr, uid, id, dt_from, dt_to, resource_id=resource) - users_obj = self.pool.get('res.users') - user = users_obj.browse(cr, uid, uid, context=context) - utc = pytz.timezone('UTC') - - if user.context_tz: - context_tz = pytz.timezone(user.context_tz) + def _interval_hours_get(self, cr, uid, id, dt_from, dt_to, resource_id=False, timezone_from_uid=None, exclude_leaves=True, context=None): + """ Calculates the Total Working hours based on given start_date to + end_date, If resource id is supplied that it will consider the source + leaves also in calculating the hours. + + @param dt_from : date start to calculate hours + @param dt_end : date end to calculate hours + @param resource_id: optional resource id, If given resource leave will be + considered. + @param timezone_from_uid: optional uid, if given we will considerer + working hours in that user timezone + @param exclude_leaves: optionnal, if set to True (default) we will exclude + resource leaves from working hours + @param context: current request context + @return : Total number of working hours based dt_from and dt_end and + resource if supplied. + """ + utc_tz = pytz.timezone('UTC') + local_tz = utc_tz + + if timezone_from_uid: + users_obj = self.pool.get('res.users') + user_timezone = users_obj.browse(cr, uid, timezone_from_uid, context=context).context_tz + if user_timezone: + try: + local_tz = pytz.timezone(user_timezone) + except pytz.UnknownTimeZoneError: + pass # fallback to UTC as local timezone + + def utc_to_local_zone(naive_datetime): + utc_dt = utc_tz.localize(naive_datetime, is_dst=False) + return utc_dt.astimezone(local_tz) + + def float_time_convert(float_val): + factor = float_val < 0 and -1 or 1 + val = abs(float_val) + return (factor * int(math.floor(val)), int(round((val % 1) * 60))) + + # Get slots hours per day + # {day_of_week: [(8, 12), (13, 17), ...], ...} + hours_range_per_weekday = {} + if id: + cr.execute("select dayofweek, hour_from,hour_to from resource_calendar_attendance where calendar_id=%s order by hour_from", (id,)) + for weekday, hour_from, hour_to in cr.fetchall(): + weekday = int(weekday) + hours_range_per_weekday.setdefault(weekday, []) + hours_range_per_weekday[weekday].append((hour_from, hour_to)) else: - context_tz = utc - - # gap between UTC and user timezone - tz_gap = (utc.localize(dt_from) - context_tz.localize(dt_from)).seconds / 3600 + # considering default working hours (Monday -> Friday, 8 -> 12, 13 -> 17) + for weekday in range(5): + hours_range_per_weekday[weekday] = [(8, 12), (13, 17)] - orig_dt_from = dt_from + ## Interval between dt_from - dt_to + ## + ## dt_from dt_to + ## =============|==================|============ + ## [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] + ## + ## [ : start of range + ## ] : end of range + ## + ## case 1: range end before interval start (skip) + ## case 2: range overlap interval start (fit start to internal) + ## case 3: range within interval + ## case 4: range overlap interval end (fit end to interval) + ## case 5: range start after interval end (skip) - while dt_from <= dt_to: - # if the working hours are None, use the default ones - if id: - cr.execute("select hour_from,hour_to from resource_calendar_attendance where dayofweek='%s' and calendar_id=%s order by hour_from", (dt_from.weekday(),id)) - slots = cr.fetchall() - elif dt_from.weekday() not in [5, 6]: - slots = [(8, 12), (13, 17)] - else: - slots = [] - - for (hour_from, hour_to) in slots: - - hour_from = hour_from - tz_gap - if hour_from < 0: - hour_from = 0 - if hour_from > 24: - hour_from = 24 - hour_to = hour_to - tz_gap - if hour_to < 0: - hour_to = 0 - if hour_to > 24: - hour_to = 24 - - dt_from_hours = dt_from.hour + dt_from.minute / 60.0 + dt_from.second / 3600.0 - - first_day = dt_from.year == orig_dt_from.year and dt_from.month == orig_dt_from.month and dt_from.day == orig_dt_from.day - last_day = dt_from.year == dt_to.year and dt_from.month == dt_to.month and dt_from.day == dt_to.day - - # special case: the ticket is closed the same day it is opened: - if first_day and last_day: - # no overlap (beginning time after end of current slot or ending time before beginning of current slot) - if dt_from_hours >= hour_to or dt_to_hours <= hour_from: - continue - # beginning of working hours is after beginning time and ending time is after end of working hours: add the entire slot - elif dt_from_hours <= hour_from and dt_to_hours >= hour_to: - hours += hour_to - hour_from - # add only the overlap (left) - elif dt_from_hours >= hour_from and dt_to_hours >= hour_to: - hours += hour_to - dt_from_hours - # add only the overlap (right) - elif dt_from_hours <= hour_from and dt_to_hours <= hour_to: - hours += dt_to_hours - hour_from - # add only the overlap (both sides) - else: - hours += dt_to_hours - dt_from_hours - - # first day: only add from beginning time to end of working hours - elif first_day: - # no overlap (beginning time after end of current slot) - if dt_from_hours >= hour_to: - continue - # beginning of working hours is after beginning time: add the entire slot - elif dt_from_hours <= hour_from: - hours += hour_to - hour_from - # add only the overlap - else: - hours += hour_to - dt_from_hours + interval_start = utc_to_local_zone(dt_from) + interval_end = utc_to_local_zone(dt_to) + hours_timedelta = timedelta() - - # last day: only add from beginning of working hours to ending time - elif last_day: - # no overlap (ending time before beginning of current slot) - if dt_to_hours <= hour_from: - continue - # ending time is after end of working hours: add the entire slot - elif dt_to_hours >= hour_to: - hours += hour_to - hour_from - # add only the overlap - else: - hours += dt_to_hours - hour_from - - # complete day in the middle: add complete working hours - else: - hours += hour_to - hour_from - - dt_from += timedelta(days=1) - dt_from = datetime(dt_from.year, dt_from.month, dt_from.day) - - return hours + # Get leaves for requested resource + dt_leaves = set([]) + if exclude_leaves and id: + dt_leaves = set(self._get_leaves(cr, uid, id, resource=resource_id)) + + for day in rrule.rrule(rrule.DAILY, dtstart=interval_start, + until=interval_end+timedelta(days=1), + byweekday=hours_range_per_weekday.keys()): + if exclude_leaves and day.strftime('%Y-%m-%d') in dt_leaves: + # XXX: futher improve leave management to allow for partial day leave + continue + for (range_from, range_to) in hours_range_per_weekday.get(day.weekday(), []): + range_from_hour, range_from_min = float_time_convert(range_from) + range_to_hour, range_to_min = float_time_convert(range_to) + daytime_start = local_tz.localize(day.replace(hour=range_from_hour, minute=range_from_min, second=0, tzinfo=None)) + daytime_end = local_tz.localize(day.replace(hour=range_to_hour, minute=range_to_min, second=0, tzinfo=None)) + + # case 1 & 5: time range out of interval + if daytime_end < interval_start or daytime_start > interval_end: + continue + # case 2 & 4: adjust start, end to fit within interval + daytime_start = max(daytime_start, interval_start) + daytime_end = min(daytime_end, interval_end) + # case 2+, 4+, 3 + hours_timedelta += (daytime_end - daytime_start) + # return timedelta converted to hours + return (hours_timedelta.days * 24.0 + hours_timedelta.seconds / 3600.0) resource_calendar() From c73d9ff5629004f6776732ba77c021bd72478d95 Mon Sep 17 00:00:00 2001 From: Xavier ALT Date: Tue, 30 Oct 2012 20:38:23 +0100 Subject: [PATCH 3/4] [FIX] resource: fix stupid typo bzr revid: xal@openerp.com-20121030193823-m9fl6g3jia57w98t --- addons/resource/resource.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/resource/resource.py b/addons/resource/resource.py index 254895b2068..4841add2727 100644 --- a/addons/resource/resource.py +++ b/addons/resource/resource.py @@ -215,7 +215,7 @@ class resource_calendar(osv.osv): """ if not id: return 0.0 - return self._internal_hours_get(cr, uid, id, dt_from, dt_to, resource_id=resource) + return self._interval_hours_get(cr, uid, id, 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): """ Calculates the Total Working hours based on given start_date to From 528fd7c2cb352d60b44442bcd45359f199bd151c Mon Sep 17 00:00:00 2001 From: Xavier ALT Date: Tue, 30 Oct 2012 21:55:14 +0100 Subject: [PATCH 4/4] [TEST] update test for resource interval_hours_get() Change test from ">" to ">=" 27, as we now have a correct calculation we will get exactly 27 hours for 'resource_developer' if test is done after 18h00 (5 working day of 9 hours, minus Monday - not included in interval as dt_from after working hours, minus Thursday - leave day) bzr revid: xal@openerp.com-20121030205514-gyf925370alc9lf8 --- addons/resource/test/resource.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/resource/test/resource.yml b/addons/resource/test/resource.yml index 5b7fa108101..bce671549d7 100644 --- a/addons/resource/test/resource.yml +++ b/addons/resource/test/resource.yml @@ -45,7 +45,7 @@ dt_from = now - timedelta(days=now.weekday()) dt_to = dt_from+ timedelta(days=6) 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' + assert hours >= 27 , 'Invalid Total Week working hour calculated' - 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. -