From f78b03a134690db4f722bd3e490f83964a17ff7f Mon Sep 17 00:00:00 2001 From: "olt@tinyerp.com" <> Date: Wed, 29 Sep 2010 14:13:40 +0200 Subject: [PATCH] [IMP] resource: performance improvement: created a 'resource.calendar' interval_get_multi which takes a list of tuples instead of single arguments 'interval_get' is not removed and now uses the multi method to avoid duplicated code bzr revid: olt@tinyerp.com-20100929121340-g9hpmkavpguizajg --- addons/mrp_operations/mrp_operations.py | 14 ++-- addons/resource/resource.py | 99 ++++++++++++++++--------- 2 files changed, 72 insertions(+), 41 deletions(-) diff --git a/addons/mrp_operations/mrp_operations.py b/addons/mrp_operations/mrp_operations.py index 919f65903ae..52a8a81cb49 100644 --- a/addons/mrp_operations/mrp_operations.py +++ b/addons/mrp_operations/mrp_operations.py @@ -62,26 +62,30 @@ class mrp_production_workcenter_line(osv.osv): else: res[op.id]=False return res - + def _get_date_end(self, cr, uid, ids, field_name, arg, context): """ Finds ending date. @return: Dictionary of values. """ + ops = self.browse(cr, uid, ids, context=context) + date_and_hours_by_cal = [(op.date_planned, op.hour, op.workcenter_id.calendar_id.id) for op in ops] + intervals = self.pool.get('resource.calendar').interval_get_multi(cr, uid, date_and_hours_by_cal) + res = {} - for op in self.browse(cr, uid, ids, context=context): + for op in ops: res[op.id] = False if op.date_planned: d = DateTime.strptime(op.date_planned,'%Y-%m-%d %H:%M:%S') - i = self.pool.get('resource.calendar').interval_get(cr, uid, op.workcenter_id.calendar_id.id or False, d, op.hour or 0.0) + i = intervals[(op.date_planned, op.hour, op.workcenter_id.calendar_id.id)] if i: res[op.id] = i[-1][1].strftime('%Y-%m-%d %H:%M:%S') else: res[op.id] = op.date_planned return res - + _inherit = 'mrp.production.workcenter.line' _order = "sequence, date_planned" - + _columns = { 'state': fields.selection([('draft','Draft'),('startworking', 'In Progress'),('pause','Pause'),('cancel','Cancelled'),('done','Finished')],'State', readonly=True, help="* When a work order is created it is set in 'Draft' state.\n" \ diff --git a/addons/resource/resource.py b/addons/resource/resource.py index 4a2ff3e34dd..24efc179c03 100644 --- a/addons/resource/resource.py +++ b/addons/resource/resource.py @@ -20,12 +20,17 @@ ############################################################################## from datetime import datetime, timedelta +from mx import DateTime import math from faces import * from new import classobj from osv import fields, osv from tools.translate import _ +from itertools import groupby +from operator import itemgetter + + class resource_calendar(osv.osv): _name = "resource.calendar" _description = "Resource Calendar" @@ -44,11 +49,12 @@ class resource_calendar(osv.osv): dt_leave = [] resource_leave_ids = resource_cal_leaves.search(cr, uid, [('calendar_id','=',id), '|', ('resource_id','=',False), ('resource_id','=',resource)]) - res_leaves = resource_cal_leaves.read(cr, uid, resource_leave_ids, ['date_from', 'date_to']) + #res_leaves = resource_cal_leaves.read(cr, uid, resource_leave_ids, ['date_from', 'date_to']) + res_leaves = resource_cal_leaves.browse(cr, uid, resource_leave_ids) for leave in res_leaves: - dtf = datetime.strptime(leave['date_from'], '%Y-%m-%d %H:%M:%S') - dtt = datetime.strptime(leave['date_to'], '%Y-%m-%d %H:%M:%S') + dtf = datetime.strptime(leave.date_from, '%Y-%m-%d %H:%M:%S') + dtt = datetime.strptime(leave.date_to, '%Y-%m-%d %H:%M:%S') no = dtt - dtf [dt_leave.append((dtf + timedelta(days=x)).strftime('%Y-%m-%d')) for x in range(int(no.days + 1))] dt_leave.sort() @@ -92,40 +98,61 @@ class resource_calendar(osv.osv): result.reverse() return result + # def interval_get(self, cr, uid, id, dt_from, hours, resource=False, byday=True): + def interval_get_multi(self, cr, uid, date_and_hours_by_cal, resource=False, byday=True): + def group(lst, key): + lst.sort(key=itemgetter(key)) + grouped = groupby(lst, itemgetter(key)) + return dict([(k, [v for v in itr]) for k, itr in grouped]) + # END group + + cr.execute("select calendar_id, dayofweek, hour_from, hour_to from resource_calendar_attendance order by hour_from") + hour_res = cr.dictfetchall() + hours_by_cal = group(hour_res, 'calendar_id') + + results = {} + + for d, hours, id in date_and_hours_by_cal: + dt_from = DateTime.strptime(d, '%Y-%m-%d %H:%M:%S') + if not id: + td = int(hours)*3 + results[(d, hours, id)] = [(dt_from, dt_from + timedelta(hours=td))] + continue + + dt_leave = self._get_leaves(cr, uid, id, resource) + todo = hours + result = [] + maxrecur = 100 + current_hour = dt_from.hour + while (todo>0) and maxrecur: + for (hour_from,hour_to) in [(item['hour_from'], item['hour_to']) for item in hours_by_cal[id] if item['dayofweek'] == str(dt_from.weekday())]: + leave_flag = False + if (hour_to>current_hour) and (todo>0): + m = max(hour_from, current_hour) + if (hour_to-m)>todo: + hour_to = m+todo + 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 + if leave_flag: + break + else: + d1 = datetime(dt_from.year, dt_from.month, dt_from.day, int(math.floor(m)), int((m%1) * 60)) + d2 = datetime(dt_from.year, dt_from.month, dt_from.day, int(math.floor(hour_to)), int((hour_to%1) * 60)) + result.append((d1, d2)) + current_hour = hour_to + todo -= (hour_to - m) + dt_from += timedelta(days=1) + current_hour = 0 + maxrecur -= 1 + results[(d, hours, id)] = result + return results + def interval_get(self, cr, uid, id, dt_from, hours, resource=False, byday=True): - if not id: - td = int(hours)*3 - return [(dt_from, dt_from + timedelta(hours=td))] - dt_leave = self._get_leaves(cr, uid, id, resource) - todo = hours - result = [] - maxrecur = 100 - current_hour = dt_from.hour - while (todo>0) and maxrecur: - 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)) - for (hour_from,hour_to) in cr.fetchall(): - leave_flag = False - if (hour_to>current_hour) and (todo>0): - m = max(hour_from, current_hour) - if (hour_to-m)>todo: - hour_to = m+todo - 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 - if leave_flag: - break - else: - d1 = datetime(dt_from.year, dt_from.month, dt_from.day, int(math.floor(m)), int((m%1) * 60)) - d2 = datetime(dt_from.year, dt_from.month, dt_from.day, int(math.floor(hour_to)), int((hour_to%1) * 60)) - result.append((d1, d2)) - current_hour = hour_to - todo -= (hour_to - m) - dt_from += timedelta(days=1) - current_hour = 0 - maxrecur -= 1 - return result + 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): if not id: