From f691dc9f77b726045e766e43586468522bca3a19 Mon Sep 17 00:00:00 2001
From: "olt@tinyerp.com" <>
Date: Mon, 20 Sep 2010 13:11:10 +0200
Subject: [PATCH 01/10] [IMP] mrp: performance improvement: avoid select sql
inside loops
bzr revid: olt@tinyerp.com-20100920111110-c7bw90kns2bo6jpo
---
addons/mrp/mrp.py | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py
index 4915ac7fc01..a7c44e5f7c0 100644
--- a/addons/mrp/mrp.py
+++ b/addons/mrp/mrp.py
@@ -355,13 +355,17 @@ class many2many_domain(fields.many2many):
def get(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None):
if not context:
context = {}
- res = {}
+
move_obj = obj.pool.get('stock.move')
- for prod in obj.browse(cr, user, ids, context=context):
- cr.execute("SELECT move_id from mrp_production_move_ids where production_id=%s" % (prod.id))
- m_ids = map(lambda x: x[0], cr.fetchall())
- final = move_obj.search(cr, user, self._domain + [('id', 'in', tuple(m_ids))])
- res[prod.id] = final
+ res = {}.fromkeys(ids, [])
+ key = operator.itemgetter(0)
+ valid_move_ids = move_obj.search(cr, user, self._domain) # move ids relative to domain argument
+ cr.execute("SELECT production_id, move_id from mrp_production_move_ids where production_id in %s and move_id in %s",
+ [tuple(ids), tuple(valid_move_ids)])
+ related_move_map = cr.fetchall()
+ related_move_dict = dict((k, list(set([v[1] for v in itr]))) for k, itr in itertools.groupby(related_move_map, key))
+ res.update(related_move_dict)
+
return res
class one2many_domain(fields.one2many):
@@ -377,8 +381,7 @@ class one2many_domain(fields.one2many):
res = {}.fromkeys(ids, [])
key = operator.itemgetter(0)
move_ids = move_obj.search(cr, user, self._domain+[('production_id', 'in', tuple(ids))], context=context)
- related_move_map = [(o.production_id.id, o.id) for o in move_obj.browse(cr, user, move_ids, context=context)]
- related_move_dict = dict((k, [v[1] for v in itr]) for k, itr in itertools.groupby(related_move_map, key))
+ related_move_dict = dict([(o.production_id.id, [o.id]) for o in move_obj.browse(cr, user, move_ids, context=context)])
res.update(related_move_dict)
return res
From 4d96d4657d3453a562eb552b529a2d4258a8c7ad Mon Sep 17 00:00:00 2001
From: "olt@tinyerp.com" <>
Date: Mon, 20 Sep 2010 13:37:45 +0200
Subject: [PATCH 02/10] [FIX] base_calendar: access to browse_null attributes
bzr revid: olt@tinyerp.com-20100920113745-o45rgjk2onl4aja5
---
addons/base_calendar/base_calendar.py | 8 ++++++--
.../base_calendar/wizard/base_calendar_invite_attendee.py | 3 ++-
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/addons/base_calendar/base_calendar.py b/addons/base_calendar/base_calendar.py
index 11bd22e6134..a08af3da241 100644
--- a/addons/base_calendar/base_calendar.py
+++ b/addons/base_calendar/base_calendar.py
@@ -484,8 +484,12 @@ property or property parameter."),
res_obj = att.ref
sub = res_obj.name
att_infos = []
- other_invitaion_ids = self.search(cr, uid, [('ref', '=', res_obj._name + ',' + str(res_obj.id))])
- for att2 in self.browse(cr, uid, other_invitaion_ids):
+ if res_obj:
+ other_invitation_ids = self.search(cr, uid, [('ref', '=', res_obj._name + ',' + str(res_obj.id))])a
+ else:
+ other_invitation_ids = []
+
+ for att2 in self.browse(cr, uid, other_invitation_ids):
att_infos.append(((att2.user_id and att2.user_id.name) or \
(att2.partner_id and att2.partner_id.name) or \
att2.email) + ' - Status: ' + att2.state.title())
diff --git a/addons/base_calendar/wizard/base_calendar_invite_attendee.py b/addons/base_calendar/wizard/base_calendar_invite_attendee.py
index f60139c0600..98369962ab7 100644
--- a/addons/base_calendar/wizard/base_calendar_invite_attendee.py
+++ b/addons/base_calendar/wizard/base_calendar_invite_attendee.py
@@ -128,8 +128,9 @@ send an Email to Invited Person')
att = att_obj.browse(cr, uid, context_id)
att_val.update({
'parent_ids': [(4, att.id)],
- 'ref': att.ref._name + ',' +str(att.ref.id)
+ 'ref': att.ref and (att.ref._name + ',' +str(att.ref.id)) or False
})
+
attendees.append(att_obj.create(cr, uid, att_val))
if model_field:
for attendee in attendees:
From 5783cb0ae7a995fa28e0578f46967f7d74d4ae44 Mon Sep 17 00:00:00 2001
From: "olt@tinyerp.com" <>
Date: Mon, 20 Sep 2010 13:39:07 +0200
Subject: [PATCH 03/10] [FIX] base_calendar: typo after the 'access to
browse_null attributes' fix
bzr revid: olt@tinyerp.com-20100920113907-hm34f2gm5m53vifk
---
addons/base_calendar/base_calendar.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/addons/base_calendar/base_calendar.py b/addons/base_calendar/base_calendar.py
index a08af3da241..c778bf6b63a 100644
--- a/addons/base_calendar/base_calendar.py
+++ b/addons/base_calendar/base_calendar.py
@@ -485,7 +485,7 @@ property or property parameter."),
sub = res_obj.name
att_infos = []
if res_obj:
- other_invitation_ids = self.search(cr, uid, [('ref', '=', res_obj._name + ',' + str(res_obj.id))])a
+ other_invitation_ids = self.search(cr, uid, [('ref', '=', res_obj._name + ',' + str(res_obj.id))])
else:
other_invitation_ids = []
From 568351b86acf37bfade00da7c8f1ba5065f03fc2 Mon Sep 17 00:00:00 2001
From: "olt@tinyerp.com" <>
Date: Mon, 20 Sep 2010 13:49:32 +0200
Subject: [PATCH 04/10] [FIX] base_calendar: fixed some errors (using a
browse_null object)
bzr revid: olt@tinyerp.com-20100920114932-ejr0m9i9foznhr9m
---
addons/base_calendar/base_calendar.py | 67 ++++++++++++++-------------
1 file changed, 34 insertions(+), 33 deletions(-)
diff --git a/addons/base_calendar/base_calendar.py b/addons/base_calendar/base_calendar.py
index c778bf6b63a..facb598427b 100644
--- a/addons/base_calendar/base_calendar.py
+++ b/addons/base_calendar/base_calendar.py
@@ -398,10 +398,13 @@ property or property parameter."),
"""
res = None
def ics_datetime(idate, short=False):
- if short:
- return date.fromtimestamp(time.mktime(time.strptime(idate, '%Y-%m-%d')))
+ if idate:
+ if short:
+ return date.fromtimestamp(time.mktime(time.strptime(idate, '%Y-%m-%d')))
+ else:
+ return datetime.strptime(idate, '%Y-%m-%d %H:%M:%S')
else:
- return datetime.strptime(idate, '%Y-%m-%d %H:%M:%S')
+ return False
try:
# FIXME: why isn't this in CalDAV?
import vobject
@@ -482,39 +485,37 @@ property or property parameter."),
sign = att.sent_by_uid and att.sent_by_uid.signature or ''
sign = '
'.join(sign and sign.split('\n') or [])
res_obj = att.ref
- sub = res_obj.name
- att_infos = []
if res_obj:
+ att_infos = []
+ sub = res_obj.name
other_invitation_ids = self.search(cr, uid, [('ref', '=', res_obj._name + ',' + str(res_obj.id))])
- else:
- other_invitation_ids = []
- for att2 in self.browse(cr, uid, other_invitation_ids):
- att_infos.append(((att2.user_id and att2.user_id.name) or \
- (att2.partner_id and att2.partner_id.name) or \
- att2.email) + ' - Status: ' + att2.state.title())
- body_vals = {'name': res_obj.name,
- 'start_date': res_obj.date,
- 'end_date': res_obj.date_deadline or False,
- 'description': res_obj.description or '-',
- 'location': res_obj.location or '-',
- 'attendees': '
'.join(att_infos),
- 'user': res_obj.user_id and res_obj.user_id.name or 'OpenERP User',
- 'sign': sign,
- 'company': company
- }
- body = html_invitation % body_vals
- if mail_to and email_from:
- attach = self.get_ics_file(cr, uid, res_obj, context=context)
- tools.email_send(
- email_from,
- mail_to,
- sub,
- body,
- attach=attach and [('invitation.ics', attach)] or None,
- subtype='html',
- reply_to=email_from
- )
+ for att2 in self.browse(cr, uid, other_invitation_ids):
+ att_infos.append(((att2.user_id and att2.user_id.name) or \
+ (att2.partner_id and att2.partner_id.name) or \
+ att2.email) + ' - Status: ' + att2.state.title())
+ body_vals = {'name': res_obj.name,
+ 'start_date': res_obj.date,
+ 'end_date': res_obj.date_deadline or False,
+ 'description': res_obj.description or '-',
+ 'location': res_obj.location or '-',
+ 'attendees': '
'.join(att_infos),
+ 'user': res_obj.user_id and res_obj.user_id.name or 'OpenERP User',
+ 'sign': sign,
+ 'company': company
+ }
+ body = html_invitation % body_vals
+ if mail_to and email_from:
+ attach = self.get_ics_file(cr, uid, res_obj, context=context)
+ tools.email_send(
+ email_from,
+ mail_to,
+ sub,
+ body,
+ attach=attach and [('invitation.ics', attach)] or None,
+ subtype='html',
+ reply_to=email_from
+ )
return True
def onchange_user_id(self, cr, uid, ids, user_id, *args, **argv):
From 993a1f275e6b0ab4aee514f02014591118b04e53 Mon Sep 17 00:00:00 2001
From: Fabien Pinckaers
Date: Mon, 20 Sep 2010 14:07:06 +0200
Subject: [PATCH 05/10] fix
bzr revid: fp@tinyerp.com-20100920120706-ob8781j8tmxd8743
---
addons/project/project.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/addons/project/project.py b/addons/project/project.py
index 0b9584655a8..dc6a6d20afb 100644
--- a/addons/project/project.py
+++ b/addons/project/project.py
@@ -426,7 +426,7 @@ class task(osv.osv):
'parent_ids': fields.many2many('project.task', 'project_task_parent_rel', 'task_id', 'parent_id', 'Parent Tasks'),
'child_ids': fields.many2many('project.task', 'project_task_parent_rel', 'parent_id', 'task_id', 'Delegated Tasks'),
'notes': fields.text('Notes'),
- 'planned_hours': fields.float('Planned Hours', required=True, help='Estimated time to do the task, usually set by the project manager when the task is in draft state.'),
+ 'planned_hours': fields.float('Planned Hours', help='Estimated time to do the task, usually set by the project manager when the task is in draft state.'),
'effective_hours': fields.function(_hours_get, method=True, string='Hours Spent', multi='hours', store=True, help="Computed using the sum of the task work done."),
'remaining_hours': fields.float('Remaining Hours', digits=(16,2), help="Total remaining time, can be re-estimated periodically by the assignee of the task."),
'total_hours': fields.function(_hours_get, method=True, string='Total Hours', multi='hours', store=True, help="Computed as: Time Spent + Remaining Time."),
From 6084e072d6f3a1b9aa6ff3b0189cfd30c1f09098 Mon Sep 17 00:00:00 2001
From: "JMA(OpenERP)" <>
Date: Mon, 20 Sep 2010 18:02:36 +0530
Subject: [PATCH 06/10] [FIX] CRM : Report for Business opportunities corrected
lp bug: https://launchpad.net/bugs/642095 fixed
bzr revid: jvo@tinyerp.com-20100920123236-45pfwtpsr97nmshf
---
addons/crm/report/report_businessopp.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/addons/crm/report/report_businessopp.py b/addons/crm/report/report_businessopp.py
index 7cadb41359a..07751622abe 100644
--- a/addons/crm/report/report_businessopp.py
+++ b/addons/crm/report/report_businessopp.py
@@ -83,12 +83,12 @@ class report_custom(report_int):
if benefit < minbenef:
minbenef = benefit
- tuple = (proba * 100, benefit)
+ tuple_benefit = (proba * 100, benefit)
responsible_data.setdefault(userid, [])
- responsible_data[userid].append(tuple)
+ responsible_data[userid].append(tuple_benefit)
- tuple = (proba * 100, cost, benefit)
- data.append(tuple)
+ tuple_benefit = (proba * 100, cost, benefit)
+ data.append(tuple_benefit)
responsible_names[userid] = (row['name'] or '/').replace('/','//')
From c54c4dd3e628ab4de11c5cb024c5ab329e915e44 Mon Sep 17 00:00:00 2001
From: "olt@tinyerp.com" <>
Date: Mon, 20 Sep 2010 15:51:40 +0200
Subject: [PATCH 07/10] [IMP] project: performance improvement: moved
'_get_user_and_default_uom_ids' method outside the loop
bzr revid: olt@tinyerp.com-20100920135140-yaxst57a22r1pxvo
---
addons/project/project.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/addons/project/project.py b/addons/project/project.py
index dc6a6d20afb..6aa3eaef151 100644
--- a/addons/project/project.py
+++ b/addons/project/project.py
@@ -128,6 +128,7 @@ class project(osv.osv):
project_id''',(tuple(all_projects),))
progress = dict(map(lambda x: (x[0], (x[1], x[2], x[3])), cr.fetchall()))
+ user_uom, def_uom = self._get_user_and_default_uom_ids(cr, uid)
for project in self.browse(cr, uid, par_child_projects.keys(), context=context):
s = [0.0, 0.0, 0.0]
tocompute = par_child_projects[project.id]
@@ -137,7 +138,6 @@ class project(osv.osv):
s[i] += progress.get(p, (0.0, 0.0, 0.0))[i]
uom_obj = self.pool.get('product.uom')
- user_uom, def_uom = self._get_user_and_default_uom_ids(cr, uid)
if user_uom != def_uom:
s[0] = uom_obj._compute_qty(cr, uid, user_uom, s[0], def_uom)
s[1] = uom_obj._compute_qty(cr, uid, user_uom, s[1], def_uom)
From 2e4f798a39a64c631d69ad768423ccf86c31234a Mon Sep 17 00:00:00 2001
From: "olt@tinyerp.com" <>
Date: Mon, 20 Sep 2010 15:59:21 +0200
Subject: [PATCH 08/10] [IMP] project: no need to use operator.itemgetter when
a simple lambda can do the same operation
bzr revid: olt@tinyerp.com-20100920135921-fhqshcnqlepcflly
---
addons/project/project.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/addons/project/project.py b/addons/project/project.py
index 6aa3eaef151..5483d7072c0 100644
--- a/addons/project/project.py
+++ b/addons/project/project.py
@@ -27,7 +27,6 @@ from tools.translate import _
from osv import fields, osv
from tools import email_send as email
-from operator import itemgetter
class project_task_type(osv.osv):
_name = 'project.task.type'
@@ -466,7 +465,7 @@ class task(osv.osv):
cr.execute('SELECT DISTINCT task_id '\
'FROM project_task_parent_rel '\
'WHERE parent_id IN %s', (tuple(ids),))
- child_ids = map(itemgetter(0), cr.fetchall())
+ child_ids = map(lambda x: x[0], cr.fetchall())
c_ids = child_ids
if (list(set(parent_ids).intersection(set(c_ids)))) or (obj_task.id in c_ids):
return False
From 5c94f9e27f68e0b7a154088278b1a7dd12520749 Mon Sep 17 00:00:00 2001
From: "olt@tinyerp.com" <>
Date: Mon, 20 Sep 2010 17:11:56 +0200
Subject: [PATCH 09/10] [IMP] mrp: only import the methods actually used
instead of whole module
bzr revid: olt@tinyerp.com-20100920151156-cz77f9le62a3xo8n
---
addons/mrp/mrp.py | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py
index a7c44e5f7c0..5ad90bf25d6 100644
--- a/addons/mrp/mrp.py
+++ b/addons/mrp/mrp.py
@@ -19,8 +19,8 @@
#
##############################################################################
-import itertools
-import operator
+from itertools import groupby
+from operator import itemgetter
from datetime import datetime
from osv import osv, fields
from tools.translate import _
@@ -358,12 +358,11 @@ class many2many_domain(fields.many2many):
move_obj = obj.pool.get('stock.move')
res = {}.fromkeys(ids, [])
- key = operator.itemgetter(0)
valid_move_ids = move_obj.search(cr, user, self._domain) # move ids relative to domain argument
cr.execute("SELECT production_id, move_id from mrp_production_move_ids where production_id in %s and move_id in %s",
[tuple(ids), tuple(valid_move_ids)])
related_move_map = cr.fetchall()
- related_move_dict = dict((k, list(set([v[1] for v in itr]))) for k, itr in itertools.groupby(related_move_map, key))
+ related_move_dict = dict((k, list(set([v[1] for v in itr]))) for k, itr in groupby(related_move_map, itemgetter(0)))
res.update(related_move_dict)
return res
From 0c1f4b268c6cd663e0077707cd6951106b2f9db5 Mon Sep 17 00:00:00 2001
From: "olt@tinyerp.com" <>
Date: Mon, 20 Sep 2010 17:12:41 +0200
Subject: [PATCH 10/10] [IMP] project: performance improvement: moved sql query
outside loop
bzr revid: olt@tinyerp.com-20100920151241-owecugwym2ft09gy
---
addons/project/project.py | 39 ++++++++++++++++++++++-----------------
1 file changed, 22 insertions(+), 17 deletions(-)
diff --git a/addons/project/project.py b/addons/project/project.py
index 5483d7072c0..6959a19fd03 100644
--- a/addons/project/project.py
+++ b/addons/project/project.py
@@ -22,7 +22,10 @@
from lxml import etree
import time
from datetime import datetime, date
+from operator import itemgetter
+from itertools import groupby
+from tools.misc import flatten
from tools.translate import _
from osv import fields, osv
from tools import email_send as email
@@ -76,20 +79,6 @@ class project(osv.osv):
pricelist_id = pricelist.get('property_product_pricelist', False) and pricelist.get('property_product_pricelist')[0] or False
return {'value':{'contact_id': addr['contact'], 'pricelist_id': pricelist_id}}
- def get_all_child_projects(self, cr, uid, ids, context=None):
- # Calculate child project for Given project id => For progress rate + planned time + Time spent
- cr.execute('''SELECT prpc.id AS id from account_analytic_account AS p
- JOIN account_analytic_account AS c ON p.id = c.parent_id
- JOIN project_project AS prp ON prp.analytic_account_id = p.id
- JOIN project_project AS prpc ON prpc.analytic_account_id = c.id
- WHERE prp.id IN %s''',(tuple(ids),))
-
- child_ids = cr.fetchall()
- if child_ids:
- child_ids = [x[0] for x in child_ids]
- child_ids = self.get_all_child_projects(cr, uid, child_ids)
- return ids + child_ids
-
def _get_user_and_default_uom_ids(self, cr, uid):
users_obj = self.pool.get('res.users')
model_data_obj = self.pool.get('ir.model.data')
@@ -101,17 +90,33 @@ class project(osv.osv):
return user_uom, default_uom
def _progress_rate(self, cr, uid, ids, names, arg, context=None):
+ def _get_all_child_projects(ids):
+ """Recursively get child project ids"""
+ child_ids = flatten([project_hierarchy.get(idn, []) for idn in ids])
+ if child_ids:
+ child_ids = _get_all_child_projects(child_ids)
+ return ids + child_ids
+ # END _get_all_child_projects
+
res = {}.fromkeys(ids, 0.0)
progress = {}
if not ids:
return res
- par_child_projects={}
+ par_child_projects = {}
all_projects = list(ids)
+ # get project hierarchy:
+ cr.execute('''SELECT prp.id AS pr_parent_id, prpc.id AS pr_child_id
+ FROM account_analytic_account AS p
+ JOIN account_analytic_account AS c ON p.id = c.parent_id
+ JOIN project_project AS prp ON prp.analytic_account_id = p.id
+ JOIN project_project AS prpc ON prpc.analytic_account_id = c.id''')
+
+ project_hierarchy = dict((k, list(set([v[1] for v in itr]))) for k, itr in groupby(cr.fetchall(), itemgetter(0)))
+
for id in ids:
- child_projects = self.get_all_child_projects(cr, uid, [id], context)
- child_projects = [x for x in child_projects]
+ child_projects = _get_all_child_projects([id])
par_child_projects[id] = child_projects
all_projects.extend(child_projects)