From a141f9dadbd71afc8d4f286f5cf4b8ea5af10360 Mon Sep 17 00:00:00 2001 From: "nch@tinyerp.com" <> Date: Mon, 28 Dec 2009 11:37:29 +0530 Subject: [PATCH 01/23] read_group method for group by bzr revid: nch@tinyerp.com-20091228060729-2tvfbsxxyq829ulb --- bin/osv/orm.py | 61 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index 280b5020704..9a05def5377 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################## -# +# # OpenERP, Open Source Management Solution # Copyright (C) 2004-2009 Tiny SPRL (). # @@ -15,7 +15,7 @@ # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . +# along with this program. If not, see . # ############################################################################## @@ -212,7 +212,7 @@ class browse_record(object): # create browse records for 'remote' objects for data in datas: if len(str(data['id']).split('-')) > 1: - data['id'] = int(str(data['id']).split('-')[0]) + data['id'] = int(str(data['id']).split('-')[0]) for n, f in ffields: if f._type in ('many2one', 'one2one'): if data[n]: @@ -348,6 +348,41 @@ class orm_template(object): CONCURRENCY_CHECK_FIELD = '__last_update' + def read_group(self, cr, user, domain, fields, order, offset=0, limit=None, context=None): + context = context or {} + # compute the where, order by, limit and offset clauses + (qu1, qu2, tables) = self._where_calc(cr, user, domain, context=context) + if len(qu1): + qu1 = ' where '+string.join(qu1, ' and ') + else: + qu1 = '' + if order: + self._check_qorder(order) + order_by = order or self._order + # sumof = ','.join(['sum('+field_name+')' for field_name,values in fields.items() if values['type'] in ('float','integer')]) # filter fields in args to only get float and int + sumof = ','.join([field_name for field_name,values in fields.items() if values['type'] in ('float','integer')]) # filter fields in args to only get float and int + + limit_str = limit and ' limit %d' % limit or '' + offset_str = offset and ' offset %d' % offset or '' + + # construct a clause for the rules : + d1, d2 = self.pool.get('ir.rule').domain_get(cr, user, self._name) + if d1: + qu1 = qu1 and qu1+' and '+d1 or ' where '+d1 + qu2 += d2 + + # execute the "main" query to fetch the ids we were searching for + cr.execute('select '+order_by+','+sumof+' from %s' % self._table + qu1+' group by '+order_by+','+sumof+limit_str+offset_str, qu2) + result = [] + for x in cr.fetchall(): + result.append({ + 'name':x[0], + 'domain':[(order_by,'=',x[0])], + 'fields': {x[0]:x[1]} + }) + print result + # return result + def _field_create(self, cr, context={}): cr.execute("SELECT id FROM ir_model WHERE model=%s", (self._name,)) if not cr.rowcount: @@ -465,7 +500,7 @@ class orm_template(object): elif field_type == 'boolean': return False return '' - + def selection_field(in_field): col_obj = self.pool.get(in_field.keys()[0]) if f[i] in col_obj._columns.keys(): @@ -473,8 +508,8 @@ class orm_template(object): elif f[i] in col_obj._inherits.keys(): selection_field(col_obj._inherits) else: - return False - + return False + lines = [] data = map(lambda x: '', range(len(fields))) @@ -501,7 +536,7 @@ class orm_template(object): else: r = r[f[i]] # To display external name of selection field when its exported - if not context.get('import_comp',False):# Allow external name only if its not import compatible + if not context.get('import_comp',False):# Allow external name only if its not import compatible cols = False if f[i] in self._columns.keys(): cols = self._columns[f[i]] @@ -1130,7 +1165,7 @@ class orm_template(object): # running -> done = signal_next (role Z) # running -> cancel = signal_cancel (role Z) - # As we don't know the object state, in this scenario, + # As we don't know the object state, in this scenario, # the button "signal_cancel" will be always shown as there is no restriction to cancel in draft # the button "signal_next" will be show if the user has any of the roles (X Y or Z) # The verification will be made later in workflow process... @@ -1929,7 +1964,7 @@ class orm(orm_template): cr.execute('ALTER TABLE "%s" RENAME "%s" TO "%s"' % ( self._table,f.oldname, k)) res = res_old res[0]['attname'] = k - + if not res: if not isinstance(f, fields.function) or f.store: @@ -2017,7 +2052,7 @@ class orm(orm_template): field_size = (65535 * f.digits[0]) + f.digits[0] + f.digits[1] if field_size != f_pg_size: field_size_change = True - + if f_pg_type != f_obj_type or field_size_change: if f_pg_type != f_obj_type: logger.notifyChannel('orm', netsvc.LOG_INFO, "column '%s' in table '%s' changed type to %s." % (k, self._table, c[1])) @@ -2322,7 +2357,7 @@ class orm(orm_template): select = map(lambda x: isinstance(x,dict) and x['id'] or x, select) result = self._read_flat(cr, user, select, fields, context, load) - + for r in result: for key, v in r.items(): if v == None: @@ -2340,8 +2375,8 @@ class orm(orm_template): id_exist = cr.fetchone() if not id_exist: cr.execute('update "'+self._table+'" set "'+key+'"=NULL where "%s"=%s' %(key,''.join("'"+str(v)+"'"))) - r[key] = '' - + r[key] = '' + if isinstance(ids, (int, long, dict)): return result and result[0] or False return result From 718aa9c775a4f78e2d7a11dd0a61832cf37af379 Mon Sep 17 00:00:00 2001 From: "nch@tinyerp.com" <> Date: Tue, 29 Dec 2009 16:50:14 +0530 Subject: [PATCH 02/23] [ADD]:added new functionality read_group' bzr revid: nch@tinyerp.com-20091229112014-wakcjr8xp0l8333v --- bin/osv/orm.py | 81 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 64 insertions(+), 17 deletions(-) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index 9a05def5377..b28b24406fc 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -348,7 +348,7 @@ class orm_template(object): CONCURRENCY_CHECK_FIELD = '__last_update' - def read_group(self, cr, user, domain, fields, order, offset=0, limit=None, context=None): + def read_group(self, cr, user, ids, domain, fields, order, offset=0, limit=None, context=None): context = context or {} # compute the where, order by, limit and offset clauses (qu1, qu2, tables) = self._where_calc(cr, user, domain, context=context) @@ -359,8 +359,10 @@ class orm_template(object): if order: self._check_qorder(order) order_by = order or self._order - # sumof = ','.join(['sum('+field_name+')' for field_name,values in fields.items() if values['type'] in ('float','integer')]) # filter fields in args to only get float and int - sumof = ','.join([field_name for field_name,values in fields.items() if values['type'] in ('float','integer')]) # filter fields in args to only get float and int + + float_int_fields = list(field_name for field_name,values in fields.items() if values['type'] in ('float','integer')) + sumof = ','.join(map(lambda field_name:'sum('+field_name+') as '+field_name+'',float_int_fields)) # filter fields in args to only get float and int + # sumof = ','.join([field_name for field_name,values in fields.items() if values['type'] in ('float','integer')]) # filter fields in args to only get float and int limit_str = limit and ' limit %d' % limit or '' offset_str = offset and ' offset %d' % offset or '' @@ -370,18 +372,64 @@ class orm_template(object): if d1: qu1 = qu1 and qu1+' and '+d1 or ' where '+d1 qu2 += d2 - + if not ids: # execute the "main" query to fetch the ids we were searching for - cr.execute('select '+order_by+','+sumof+' from %s' % self._table + qu1+' group by '+order_by+','+sumof+limit_str+offset_str, qu2) - result = [] - for x in cr.fetchall(): - result.append({ - 'name':x[0], - 'domain':[(order_by,'=',x[0])], - 'fields': {x[0]:x[1]} - }) - print result - # return result + #cr.execute('select distinct('+order_by+'),'+self._table+'.id,'+sumof+' from ' + ','.join(tables) +qu1+' group by '+order_by +','+self._table+'.id'+limit_str+offset_str) + cr.execute('select distinct('+order_by+'),'+sumof+' from ' + ','.join(tables) +qu1+' group by '+order_by +limit_str+offset_str) + res = cr.fetchall() + uniq_ids = () + if fields[order_by]['type'] == 'many2one': + uniq_ids =tuple(set(map(lambda x:str(x[0]),res))) + if uniq_ids and len(uniq_ids) == 1: + cond = ' where id = %s'%(uniq_ids) + else: + cond = ' where id in %s'%(uniq_ids,) + qury = 'select name,id from ' + fields[order_by]['relation'].replace('.','_') + cond + cr.execute(qury) + uniq_order_by_res = dict(map(lambda x:(x[1],x[0]),cr.fetchall())) + result = [] + b = {} + for p_ids in uniq_ids: + cr.execute('select id from '+','.join(tables)+' where +'+order_by+' = %s'%(p_ids,)) + res2 = cr.fetchall() + for val in res2: + if int(p_ids) not in b: + b[int(p_ids)] = [val[0]] + else: + b[int(p_ids)].append(val[0]) + old_id = [] + for x in res: + if x[0] in old_id: + continue + temp = {'id':x[0],order_by:(x[0],uniq_order_by_res[x[0]]),'group_child':b[x[0]]} + for sum in float_int_fields: + temp[sum] = x[float_int_fields.index(sum)+1] + for field in fields.keys(): + if field not in temp: + temp[field] = False + old_id.append(x[0]) + result.append(temp) + return result + else: + query_fields = ','.join(fields.keys()) + result = [] + ids = ','.join(map(lambda x:str(x),ids)) + cr.execute('select id,' + query_fields+' from '+','.join(tables)+' where id in (%s)'%(ids)) + pos_orderby = fields.keys().index(order_by) + res1 = cr.fetchall() + if res1 and len(res1): + part = str(res1[0][pos_orderby+1]) + cr.execute('select id,name from %s where id = %s'%(fields[order_by]['relation'].replace('.','_'),part)) + partner = cr.fetchall()[0] + for val in res1: + temp = {'id':val[0],'group_child':[]} + for field in fields.keys(): + if field == order_by: + temp[field] = partner + continue + temp[field] = val[fields.keys().index(field)+1] + result.append(temp) + return result def _field_create(self, cr, context={}): cr.execute("SELECT id FROM ir_model WHERE model=%s", (self._name,)) @@ -2357,7 +2405,6 @@ class orm(orm_template): select = map(lambda x: isinstance(x,dict) and x['id'] or x, select) result = self._read_flat(cr, user, select, fields, context, load) - for r in result: for key, v in r.items(): if v == None: @@ -2386,6 +2433,8 @@ class orm(orm_template): context = {} if not ids: return [] + if len(ids) and type(ids[0])==tuple: + ids = list(set(map(lambda x:x[0],ids))) ids = map(lambda x:int(x), ids) if fields_to_read == None: fields_to_read = self._columns.keys() @@ -3201,8 +3250,6 @@ class orm(orm_template): ','.join(tables) +qu1 + limit_str + offset_str, qu2) res = cr.fetchall() return res[0][0] - - # execute the "main" query to fetch the ids we were searching for cr.execute('select %s.id from ' % self._table + ','.join(tables) +qu1+' order by '+order_by+limit_str+offset_str, qu2) res = cr.fetchall() return [x[0] for x in res] From d264461befd558669783e9a1df96ef068a84bb4e Mon Sep 17 00:00:00 2001 From: "nch@tinyerp.com" <> Date: Tue, 29 Dec 2009 18:24:07 +0530 Subject: [PATCH 03/23] [REF,IMP]:improved the read_group code bzr revid: nch@tinyerp.com-20091229125407-jt5fbvvhbcf0xhxv --- bin/osv/orm.py | 93 +++++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 47 deletions(-) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index b28b24406fc..e56487d42d2 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -358,11 +358,12 @@ class orm_template(object): qu1 = '' if order: self._check_qorder(order) + order_by = order or self._order float_int_fields = list(field_name for field_name,values in fields.items() if values['type'] in ('float','integer')) + sumof = ','.join(map(lambda field_name:'sum('+field_name+') as '+field_name+'',float_int_fields)) # filter fields in args to only get float and int - # sumof = ','.join([field_name for field_name,values in fields.items() if values['type'] in ('float','integer')]) # filter fields in args to only get float and int limit_str = limit and ' limit %d' % limit or '' offset_str = offset and ' offset %d' % offset or '' @@ -372,63 +373,61 @@ class orm_template(object): if d1: qu1 = qu1 and qu1+' and '+d1 or ' where '+d1 qu2 += d2 + + def get_fulname(ids,table): + + if ids and not type(ids) in (list,tuple) or len(ids) == 1: + cond = ' where id = %s'%(ids) + else: + cond = ' where id in %s'%(ids,) + qury = 'select id,name from ' + table + cond + cr.execute(qury) + return cr.fetchall() + if not ids: - # execute the "main" query to fetch the ids we were searching for - #cr.execute('select distinct('+order_by+'),'+self._table+'.id,'+sumof+' from ' + ','.join(tables) +qu1+' group by '+order_by +','+self._table+'.id'+limit_str+offset_str) - cr.execute('select distinct('+order_by+'),'+sumof+' from ' + ','.join(tables) +qu1+' group by '+order_by +limit_str+offset_str) - res = cr.fetchall() - uniq_ids = () - if fields[order_by]['type'] == 'many2one': - uniq_ids =tuple(set(map(lambda x:str(x[0]),res))) - if uniq_ids and len(uniq_ids) == 1: - cond = ' where id = %s'%(uniq_ids) - else: - cond = ' where id in %s'%(uniq_ids,) - qury = 'select name,id from ' + fields[order_by]['relation'].replace('.','_') + cond - cr.execute(qury) - uniq_order_by_res = dict(map(lambda x:(x[1],x[0]),cr.fetchall())) result = [] - b = {} - for p_ids in uniq_ids: - cr.execute('select id from '+','.join(tables)+' where +'+order_by+' = %s'%(p_ids,)) - res2 = cr.fetchall() - for val in res2: - if int(p_ids) not in b: - b[int(p_ids)] = [val[0]] + cr.execute('select distinct('+order_by+'),'+sumof+' from ' + ','.join(tables) +qu1+' group by '+order_by +limit_str+offset_str) + parent_res = cr.fetchall() + uniq_ids = tuple(map(lambda x:str(x[0]),parent_res)) + if len(uniq_ids): + uniq_order_by_res = get_fulname(uniq_ids,fields[order_by]['relation'].replace('.','_')) + uniq_order_by_res = dict(uniq_order_by_res) + child_ids_dict = {} + # get child ids + for parent_id in uniq_ids: + cr.execute('select id from '+','.join(tables)+' where +'+order_by+' = %s'%(parent_id,)) + child_ids = cr.fetchall() + for val in child_ids: + if int(parent_id) not in child_ids_dict: + child_ids_dict[int(parent_id)] = [val[0]] else: - b[int(p_ids)].append(val[0]) - old_id = [] - for x in res: - if x[0] in old_id: - continue - temp = {'id':x[0],order_by:(x[0],uniq_order_by_res[x[0]]),'group_child':b[x[0]]} + child_ids_dict[int(parent_id)].append(val[0]) + #create [{},{}] for parent ids i.e for group by field + for x in parent_res: + parent_val_dict = {'id':x[0],order_by:(x[0],uniq_order_by_res[x[0]]),'group_child':child_ids_dict[x[0]]} for sum in float_int_fields: - temp[sum] = x[float_int_fields.index(sum)+1] + parent_val_dict[sum] = x[float_int_fields.index(sum)+1] for field in fields.keys(): - if field not in temp: - temp[field] = False - old_id.append(x[0]) - result.append(temp) + if field not in parent_val_dict: + parent_val_dict[field] = False + result.append(parent_val_dict) return result else: - query_fields = ','.join(fields.keys()) + # process for getting child values for all fields in the view result = [] ids = ','.join(map(lambda x:str(x),ids)) - cr.execute('select id,' + query_fields+' from '+','.join(tables)+' where id in (%s)'%(ids)) - pos_orderby = fields.keys().index(order_by) - res1 = cr.fetchall() - if res1 and len(res1): - part = str(res1[0][pos_orderby+1]) - cr.execute('select id,name from %s where id = %s'%(fields[order_by]['relation'].replace('.','_'),part)) - partner = cr.fetchall()[0] - for val in res1: - temp = {'id':val[0],'group_child':[]} + cr.execute('select id,' + ','.join(fields.keys())+' from '+','.join(tables)+' where id in (%s)'%(ids)) + child_res = cr.fetchall() + for val in child_res: + child_dict = {'id':val[0],'group_child':[]} for field in fields.keys(): - if field == order_by: - temp[field] = partner + if fields[field]['type'] == 'many2one': + pos = fields.keys().index(field) + part = str(val[pos+1]) + child_dict[field] = get_fulname(part,fields[field]['relation'].replace('.','_'))[0] continue - temp[field] = val[fields.keys().index(field)+1] - result.append(temp) + child_dict[field] = val[fields.keys().index(field)+1] + result.append(child_dict) return result def _field_create(self, cr, context={}): From 5d9d5562a2ec32cc32664305ecdd508d12419262 Mon Sep 17 00:00:00 2001 From: "nch@tinyerp.com" <> Date: Tue, 29 Dec 2009 18:35:00 +0530 Subject: [PATCH 04/23] [ADD,FIX]:Group by customer and shop in sale order and a small bug in stock/product.py bzr revid: nch@tinyerp.com-20091229130500-b3crhavxmrkmni4q --- addons/sale/sale_view.xml | 52 +++++++++++++++++++++++++++++++++++++-- addons/stock/product.py | 2 ++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/addons/sale/sale_view.xml b/addons/sale/sale_view.xml index a7535336982..83c847a4ef2 100644 --- a/addons/sale/sale_view.xml +++ b/addons/sale/sale_view.xml @@ -131,7 +131,7 @@ on_change="product_id_change(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,product_uos,name,parent.partner_id, 'lang' in context and context['lang'], False, parent.date_order, product_packaging, parent.fiscal_position)" domain="[('product_id','=',product_id)]" groups="base.group_extended"/> - + @@ -264,6 +264,54 @@ + + + sale.order.gp.tree + sale.order + tree + + + + + + + + + + + + + + + Sale Order Group By Customer + ir.actions.act_window + sale.order + {'group_by':'partner_id'} + tree + form,graph + + + + + Sale Order Group By Shop + ir.actions.act_window + sale.order + {'group_by':'shop_id'} + tree + form,graph + + + + + + + All Sales Order ir.actions.act_window @@ -415,7 +463,7 @@ - + diff --git a/addons/stock/product.py b/addons/stock/product.py index 5c42cdbdab2..544cc1b2789 100644 --- a/addons/stock/product.py +++ b/addons/stock/product.py @@ -175,6 +175,8 @@ class product_product(osv.osv): } def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False): res = super(product_product,self).fields_view_get(cr, uid, view_id, view_type, context, toolbar=toolbar, submenu=submenu) + if context == None: + context = {} if ('location' in context) and context['location']: location_info = self.pool.get('stock.location').browse(cr, uid, context['location']) fields=res.get('fields',{}) From d65c7d8776505cccd921ca6239a62be47832a269 Mon Sep 17 00:00:00 2001 From: "nch@tinyerp.com" <> Date: Tue, 5 Jan 2010 14:15:30 +0530 Subject: [PATCH 05/23] [IMP]:read_group bzr revid: nch@tinyerp.com-20100105084530-zjc1nx1iyije91sa --- bin/osv/orm.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index e56487d42d2..afe516104d6 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -411,6 +411,7 @@ class orm_template(object): if field not in parent_val_dict: parent_val_dict[field] = False result.append(parent_val_dict) + print "returning.........",result return result else: # process for getting child values for all fields in the view @@ -2432,8 +2433,6 @@ class orm(orm_template): context = {} if not ids: return [] - if len(ids) and type(ids[0])==tuple: - ids = list(set(map(lambda x:x[0],ids))) ids = map(lambda x:int(x), ids) if fields_to_read == None: fields_to_read = self._columns.keys() From 83bcb89d40d1e1671ad465d208d37cb94ef25671 Mon Sep 17 00:00:00 2001 From: "nch@tinyerp.com" <> Date: Wed, 6 Jan 2010 18:57:48 +0530 Subject: [PATCH 06/23] [IMP]:improved the read_group method bzr revid: nch@tinyerp.com-20100106132748-o75tot3byxghk6t2 --- bin/osv/orm.py | 108 +++++++++++++++++-------------------------------- 1 file changed, 36 insertions(+), 72 deletions(-) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index afe516104d6..aa6803bf622 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -348,88 +348,52 @@ class orm_template(object): CONCURRENCY_CHECK_FIELD = '__last_update' - def read_group(self, cr, user, ids, domain, fields, order, offset=0, limit=None, context=None): + def read_group(self, cr, user, ids, fields, groupby, context=None): context = context or {} - # compute the where, order by, limit and offset clauses - (qu1, qu2, tables) = self._where_calc(cr, user, domain, context=context) - if len(qu1): - qu1 = ' where '+string.join(qu1, ' and ') - else: - qu1 = '' - if order: - self._check_qorder(order) - - order_by = order or self._order - - float_int_fields = list(field_name for field_name,values in fields.items() if values['type'] in ('float','integer')) - - sumof = ','.join(map(lambda field_name:'sum('+field_name+') as '+field_name+'',float_int_fields)) # filter fields in args to only get float and int - - limit_str = limit and ' limit %d' % limit or '' - offset_str = offset and ' offset %d' % offset or '' + result = [] + if not ids:return + qu1 = ' where id in (' + ','.join([str(id) for id in ids]) + ')' + qu2 = '' # construct a clause for the rules : d1, d2 = self.pool.get('ir.rule').domain_get(cr, user, self._name) if d1: qu1 = qu1 and qu1+' and '+d1 or ' where '+d1 qu2 += d2 - def get_fulname(ids,table): + group_by_table = fields[groupby]['relation'].replace('.','_') - if ids and not type(ids) in (list,tuple) or len(ids) == 1: - cond = ' where id = %s'%(ids) - else: - cond = ' where id in %s'%(ids,) - qury = 'select id,name from ' + table + cond - cr.execute(qury) - return cr.fetchall() + float_int_fields = list(field_name for field_name,values in fields.items() if values['type'] in ('float','integer')) + sumof = ','.join(map(lambda field_name:'sum('+field_name+') as '+field_name+'',float_int_fields)) - if not ids: - result = [] - cr.execute('select distinct('+order_by+'),'+sumof+' from ' + ','.join(tables) +qu1+' group by '+order_by +limit_str+offset_str) - parent_res = cr.fetchall() - uniq_ids = tuple(map(lambda x:str(x[0]),parent_res)) - if len(uniq_ids): - uniq_order_by_res = get_fulname(uniq_ids,fields[order_by]['relation'].replace('.','_')) - uniq_order_by_res = dict(uniq_order_by_res) - child_ids_dict = {} - # get child ids - for parent_id in uniq_ids: - cr.execute('select id from '+','.join(tables)+' where +'+order_by+' = %s'%(parent_id,)) - child_ids = cr.fetchall() - for val in child_ids: - if int(parent_id) not in child_ids_dict: - child_ids_dict[int(parent_id)] = [val[0]] - else: - child_ids_dict[int(parent_id)].append(val[0]) - #create [{},{}] for parent ids i.e for group by field - for x in parent_res: - parent_val_dict = {'id':x[0],order_by:(x[0],uniq_order_by_res[x[0]]),'group_child':child_ids_dict[x[0]]} - for sum in float_int_fields: - parent_val_dict[sum] = x[float_int_fields.index(sum)+1] - for field in fields.keys(): - if field not in parent_val_dict: - parent_val_dict[field] = False - result.append(parent_val_dict) - print "returning.........",result - return result - else: - # process for getting child values for all fields in the view - result = [] - ids = ','.join(map(lambda x:str(x),ids)) - cr.execute('select id,' + ','.join(fields.keys())+' from '+','.join(tables)+' where id in (%s)'%(ids)) - child_res = cr.fetchall() - for val in child_res: - child_dict = {'id':val[0],'group_child':[]} - for field in fields.keys(): - if fields[field]['type'] == 'many2one': - pos = fields.keys().index(field) - part = str(val[pos+1]) - child_dict[field] = get_fulname(part,fields[field]['relation'].replace('.','_'))[0] - continue - child_dict[field] = val[fields.keys().index(field)+1] - result.append(child_dict) - return result + cr.execute('select '+groupby+','+sumof+' from ' + self._table +qu1+' group by '+groupby+qu2) + parent_res = cr.fetchall() + groupby_ids = map(lambda x:x[0],parent_res) + groupby_name = dict(self.pool.get(fields[groupby]['relation']).name_get(cr,user,groupby_ids,context)) + + child_ids_dict = {} + # get child ids + for parent_id in groupby_ids: + chqu1 =' where id in (' + ','.join([str(id) for id in ids]) + ') and ' + cr.execute('select id from '+self._table+chqu1 +groupby+' = %s'%(parent_id,)) + child_ids = cr.fetchall() + print child_ids + for val in child_ids: + if parent_id not in child_ids_dict: + child_ids_dict[parent_id] = [val[0]] + else: + child_ids_dict[parent_id].append(val[0]) + #create [{},{}] for parent ids i.e for group by field + for x in parent_res: + parent_val_dict = {'id':x[0],groupby:(x[0],groupby_name[x[0]]),'group_child':child_ids_dict[x[0]]} + for sum in float_int_fields: + parent_val_dict[sum] = x[float_int_fields.index(sum)+1] + for field in fields.keys(): + if field not in parent_val_dict: + parent_val_dict[field] = False + result.append(parent_val_dict) + print "returning.........",result + return result def _field_create(self, cr, context={}): cr.execute("SELECT id FROM ir_model WHERE model=%s", (self._name,)) From d904c93dd70aa3d67b69cd404932845e8d952e20 Mon Sep 17 00:00:00 2001 From: "nch@tinyerp.com" <> Date: Fri, 8 Jan 2010 17:56:40 +0530 Subject: [PATCH 07/23] [FIX]:passed group header id as None bzr revid: nch@tinyerp.com-20100108122640-kiyc8d2a3wyvw9ox --- bin/osv/orm.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index aa6803bf622..fe39fca616b 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -377,7 +377,6 @@ class orm_template(object): chqu1 =' where id in (' + ','.join([str(id) for id in ids]) + ') and ' cr.execute('select id from '+self._table+chqu1 +groupby+' = %s'%(parent_id,)) child_ids = cr.fetchall() - print child_ids for val in child_ids: if parent_id not in child_ids_dict: child_ids_dict[parent_id] = [val[0]] @@ -385,7 +384,7 @@ class orm_template(object): child_ids_dict[parent_id].append(val[0]) #create [{},{}] for parent ids i.e for group by field for x in parent_res: - parent_val_dict = {'id':x[0],groupby:(x[0],groupby_name[x[0]]),'group_child':child_ids_dict[x[0]]} + parent_val_dict = {'id':None,groupby:(x[0],groupby_name[x[0]]),'group_child':child_ids_dict[x[0]]} for sum in float_int_fields: parent_val_dict[sum] = x[float_int_fields.index(sum)+1] for field in fields.keys(): From ca8aca1fa38ddcba62e8c7345f2ad302f9873e83 Mon Sep 17 00:00:00 2001 From: "nch@tinyerp.com" <> Date: Sat, 9 Jan 2010 12:14:44 +0530 Subject: [PATCH 08/23] [IMP]:groupby on date field bzr revid: nch@tinyerp.com-20100109064444-uqpmnowdk282pn0a --- bin/osv/orm.py | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index fe39fca616b..159d083604e 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -361,21 +361,23 @@ class orm_template(object): qu1 = qu1 and qu1+' and '+d1 or ' where '+d1 qu2 += d2 - group_by_table = fields[groupby]['relation'].replace('.','_') - float_int_fields = list(field_name for field_name,values in fields.items() if values['type'] in ('float','integer')) sumof = ','.join(map(lambda field_name:'sum('+field_name+') as '+field_name+'',float_int_fields)) - cr.execute('select '+groupby+','+sumof+' from ' + self._table +qu1+' group by '+groupby+qu2) parent_res = cr.fetchall() groupby_ids = map(lambda x:x[0],parent_res) - groupby_name = dict(self.pool.get(fields[groupby]['relation']).name_get(cr,user,groupby_ids,context)) + groupby_name = {} + if fields[groupby]['type'] == 'many2one': + groupby_name = dict(self.pool.get(fields[groupby]['relation']).name_get(cr,user,groupby_ids,context)) + chqu1 =' where id in (' + ','.join([str(id) for id in ids]) + ') and ' + else: + chqu1 =' where ' child_ids_dict = {} # get child ids + for parent_id in groupby_ids: - chqu1 =' where id in (' + ','.join([str(id) for id in ids]) + ') and ' - cr.execute('select id from '+self._table+chqu1 +groupby+' = %s'%(parent_id,)) + cr.execute('select id from '+self._table+chqu1 +groupby+" = '%s'"%(parent_id,)) child_ids = cr.fetchall() for val in child_ids: if parent_id not in child_ids_dict: @@ -383,15 +385,30 @@ class orm_template(object): else: child_ids_dict[parent_id].append(val[0]) #create [{},{}] for parent ids i.e for group by field + import datetime + curr_date = datetime.date.today() + yesterday = (curr_date - datetime.timedelta(days=1)).strftime('%Y-%m-%d') + lastweek = (curr_date + datetime.timedelta(weeks=-1)).strftime('%Y-%m-%d') + date_format = 'Old' for x in parent_res: - parent_val_dict = {'id':None,groupby:(x[0],groupby_name[x[0]]),'group_child':child_ids_dict[x[0]]} + if fields[groupby]['type'] in ('date','datetime'): + if x[0] == curr_date.strftime('%Y-%m-%d'): + date_format = 'Today' + elif x[0] == yesterday: + date_format = 'Yesterday' + elif (x[0] < yesterday) and (x[0] >= lastweek): + date_format = 'LastWeek' + val = date_format + else: + val = (x[0],groupby_name[x[0]]) + + parent_val_dict = {'id':None,groupby:val,'group_child':child_ids_dict[x[0]]} for sum in float_int_fields: parent_val_dict[sum] = x[float_int_fields.index(sum)+1] for field in fields.keys(): if field not in parent_val_dict: parent_val_dict[field] = False result.append(parent_val_dict) - print "returning.........",result return result def _field_create(self, cr, context={}): From acac978830f9b953197438632d4df9b84d7b7cc1 Mon Sep 17 00:00:00 2001 From: "nch@tinyerp.com" <> Date: Mon, 11 Jan 2010 16:00:11 +0530 Subject: [PATCH 09/23] [IMP]:read group for date fields bzr revid: nch@tinyerp.com-20100111103011-t6r3urfx50zghfro --- bin/osv/orm.py | 80 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 29 deletions(-) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index 159d083604e..7da3e17a573 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -349,10 +349,11 @@ class orm_template(object): CONCURRENCY_CHECK_FIELD = '__last_update' def read_group(self, cr, user, ids, fields, groupby, context=None): + print ":::::::::::::",fields[groupby],groupby context = context or {} - result = [] if not ids:return - + if fields[groupby]['type'] not in ('many2one,date,datetime'): + raise Exception(_("Type Not supported for Group By: %s :Only many2one,date and datetime are supported ") %(fields[groupby]['type'],)) qu1 = ' where id in (' + ','.join([str(id) for id in ids]) + ')' qu2 = '' # construct a clause for the rules : @@ -367,15 +368,13 @@ class orm_template(object): parent_res = cr.fetchall() groupby_ids = map(lambda x:x[0],parent_res) groupby_name = {} + child_ids_dict = {} + if fields[groupby]['type'] == 'many2one': groupby_name = dict(self.pool.get(fields[groupby]['relation']).name_get(cr,user,groupby_ids,context)) - chqu1 =' where id in (' + ','.join([str(id) for id in ids]) + ') and ' - else: - chqu1 =' where ' + chqu1 =' where id in (' + ','.join([str(id) for id in ids]) + ') and ' - child_ids_dict = {} # get child ids - for parent_id in groupby_ids: cr.execute('select id from '+self._table+chqu1 +groupby+" = '%s'"%(parent_id,)) child_ids = cr.fetchall() @@ -385,31 +384,54 @@ class orm_template(object): else: child_ids_dict[parent_id].append(val[0]) #create [{},{}] for parent ids i.e for group by field - import datetime - curr_date = datetime.date.today() - yesterday = (curr_date - datetime.timedelta(days=1)).strftime('%Y-%m-%d') - lastweek = (curr_date + datetime.timedelta(weeks=-1)).strftime('%Y-%m-%d') - date_format = 'Old' - for x in parent_res: - if fields[groupby]['type'] in ('date','datetime'): - if x[0] == curr_date.strftime('%Y-%m-%d'): + result = [] + if fields[groupby]['type'] in ('date','datetime'): + curr_date = datetime.date.today() + yesterday = (curr_date - datetime.timedelta(days=1)).strftime('%Y-%m-%d') + lastweek = (curr_date + datetime.timedelta(weeks=-1)).strftime('%Y-%m-%d') + date_result = {'Today':{'group_child':[]},'Yesterday':{'group_child':[]}, + 'LastWeek':{'group_child':[]},'Old':{'group_child':[]}} + for x in parent_res: + db_date = x[0][:10] + if db_date == curr_date.strftime('%Y-%m-%d'): date_format = 'Today' - elif x[0] == yesterday: + elif db_date == yesterday: date_format = 'Yesterday' - elif (x[0] < yesterday) and (x[0] >= lastweek): + elif (db_date < yesterday) and (db_date >= lastweek): date_format = 'LastWeek' - val = date_format - else: - val = (x[0],groupby_name[x[0]]) - - parent_val_dict = {'id':None,groupby:val,'group_child':child_ids_dict[x[0]]} - for sum in float_int_fields: - parent_val_dict[sum] = x[float_int_fields.index(sum)+1] - for field in fields.keys(): - if field not in parent_val_dict: - parent_val_dict[field] = False - result.append(parent_val_dict) - return result + else: + date_format = 'Old' + date_result[date_format].update({'id':None,groupby:date_format}) + date_result[date_format]['group_child'] += child_ids_dict[x[0]] + for sum in float_int_fields: + if sum not in date_result[date_format]: + date_result[date_format][sum] = x[float_int_fields.index(sum)+1] + if float_int_fields.index(sum): + date_result[date_format][sum] += x[float_int_fields.index(sum)+1] + for key,val in date_result.items(): + if len(date_result[key]) == 1: + del date_result[key] + continue + for field in fields.keys(): + if field not in val: + val[field] = False + if key in ('Today','Yesterday') and len(result): + result.insert(0,val) + else: + result.insert(-1,val) + print result + return result + else: + for x in parent_res: + parent_val_dict = {'id':None,groupby:(x[0],groupby_name[x[0]]),'group_child':child_ids_dict[x[0]]} + for sum in float_int_fields: + parent_val_dict[sum] = x[float_int_fields.index(sum)+1] + for field in fields.keys(): + if field not in parent_val_dict: + parent_val_dict[field] = False + result.append(parent_val_dict) + print result + return result def _field_create(self, cr, context={}): cr.execute("SELECT id FROM ir_model WHERE model=%s", (self._name,)) From 926d2b9de8a089460b4d8c2693cc08db7cf5eba9 Mon Sep 17 00:00:00 2001 From: "Rvo (Open ERP)" Date: Tue, 12 Jan 2010 14:50:13 +0530 Subject: [PATCH 10/23] Changes in project/project.py and hr/hr_view.xml bzr revid: rvo@tinyerp.co.in-20100112092013-g0nq8vhxssg1ha1n --- addons/hr/hr_view.xml | 9 ++++++- addons/project/project.py | 53 ++++++++------------------------------- 2 files changed, 19 insertions(+), 43 deletions(-) diff --git a/addons/hr/hr_view.xml b/addons/hr/hr_view.xml index dd8a2d3a3fd..45d55d8b785 100644 --- a/addons/hr/hr_view.xml +++ b/addons/hr/hr_view.xml @@ -155,7 +155,7 @@ - + + + + 38 Hours/Week + + + + Fabien Pinckaers + + + + + + + Monday morning + 0 + 08 + 12 + + + + Monday evening + 0 + 13 + 18 + + + + Tuesday morning + 1 + 08 + 12 + + + + Tuesday evening + 1 + 13 + 18 + + + + Wednesday morning + 2 + 08 + 12 + + + + Wednesday evening + 2 + 13 + 18 + + + + Thursday morning + 3 + 08 + 12 + + + + Thursday evening + 13 + 18 + 3 + + + + Friday morning + 4 + 08 + 12 + + + + Friday evening + 4 + 13 + 18 + + + + + diff --git a/addons/resource/hr_department.py b/addons/resource/hr_department.py new file mode 100755 index 00000000000..907bc55a435 --- /dev/null +++ b/addons/resource/hr_department.py @@ -0,0 +1,153 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2009 Tiny SPRL (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from osv import fields,osv +import tools + +class hr_department(osv.osv): + _name = "hr.department" + _columns = { + 'name': fields.char('Department Name', size=64, required=True), + 'company_id': fields.many2one('res.company', 'Company', select=True, required=True), + 'parent_id': fields.many2one('hr.department', 'Parent Department', select=True), + 'child_ids': fields.one2many('hr.department', 'parent_id', 'Child Departments'), + 'note': fields.text('Note'), + 'manager_id': fields.many2one('res.users', 'Manager', required=True), + 'member_ids': fields.many2many('res.users', 'hr_department_user_rel', 'department_id', 'user_id', 'Members'), + } + def _get_members(self,cr, uid, context={}): + mids = self.search(cr, uid, [('manager_id','=',uid)]) + result = {uid:1} + for m in self.browse(cr, uid, mids, context): + for user in m.member_ids: + result[user.id] = 1 + return result.keys() + def _check_recursion(self, cr, uid, ids): + level = 100 + while len(ids): + cr.execute('select distinct parent_id from hr_department where id in ('+','.join(map(str, ids))+')') + ids = filter(None, map(lambda x:x[0], cr.fetchall())) + if not level: + return False + level -= 1 + return True + + _constraints = [ + (_check_recursion, 'Error! You can not create recursive departments.', ['parent_id']) + ] + +hr_department() + + +class ir_action_window(osv.osv): + _inherit = 'ir.actions.act_window' + + def read(self, cr, uid, ids, fields=None, context=None, + load='_classic_read'): + select = ids + if isinstance(ids, (int, long)): + select = [ids] + res = super(ir_action_window, self).read(cr, uid, select, fields=fields, + context=context, load=load) + for r in res: + mystring = 'department_users_get()' + if mystring in (r.get('domain', '[]') or ''): + r['domain'] = r['domain'].replace(mystring, str( + self.pool.get('hr.department')._get_members(cr, uid))) + if isinstance(ids, (int, long)): + if res: + return res[0] + else: + return False + return res + +ir_action_window() + +class res_users(osv.osv): + _inherit = 'res.users' + _description = 'res.users' + + def _parent_compute(self, cr, uid, ids, name, args, context={}): + result = {} + obj_dept = self.pool.get('hr.department') + for user_id in ids: + ids_dept = obj_dept.search(cr, uid, [('member_ids', 'in', [user_id])]) + parent_ids = [] + if ids_dept: + data_dept = obj_dept.read(cr, uid, ids_dept, ['manager_id']) + parent_ids = map(lambda x: x['manager_id'][0], data_dept) + result[user_id] = parent_ids + return result + + def _parent_search(self, cr, uid, obj, name, args): + parent = [] + for arg in args: + if arg[0] == 'parent_id': + parent = arg[2] + child_ids = self._child_compute(cr, uid, parent,name, args, {}) + if not child_ids: + return [('id', 'in', [0])] + return [('id', 'in', child_ids.get(uid,[]))] + + def _child_compute(self, cr, uid, ids, name, args, context={}): + obj_dept = self.pool.get('hr.department') + obj_user = self.pool.get('res.users') + result = {} + for manager_id in ids: + child_ids = [] + mgnt_dept_ids = obj_dept.search(cr, uid, [('manager_id', '=', manager_id)]) + ids_dept = obj_dept.search(cr, uid, [('id', 'child_of', mgnt_dept_ids)]) + if ids_dept: + data_dept = obj_dept.read(cr, uid, ids_dept, ['member_ids']) + childs = map(lambda x: x['member_ids'], data_dept) + childs = tools.flatten(childs) + childs = obj_user.search(cr, uid, [('id','in',childs),('active','=',True)]) + if manager_id in childs: + childs.remove(manager_id) + + child_ids.extend(tools.flatten(childs)) + set = {} + map(set.__setitem__, child_ids, []) + child_ids = set.keys() + else: + child_ids = [] + result[manager_id] = child_ids + return result + + def _child_search(self, cr, uid, obj, name, args): + parent = [] + for arg in args: + if arg[0] == 'child_ids': + parent = arg[2] + child_ids = self._child_compute(cr, uid, parent,name, args, {}) + if not child_ids: + return [('id', 'in', [0])] + return [('id', 'in', child_ids.get(uid,[]))] + + _columns = { + 'parent_id': fields.function(_parent_compute, relation='res.users',fnct_search=_parent_search, method=True, string="Managers", type='many2many'), + 'child_ids': fields.function(_child_compute, relation='res.users', fnct_search=_child_search,method=True, string="Subordinates", type='many2many'), + } + + +res_users() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/addons/resource/hr_department_demo.xml b/addons/resource/hr_department_demo.xml new file mode 100755 index 00000000000..c7ea68f1dc3 --- /dev/null +++ b/addons/resource/hr_department_demo.xml @@ -0,0 +1,63 @@ + + + + + + Management + + + + + Administration + + + + + + + Technical department + + + + + + + IT + + + + + + + Marketing + + + + + + + Sales + + + + + + + Sales Europe + + + + + + + Sales America + + + + + + + + + + diff --git a/addons/resource/hr_department_view.xml b/addons/resource/hr_department_view.xml new file mode 100755 index 00000000000..fe65d988237 --- /dev/null +++ b/addons/resource/hr_department_view.xml @@ -0,0 +1,79 @@ + + + + + + + hr.department.form + hr.department + form + +
+ + + + + + + + + + + + + + +
+ + hr.department.tree + hr.department + tree + child_ids + + + + + + + + + + Departments + hr.department + tree + [('parent_id','=',False)] + + + + + Departments + hr.department + form + + + + + + + res.users.form + form + res.users + + + + + + + + + + + + + +
+
diff --git a/addons/resource/hr_view.xml b/addons/resource/hr_view.xml new file mode 100755 index 00000000000..abf3c5f023f --- /dev/null +++ b/addons/resource/hr_view.xml @@ -0,0 +1,296 @@ + + + + + + + + + + hr.employee.form + hr.employee + form + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + hr.employee.tree + hr.employee + tree + child_ids + + + + + + + + + + + + Employees Structure + hr.employee + tree + tree,form + + [('parent_id','=',False)] + + + + Employees + hr.employee + form + tree,form + + + + + + + + All Employees + hr.employee + form + tree,form + [] + + + + + + hr.employee.tree + hr.employee + tree + child_ids + + + + + + + + + + + Employee Hierarchy + ir.actions.act_window + hr.employee + [('id','in',active_ids)] + tree + + + + + + + Employees Hierarchy + + + + + + + + + resource.calendar.form + resource.calendar + form + +
+ + + + + + +
+ + Working Time Categories + resource.calendar + form + + + + + + resource.calendar.week.tree + resource.calendar.week + tree + + + + + + + + + + + resource.calendar.week.form + resource.calendar.week + form + +
+ + + + + + + +
+ + + + + hr.employee.category.form + hr.employee.category + form + +
+ + + + +
+ + hr.employee.category.list + hr.employee.category + tree + + + + + + + + + + hr.employee.category.tree + hr.employee.category + tree + child_ids + + + + + + + + Categories of Employee + hr.employee.category + form + tree,form + + + + + Categories structure + hr.employee.category + tree + + [('parent_id','=',False)] + + + + Employees + ir.actions.act_window + hr.employee + form + tree,form + [('category_id','child_of',[active_id])] + {'category_id':active_id} + + + + + + Employees by Categories + + + + + + +
+
diff --git a/addons/resource/resource.py b/addons/resource/resource.py new file mode 100755 index 00000000000..2d225527f0e --- /dev/null +++ b/addons/resource/resource.py @@ -0,0 +1,195 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2009 Tiny SPRL (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## +import mx.DateTime +import time +import math +from osv import fields, osv +from tools.translate import _ + +class resource_calendar(osv.osv): + _name = "resource.calendar" + _description = "Resource Calendar" + _columns = { + 'name' : fields.char("Name", size=64, required=True), + 'company_id' : fields.many2one('res.company', 'Company', required=True), + 'week_id' : fields.one2many('resource.calendar.week', 'calendar_id', 'Working Time'), + 'manager' : fields.many2one('res.users', 'Workgroup manager'), + } + _defaults = { + 'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'resource.calendar', c) + } + def interval_min_get(self, cr, uid, id, dt_from, hours , resource=0): + dt_leave = [] + if not id: + return [(dt_from-mx.DateTime.RelativeDateTime(hours=int(hours)*3), dt_from)] + if resource: + resource_leave_ids = self.pool.get('resource.calendar.leaves').search(cr,uid,[('resource_id','=',resource)]) + if resource_leave_ids: + res_leaves = self.pool.get('resource.calendar.leaves').read(cr,uid,resource_leave_ids,['date_from','date_to']) + print 'Leave Details',res_leaves + for i in range(len(res_leaves)): + dtf = mx.DateTime.strptime(res_leaves[i]['date_from'],'%Y-%m-%d %H:%M:%S') + dtt = mx.DateTime.strptime(res_leaves[i]['date_to'],'%Y-%m-%d %H:%M:%S') + leave_days = ((dtt - dtf).days) + 1 + print 'No Of Leaves:::::::::',int(leave_days) + for x in range(int(leave_days)): + dt_leave.append((dtf + mx.DateTime.RelativeDateTime(days=x)).strftime('%Y-%m-%d')) + dt_leave.sort() + print 'Sorted Leave Dates::::',dt_leave + todo = hours + cycle = 0 + result = [] + maxrecur = 100 + current_hour = dt_from.hour + while (todo>0) and maxrecur: + cr.execute("select hour_from,hour_to from resource_calendar_week where dayofweek='%s' and calendar_id=%s order by hour_from", (dt_from.day_of_week,id)) + for (hour_from,hour_to) in cr.fetchall(): + if (hour_to>current_hour) and (todo>0): + m = max(hour_from, current_hour) + if (hour_to-m)>todo: + hour_to = m+todo + d1 = mx.DateTime.DateTime(dt_from.year,dt_from.month,dt_from.day,int(math.floor(m)),int((m%1) * 60)) + d2 = mx.DateTime.DateTime(dt_from.year,dt_from.month,dt_from.day,int(math.floor(hour_to)),int((hour_to%1) * 60)) + dt1 = d1.strftime('%Y-%m-%d') + dt2 = d2.strftime('%Y-%m-%d') + print 'Date 1',dt1 + print 'Date 2',dt2 + for i in range(len(dt_leave)): + if dt1 == dt_leave[i]: + print 'Leave::::::::' + dt_from += mx.DateTime.RelativeDateTime(days=1) + d1 = mx.DateTime.DateTime(dt_from.year,dt_from.month,dt_from.day,int(math.floor(m)),int((m%1) * 60)) + d2 = mx.DateTime.DateTime(dt_from.year,dt_from.month,dt_from.day,int(math.floor(hour_to)),int((hour_to%1) * 60)) + dt1 = d1.strftime('%Y-%m-%d') + dt2 = d2.strftime('%Y-%m-%d') + result.append((d1, d2)) + current_hour = hour_to + todo -= (hour_to - m) + dt_from += mx.DateTime.RelativeDateTime(days=1) + current_hour = 0 + maxrecur -= 1 + return result + + def interval_get(self, cr, uid, id, dt_from, hours, resource=0, byday=True): + dt_leave = [] + if not id: + return [(dt_from,dt_from+mx.DateTime.RelativeDateTime(hours=int(hours)*3))] + if resource: + resource_leave_ids = self.pool.get('resource.calendar.leaves').search(cr,uid,[('resource_id','=',resource)]) + if resource_leave_ids: + res_leaves = self.pool.get('resource.calendar.leaves').read(cr,uid,resource_leave_ids,['date_from','date_to']) + print 'Leave Details',res_leaves + for i in range(len(res_leaves)): + dtf = mx.DateTime.strptime(res_leaves[i]['date_from'],'%Y-%m-%d %H:%M:%S') + dtt = mx.DateTime.strptime(res_leaves[i]['date_to'],'%Y-%m-%d %H:%M:%S') + no = dtt - dtf + leave_days = no.days + 1 + print 'No Of Leaves:::::::::',int(leave_days) + for x in range(int(leave_days)): + dt_leave.append((dtf + mx.DateTime.RelativeDateTime(days=x)).strftime('%Y-%m-%d')) + dt_leave.sort() + print 'Sorted Leave Dates::::',dt_leave + todo = hours + cycle = 0 + result = [] + maxrecur = 100 + current_hour = dt_from.hour + while (todo>0) and maxrecur: + cr.execute("select hour_from,hour_to from resource_calendar_week where dayofweek='%s' and calendar_id=%s order by hour_from", (dt_from.day_of_week,id)) + for (hour_from,hour_to) in cr.fetchall(): + if (hour_to>current_hour) and (todo>0): + m = max(hour_from, current_hour) + if (hour_to-m)>todo: + hour_to = m+todo + d1 = mx.DateTime.DateTime(dt_from.year,dt_from.month,dt_from.day,int(math.floor(m)),int((m%1) * 60)) + d2 = mx.DateTime.DateTime(dt_from.year,dt_from.month,dt_from.day,int(math.floor(hour_to)),int((hour_to%1) * 60)) + dt1 = d1.strftime('%Y-%m-%d') + dt2 = d2.strftime('%Y-%m-%d') + print 'Date 1',dt1 + print 'Date 2',dt2 + for i in range(len(dt_leave)): + if dt1 == dt_leave[i]: + print 'Leave::::::::' + dt_from += mx.DateTime.RelativeDateTime(days=1) + d1 = mx.DateTime.DateTime(dt_from.year,dt_from.month,dt_from.day,int(math.floor(m)),int((m%1) * 60)) + d2 = mx.DateTime.DateTime(dt_from.year,dt_from.month,dt_from.day,int(math.floor(hour_to)),int((hour_to%1) * 60)) + dt1 = d1.strftime('%Y-%m-%d') + dt2 = d2.strftime('%Y-%m-%d') + result.append((d1, d2)) + current_hour = hour_to + todo -= (hour_to - m) + dt_from += mx.DateTime.RelativeDateTime(days=1) + current_hour = 0 + maxrecur -= 1 + return result + +resource_calendar() + +class resource_calendar_week(osv.osv): + _name = "resource.calendar.week" + _description = "Work Detail" + _columns = { + 'name' : fields.char("Name", size=64, required=True), + 'dayofweek': fields.selection([('0','Monday'),('1','Tuesday'),('2','Wednesday'),('3','Thursday'),('4','Friday'),('5','Saturday'),('6','Sunday')], 'Day of week'), + 'date_from' : fields.date('Starting date'), + 'hour_from' : fields.float('Work from', size=8, required=True), + 'hour_to' : fields.float("Work to", size=8, required=True), + 'calendar_id' : fields.many2one("resource.calendar", "Resource's Calendar", required=True), + } + _order = 'dayofweek, hour_from' +resource_calendar_week() + +class resource_resource(osv.osv): + _name = "resource.resource" + _description = "Resource Detail" + _columns = { + 'name' : fields.char("Name", size=64, required=True), + 'code': fields.char('Code', size=16), + 'active' : fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the resource record without removing it."), + 'company_id' : fields.many2one('res.company', 'Company', required=True), + 'resource_type': fields.selection([('user','Human'),('material','Material')], 'Resource Type', required=True), + 'user_id' : fields.many2one('res.users', 'User'), + 'time_efficiency' : fields.float('Efficiency factor', size=8, help="This field depict the efficency of the ressource to complete tasks. e.g ressource 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 efficency of 200%, then his load will only be 50%."), + 'calendar_id' : fields.many2one("resource.calendar", "Working time", required=True, help="Define the schedule of resource"), + } + _defaults = { + 'resource_type' : lambda *a: 'user', + 'time_efficiency' : lambda *a: 1, + 'active' : lambda *a: True, + 'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'resource.resource', c) + } +resource_resource() + +class resource_calendar_leaves(osv.osv): + _name = "resource.calendar.leaves" + _description = "Leave Detail" + _columns = { + 'name' : fields.char("Name", size=64), + 'company_id' : fields.related('calendar_id','company_id',type='many2one',relation='res.company',string="Company",required=True), + #'company_id':fields.many2one('res.company', 'Company', required=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"), + + } +resource_calendar_leaves() +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/resource/resource_view.xml b/addons/resource/resource_view.xml new file mode 100755 index 00000000000..80d0650e0c8 --- /dev/null +++ b/addons/resource/resource_view.xml @@ -0,0 +1,174 @@ + + + + + + + + + + resource.calendar.form + resource.calendar + form + +
+ + + + + + + +
+ + Resource Calendar + resource.calendar + form + + + + + + resource.calendar.week.tree + resource.calendar.week + tree + + + + + + + + + + + resource.calendar.week.form + resource.calendar.week + form + +
+ + + + + + + +
+ + + resource.calendar.leaves.calendar + resource.calendar.leaves + calendar + + + + + + + + + + + + + + + + resource.resource.form + resource.resource + form + +
+ + + + + + + + + +
+ + resource.resource.tree + resource.resource + tree + + + + + + + + + + + + + Resources + resource.resource + tree,form + + + + + resource.calendar.leaves.form + resource.calendar.leaves + form + +
+ + + + + + + + +
+ + resource.calendar.leaves.tree + resource.calendar.leaves + tree + + + + + + + + + + + + + Leaves + resource.calendar.leaves + tree,form,calendar + + + + +
+
From ebf3b965270287c284eebcf230181952a213ef97 Mon Sep 17 00:00:00 2001 From: "Rvo (Open ERP)" Date: Tue, 12 Jan 2010 18:15:02 +0530 Subject: [PATCH 13/23] [ADD]:added module project_long_term bzr revid: rvo@tinyerp.co.in-20100112124502-k2adb24jmfixtngm --- addons/project_long_term/__init__.py | 25 ++ addons/project_long_term/__terp__.py | 42 +++ addons/project_long_term/project.py | 119 +++++++++ addons/project_long_term/project_data.xml | 16 ++ .../project_data_scheduler.xml | 23 ++ addons/project_long_term/project_demo.xml | 252 ++++++++++++++++++ addons/project_long_term/project_report.xml | 8 + addons/project_long_term/project_view.xml | 101 +++++++ addons/project_long_term/project_wizard.xml | 8 + 9 files changed, 594 insertions(+) create mode 100644 addons/project_long_term/__init__.py create mode 100644 addons/project_long_term/__terp__.py create mode 100644 addons/project_long_term/project.py create mode 100644 addons/project_long_term/project_data.xml create mode 100644 addons/project_long_term/project_data_scheduler.xml create mode 100644 addons/project_long_term/project_demo.xml create mode 100644 addons/project_long_term/project_report.xml create mode 100644 addons/project_long_term/project_view.xml create mode 100644 addons/project_long_term/project_wizard.xml diff --git a/addons/project_long_term/__init__.py b/addons/project_long_term/__init__.py new file mode 100644 index 00000000000..33adeb520b9 --- /dev/null +++ b/addons/project_long_term/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2009 Tiny SPRL (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +import project + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + diff --git a/addons/project_long_term/__terp__.py b/addons/project_long_term/__terp__.py new file mode 100644 index 00000000000..1b5dfa348ad --- /dev/null +++ b/addons/project_long_term/__terp__.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2009 Tiny SPRL (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +{ + "name" : "Long Term Project Management", + "version": "1.1", + "author" : "Tiny", + "website" : "http://www.openerp.com", + "category" : "Generic Modules/Projects & Services", + "depends" : ["project"], + "description": """Long Term Project management module that track planning, scheduling, resources allocation. + """, + "init_xml" : [], + "demo_xml" : [#"project_demo.xml" +], + "update_xml": [ + "project_view.xml", + ], + 'installable': True, + 'active': False, + 'certificate': None, +} +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/project_long_term/project.py b/addons/project_long_term/project.py new file mode 100644 index 00000000000..f04e18babfd --- /dev/null +++ b/addons/project_long_term/project.py @@ -0,0 +1,119 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2009 Tiny SPRL (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from lxml import etree +from mx import DateTime +from mx.DateTime import now +import time +from tools.translate import _ + +from osv import fields, osv +from tools.translate import _ + +class project_phase(osv.osv): + _name = "project.phase" + _description = "Project Phase" + + def _check_recursion(self,cr,uid,ids): + level = 100 + while len(ids): + cr.execute('select distinct next_phase_id from project_phase_next_rel where phase_id in ('+','.join(map(str, ids))+')') + ids = filter(None, map(lambda x:x[0], cr.fetchall())) + next_ids = ids + while(next_ids): + cr.execute('select distinct prev_phase_id from project_phase_prev_rel where phase_id in ('+','.join(map(str, ids))+')') + prev_ids = filter(None, map(lambda x:x[0], cr.fetchall())) + + return True + + while(ids): + cr.execute('select distinct child_id from account_account_consol_rel where parent_id in ('+','.join(map(str, ids))+')') + child_ids = filter(None, map(lambda x: x[0], cr.fetchall())) + c_ids = child_ids + if (p_id and (p_id in c_ids)) or (obj_self.id in c_ids): + return False + while len(c_ids): + s_ids = self.search(cr, uid, [('parent_id', 'in', c_ids)]) + if p_id and (p_id in s_ids): + return False + c_ids = s_ids + ids = child_ids + return True + + + + _columns = { + 'name': fields.char("Phase Name", size=64, required=True), + 'date_start': fields.datetime('Starting Date'), + 'date_end': fields.datetime('End Date'), + 'constraint_date_start': fields.datetime('Constraint Starting Date'), + 'constraint_date_end': fields.datetime('Constraint End Date'), + 'project_id': fields.many2one('project.project', 'Project', required=True), + 'next_phase_ids': fields.many2many('project.phase', 'project_phase_next_rel', 'phase_id', 'next_phase_id', 'Next Phases'), + 'previous_phase_ids': fields.many2many('project.phase', 'project_phase_previous_rel', 'phase_id', 'prv_phase_id', 'Previous Phases'), + 'duration': fields.float('Duration'), + 'product_uom': fields.many2one('product.uom', 'Duration UoM', help="UoM (Unit of Measure) is the unit of measurement for Duration"), + 'task_ids': fields.one2many('project.task', 'phase_id', "Project Tasks"), + 'resource_ids': fields.one2many('project.resource.allocation', 'phase_id', "Project Resources"), + } + + _defaults = { + 'date_start': lambda *a: time.strftime('%Y-%m-%d'), + } + + _order = "name" + _constraints = [ + (_check_recursion,'Error ! Loops In Phases Not Allowed',['next_phase_ids','previous_phase_ids']) + ] +project_phase() + +class project_resource_allocation(osv.osv): + _name = 'project.resource.allocation' + _description = 'Project Resource Allocation' + _columns = { + 'resource_id': fields.many2one('resource.resource', 'Resource', required=True), + 'phase_id': fields.many2one('project.phase', 'Project Phase', required=True), + 'useability': fields.float('Useability', help="Useability of this ressource for this project phase in percentage (=50%)"), + } + _defaults = { + 'useability': lambda *a: 100, + } +project_resource_allocation() + +class project(osv.osv): + _inherit = "project.project" + + _columns = { + 'phase_ids': fields.one2many('project.phase', 'project_id', "Project Phases") + } + +project() + +class task(osv.osv): + _inherit = "project.task" + + _columns = { + 'phase_id': fields.many2one('project.phase', 'Project Phase') + } + +task() +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + diff --git a/addons/project_long_term/project_data.xml b/addons/project_long_term/project_data.xml new file mode 100644 index 00000000000..2addd68fa19 --- /dev/null +++ b/addons/project_long_term/project_data.xml @@ -0,0 +1,16 @@ + + + + + + Project + project.project + + + Project task + project.task + + + diff --git a/addons/project_long_term/project_data_scheduler.xml b/addons/project_long_term/project_data_scheduler.xml new file mode 100644 index 00000000000..32e74725d58 --- /dev/null +++ b/addons/project_long_term/project_data_scheduler.xml @@ -0,0 +1,23 @@ + + + + + + + Calculate Project Task Length Scheduler + + + 1 + minutes + -1 + + + + + + + + + + diff --git a/addons/project_long_term/project_demo.xml b/addons/project_long_term/project_demo.xml new file mode 100644 index 00000000000..e762d3874ba --- /dev/null +++ b/addons/project_long_term/project_demo.xml @@ -0,0 +1,252 @@ + + + + + + + + + + + Analysis + + + New Feature + + + Quotation + + + Bug + + + + 1 + Open ERP Integration + + + + 1 + 10 + + Study + Prototype + + + + + 20 + + Specific Developements + + + + + 30 + + Install, data import, configuration + + + + + + 38.0 + 38.0 + + + + BoM, After sales returns, interventions. Tracability. + Specific adaptation to MRP + + + 16.0 + 16.0 + + + + Data importation + Doc + + + 16.0 + 16.0 + + + + Modifications asked by the customer. + + + 16.0 + 16.0 + + + 0 + + Customer analysis + Architecture + + + 15 + 8.0 + 8.0 + + + + Internal testing + Software Install + 2008-06-06 + + + 17 + 16.0 + 16.0 + + + 2 + open + + Analysis, Data Importation + + + 20 + 16.0 + 16.0 + open + + + Parameters + + + 20 + 32.0 + 32.0 + + open + + Start of the doc redaction + MRP + + + 25 + 24.0 + 24.0 + + + done + MRP Tests + + + 29 + 24.0 + 24.0 + + + MRP; functionnal layer + done + + + + 30 + 24.0 + 24.0 + + + Products Adaptation + + + 30 + 24.0 + 24.0 + + + Install + Super User Training + + + 30 + 32.0 + 32.0 + + + Customer docs + + + 30 + 24.0 + 24.0 + + + Development of the presentation layer + + + 40 + 32.0 + 32.0 + + + Free Time + + + 40 + 50.0 + 50.0 + + + Specific tests + + + 40 + 24.0 + 24.0 + + + Sale module + + + 40 + 32.0 + 32.0 + + + open + In house training + 2007-06-06 + + + 50 + 24.0 + 24.0 + + + Validation + latest modifications. + + + 50 + 24.0 + 24.0 + + + Adaptations buy module + + + 60 + 16.0 + 16.0 + + + Presentation of the software. + + + 60 + 24.0 + 24.0 + + + Adaptations Stock module + + + 70 + 24.0 + 24.0 + + + Latest in house tests + + + diff --git a/addons/project_long_term/project_report.xml b/addons/project_long_term/project_report.xml new file mode 100644 index 00000000000..c3b681cdd8b --- /dev/null +++ b/addons/project_long_term/project_report.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/addons/project_long_term/project_view.xml b/addons/project_long_term/project_view.xml new file mode 100644 index 00000000000..5afbad59af8 --- /dev/null +++ b/addons/project_long_term/project_view.xml @@ -0,0 +1,101 @@ + + + + + project.resource.allocation.form + project.resource.allocation + form + +
+ + + + + +
+ + project.resource.allocation.list + project.resource.allocation + tree + + + + + + + + + + + project.phase.form + project.phase + form + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + project.phase.list + project.phase + tree + + + + + + + + + + + + + + + + Project phases + project.phase + form + + + + + + + +
+
diff --git a/addons/project_long_term/project_wizard.xml b/addons/project_long_term/project_wizard.xml new file mode 100644 index 00000000000..109a003da4a --- /dev/null +++ b/addons/project_long_term/project_wizard.xml @@ -0,0 +1,8 @@ + + + + + + + + From 5fe81283a19b22f102204f539e3d1f30c8e605fe Mon Sep 17 00:00:00 2001 From: "pap (openerp)" Date: Wed, 13 Jan 2010 16:17:23 +0530 Subject: [PATCH 14/23] [IMP]:removed duplicate fields from hr.employee module, put resource_id also while creating resource.calendar.leaves record when hr.holidays record is confirmed bzr revid: pap@tinyerp.co.in-20100113104723-lcpmbsa63nv6ioam --- addons/hr/hr.py | 5 ----- addons/hr_holidays/hr.py | 8 +++++--- addons/resource/resource.py | 23 +++++------------------ 3 files changed, 10 insertions(+), 26 deletions(-) mode change 100644 => 100755 addons/hr/hr.py mode change 100644 => 100755 addons/hr_holidays/hr.py diff --git a/addons/hr/hr.py b/addons/hr/hr.py old mode 100644 new mode 100755 index 181d783d98d..4d77cf715b8 --- a/addons/hr/hr.py +++ b/addons/hr/hr.py @@ -57,11 +57,6 @@ class hr_employee(osv.osv): _description = "Employee" _inherits = {'resource.resource':"resource_id"} _columns = { - 'name' : fields.char("Employee's Name", size=128, required=True), - 'active' : fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the employee record without removing it."), - 'company_id': fields.many2one('res.company', 'Company'), - 'user_id' : fields.many2one('res.users', 'Related User', help='Related user name for an employee to manage his access rights.'), - 'country_id' : fields.many2one('res.country', 'Nationality'), 'birthday' : fields.date("Birthday"), 'ssnid': fields.char('SSN No', size=32, help='Social Security Number'), diff --git a/addons/hr_holidays/hr.py b/addons/hr_holidays/hr.py old mode 100644 new mode 100755 index 6c5e12771e1..a77eb046a33 --- a/addons/hr_holidays/hr.py +++ b/addons/hr_holidays/hr.py @@ -242,7 +242,6 @@ class hr_holidays(osv.osv): 'state':'validate', } ids2 = self.pool.get('hr.employee').search(cr, uid, [('user_id','=', uid)]) - if ids2: vals['manager_id'] = ids2[0] else: @@ -272,9 +271,12 @@ class hr_holidays(osv.osv): vals= { 'name':record.name, 'date_from':record.date_from, - 'date_to':record.date_to + 'date_to':record.date_to, + 'calendar_id':record.employee_id.calendar_id.id, + 'company_id':record.employee_id.company_id.id, + 'resource_id':record.employee_id.resource_id.id } - self.pool.get('resource.calendar.leaves').create(cr,uid,vals,context) + self.pool.get('resource.calendar.leaves').create(cr,uid,vals) return True diff --git a/addons/resource/resource.py b/addons/resource/resource.py index 2d225527f0e..dad8aedf5cf 100755 --- a/addons/resource/resource.py +++ b/addons/resource/resource.py @@ -44,16 +44,13 @@ class resource_calendar(osv.osv): resource_leave_ids = self.pool.get('resource.calendar.leaves').search(cr,uid,[('resource_id','=',resource)]) if resource_leave_ids: res_leaves = self.pool.get('resource.calendar.leaves').read(cr,uid,resource_leave_ids,['date_from','date_to']) - print 'Leave Details',res_leaves for i in range(len(res_leaves)): dtf = mx.DateTime.strptime(res_leaves[i]['date_from'],'%Y-%m-%d %H:%M:%S') dtt = mx.DateTime.strptime(res_leaves[i]['date_to'],'%Y-%m-%d %H:%M:%S') leave_days = ((dtt - dtf).days) + 1 - print 'No Of Leaves:::::::::',int(leave_days) for x in range(int(leave_days)): dt_leave.append((dtf + mx.DateTime.RelativeDateTime(days=x)).strftime('%Y-%m-%d')) dt_leave.sort() - print 'Sorted Leave Dates::::',dt_leave todo = hours cycle = 0 result = [] @@ -70,11 +67,8 @@ class resource_calendar(osv.osv): d2 = mx.DateTime.DateTime(dt_from.year,dt_from.month,dt_from.day,int(math.floor(hour_to)),int((hour_to%1) * 60)) dt1 = d1.strftime('%Y-%m-%d') dt2 = d2.strftime('%Y-%m-%d') - print 'Date 1',dt1 - print 'Date 2',dt2 for i in range(len(dt_leave)): if dt1 == dt_leave[i]: - print 'Leave::::::::' dt_from += mx.DateTime.RelativeDateTime(days=1) d1 = mx.DateTime.DateTime(dt_from.year,dt_from.month,dt_from.day,int(math.floor(m)),int((m%1) * 60)) d2 = mx.DateTime.DateTime(dt_from.year,dt_from.month,dt_from.day,int(math.floor(hour_to)),int((hour_to%1) * 60)) @@ -96,17 +90,14 @@ class resource_calendar(osv.osv): resource_leave_ids = self.pool.get('resource.calendar.leaves').search(cr,uid,[('resource_id','=',resource)]) if resource_leave_ids: res_leaves = self.pool.get('resource.calendar.leaves').read(cr,uid,resource_leave_ids,['date_from','date_to']) - print 'Leave Details',res_leaves for i in range(len(res_leaves)): dtf = mx.DateTime.strptime(res_leaves[i]['date_from'],'%Y-%m-%d %H:%M:%S') dtt = mx.DateTime.strptime(res_leaves[i]['date_to'],'%Y-%m-%d %H:%M:%S') no = dtt - dtf leave_days = no.days + 1 - print 'No Of Leaves:::::::::',int(leave_days) for x in range(int(leave_days)): dt_leave.append((dtf + mx.DateTime.RelativeDateTime(days=x)).strftime('%Y-%m-%d')) dt_leave.sort() - print 'Sorted Leave Dates::::',dt_leave todo = hours cycle = 0 result = [] @@ -123,11 +114,8 @@ class resource_calendar(osv.osv): d2 = mx.DateTime.DateTime(dt_from.year,dt_from.month,dt_from.day,int(math.floor(hour_to)),int((hour_to%1) * 60)) dt1 = d1.strftime('%Y-%m-%d') dt2 = d2.strftime('%Y-%m-%d') - print 'Date 1',dt1 - print 'Date 2',dt2 for i in range(len(dt_leave)): if dt1 == dt_leave[i]: - print 'Leave::::::::' dt_from += mx.DateTime.RelativeDateTime(days=1) d1 = mx.DateTime.DateTime(dt_from.year,dt_from.month,dt_from.day,int(math.floor(m)),int((m%1) * 60)) d2 = mx.DateTime.DateTime(dt_from.year,dt_from.month,dt_from.day,int(math.floor(hour_to)),int((hour_to%1) * 60)) @@ -161,14 +149,14 @@ class resource_resource(osv.osv): _name = "resource.resource" _description = "Resource Detail" _columns = { - 'name' : fields.char("Name", size=64, required=True), + 'name' : fields.char("Name", size=64, required=True ), 'code': fields.char('Code', size=16), 'active' : fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the resource record without removing it."), 'company_id' : fields.many2one('res.company', 'Company', required=True), 'resource_type': fields.selection([('user','Human'),('material','Material')], 'Resource Type', required=True), - 'user_id' : fields.many2one('res.users', 'User'), - 'time_efficiency' : fields.float('Efficiency factor', size=8, help="This field depict the efficency of the ressource to complete tasks. e.g ressource 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 efficency of 200%, then his load will only be 50%."), - 'calendar_id' : fields.many2one("resource.calendar", "Working time", required=True, help="Define the schedule of resource"), + '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, 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 efficency of 200%, then his load will only be 50%."), + 'calendar_id' : fields.many2one("resource.calendar", "Working time", help="Define the schedule of resource"), } _defaults = { 'resource_type' : lambda *a: 'user', @@ -183,8 +171,7 @@ class resource_calendar_leaves(osv.osv): _description = "Leave Detail" _columns = { 'name' : fields.char("Name", size=64), - 'company_id' : fields.related('calendar_id','company_id',type='many2one',relation='res.company',string="Company",required=True), - #'company_id':fields.many2one('res.company', 'Company', required=True), + 'company_id' : fields.related('calendar_id','company_id',type='many2one',relation='res.company',string="Company",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), From b221e232599d28d6a0c9d9ceb8ee4e7d2539e696 Mon Sep 17 00:00:00 2001 From: "nch@tinyerp.com" <> Date: Mon, 18 Jan 2010 18:10:04 +0530 Subject: [PATCH 15/23] [IMP]:read_group bzr revid: nch@tinyerp.com-20100118124004-m35ihvp4padm5ri3 --- bin/osv/orm.py | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index 7da3e17a573..9f25796ed1d 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -349,7 +349,6 @@ class orm_template(object): CONCURRENCY_CHECK_FIELD = '__last_update' def read_group(self, cr, user, ids, fields, groupby, context=None): - print ":::::::::::::",fields[groupby],groupby context = context or {} if not ids:return if fields[groupby]['type'] not in ('many2one,date,datetime'): @@ -363,10 +362,16 @@ class orm_template(object): qu2 += d2 float_int_fields = list(field_name for field_name,values in fields.items() if values['type'] in ('float','integer')) - sumof = ','.join(map(lambda field_name:'sum('+field_name+') as '+field_name+'',float_int_fields)) - cr.execute('select '+groupby+','+sumof+' from ' + self._table +qu1+' group by '+groupby+qu2) + sum = {} + + cr.execute('select '+groupby+' from ' + self._table +qu1+' group by '+groupby+qu2) parent_res = cr.fetchall() + try: + parent_res = [(m[0],m[1]) for m in parent_res if m[0]] + except: + parent_res = [(m[0],) for m in parent_res if m[0]] groupby_ids = map(lambda x:x[0],parent_res) + groupby_name = {} child_ids_dict = {} @@ -384,6 +389,7 @@ class orm_template(object): else: child_ids_dict[parent_id].append(val[0]) #create [{},{}] for parent ids i.e for group by field + result = [] if fields[groupby]['type'] in ('date','datetime'): curr_date = datetime.date.today() @@ -403,11 +409,16 @@ class orm_template(object): date_format = 'Old' date_result[date_format].update({'id':None,groupby:date_format}) date_result[date_format]['group_child'] += child_ids_dict[x[0]] - for sum in float_int_fields: - if sum not in date_result[date_format]: - date_result[date_format][sum] = x[float_int_fields.index(sum)+1] - if float_int_fields.index(sum): - date_result[date_format][sum] += x[float_int_fields.index(sum)+1] + float_int_sum = self.read(cr, user, child_ids_dict[x[0]], float_int_fields, context) + for value in float_int_sum: + for field,val in value.items(): + if field == 'id':continue + if field not in sum: + sum[field] = 0.0 + sum[field] += val + for k,v in sum.items(): + date_result[date_format][k] = v + sum = {} for key,val in date_result.items(): if len(date_result[key]) == 1: del date_result[key] @@ -419,18 +430,24 @@ class orm_template(object): result.insert(0,val) else: result.insert(-1,val) - print result return result else: for x in parent_res: - parent_val_dict = {'id':None,groupby:(x[0],groupby_name[x[0]]),'group_child':child_ids_dict[x[0]]} - for sum in float_int_fields: - parent_val_dict[sum] = x[float_int_fields.index(sum)+1] + parent_val_dict = {'id':str(x[0])+':Gpby',groupby:(x[0],groupby_name[x[0]]),'group_child':child_ids_dict[x[0]]} + float_int_sum = self.read(cr, user, child_ids_dict[x[0]], float_int_fields, context) + for value in float_int_sum: + for field,val in value.items(): + if field == 'id':continue + if field not in sum: + sum[field] = 0.0 + sum[field] += val + for k,v in sum.items(): + parent_val_dict[k] = v + sum = {} for field in fields.keys(): if field not in parent_val_dict: parent_val_dict[field] = False result.append(parent_val_dict) - print result return result def _field_create(self, cr, context={}): From 386ce8c18e59afa6a991ce62e11dd0c34d0cc81b Mon Sep 17 00:00:00 2001 From: "Rvo (Open ERP)" Date: Mon, 18 Jan 2010 18:36:09 +0530 Subject: [PATCH 16/23] [FIX]:Removed the scheduler method compute_date from project__terp__.py bzr revid: rvo@tinyerp.co.in-20100118130609-5hqc8dl0detz72y7 --- addons/project/__terp__.py | 2 +- addons/project/project.py | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/addons/project/__terp__.py b/addons/project/__terp__.py index 97a4c94deb0..1a11e64f134 100644 --- a/addons/project/__terp__.py +++ b/addons/project/__terp__.py @@ -42,7 +42,7 @@ works done on tasks, eso. It is able to render planning, order tasks, eso. "process/task_process.xml" ], 'demo_xml': [#'project_demo.xml' - 'project_data_scheduler.xml' + ], 'installable': True, 'active': False, diff --git a/addons/project/project.py b/addons/project/project.py index 4081524f0ec..95a8c9497e7 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -21,12 +21,17 @@ from lxml import etree import mx.DateTime +import datetime import time from tools.translate import _ - from osv import fields, osv from tools.translate import _ +#from resource.faces import * +#from resource.faces.lib import workbreakdown +#from resource.faces.lib import generator +#from resource.faces.lib import resource + class project(osv.osv): _name = "project.project" _description = "Project" From cfe2942d8ab2170dc1c412ebfb9288f4114a592e Mon Sep 17 00:00:00 2001 From: "pap (openerp)" Date: Mon, 18 Jan 2010 19:14:53 +0530 Subject: [PATCH 17/23] [IMP]: 1) start_date < end_date in leave form 2) remove duplicate fields from mrp.workcenter 3) remove recursion in project phases, start_date < end_date start_date < end_date in project.task and project.project bzr revid: pap@tinyerp.co.in-20100118134453-uptuohuxvyqhizfq --- addons/mrp/mrp.py | 5 +- addons/mrp/mrp_view.xml | 2 +- addons/project/project.py | 40 ++++++++++++++-- addons/project/project_view.xml | 6 ++- addons/project_long_term/project.py | 72 +++++++++++++++++++---------- addons/resource/resource.py | 11 ++++- 6 files changed, 101 insertions(+), 35 deletions(-) diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index 726d5a3e34e..c3a272f06ca 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -42,7 +42,7 @@ class mrp_workcenter(osv.osv): _description = 'Work Center' _inherits = {'resource.resource':"resource_id"} _columns = { - 'name': fields.char('Work Center Name', size=64, required=True), +# 'name': fields.char('Work Center Name', size=64, required=True), 'note': fields.text('Description', help="Description of the workcenter. Explain here what's a cycle according to this workcenter."), 'capacity_per_cycle': fields.float('Capacity per Cycle', help="Number of operations this workcenter can do in parallel. If this workcenter represents a team of 5 workers, the capacity per cycle is 5."), 'time_cycle': fields.float('Time for 1 cycle (hour)', help="Time in hours for doing one cycle."), @@ -56,7 +56,8 @@ class mrp_workcenter(osv.osv): help="Complete this only if you want automatic analytic accounting entries on production orders."), 'costs_journal_id': fields.many2one('account.analytic.journal', 'Analytic Journal'), 'costs_general_account_id': fields.many2one('account.account', 'General Account', domain=[('type','<>','view')]), - 'company_id': fields.many2one('res.company','Company',required=True), +# 'company_id': fields.many2one('res.company','Company',required=True), + 'resource_id': fields.many2one('resource.resource','Resource',ondelete='cascade'), } _defaults = { 'capacity_per_cycle': lambda *a: 1.0, diff --git a/addons/mrp/mrp_view.xml b/addons/mrp/mrp_view.xml index 7c567ef0b7a..0e7ff6db167 100644 --- a/addons/mrp/mrp_view.xml +++ b/addons/mrp/mrp_view.xml @@ -114,7 +114,7 @@ - + diff --git a/addons/project/project.py b/addons/project/project.py index 95a8c9497e7..89cf75e454c 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -130,6 +130,16 @@ class project(osv.osv): # 'state': lambda *a: 'open', # 'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'project.project', context=c) } + def _check_dates(self, cr, uid, ids): + leave = self.read(cr, uid, ids[0],['date_start','date']) + if leave['date_start'] and leave['date']: + if leave['date_start'] > leave['date']: + return False + return True + + _constraints = [ + (_check_dates, 'Error! project start-date must be lower then project end-date.', ['date_start', 'date']) + ] # _order = "parent_id,priority,name" # _constraints = [ @@ -221,6 +231,32 @@ class task(osv.osv): _description = "Tasks" _date_name = "date_start" +# def compute_date(self,cr,uid): +# project_id = self.pool.get('project.project').search(cr,uid,[]) +# for i in range(len(project_id)): +# task_ids = self.pool.get('project.task').search(cr,uid,[('project_id','=',project_id[i])]) +# if task_ids: +# task_obj = self.pool.get('project.task').browse(cr,uid,task_ids) +# task_1 = task_obj[0] +# task_1.date_start = self.pool.get('project.project').browse(cr,uid,project_id[i]).date_start +## print '1st Date Start::::',task_1.date_start,type(task_1.date_start) +# dt = mx.DateTime.strptime(task_1.date_start,"%Y-%m-%d").strftime("%Y-%m-%d") +## print 'Hours:::::',task_1.planned_hours +## print 'Date',dt +# def Project_1(): +# title = "New Project" +# start = dt +# +# def task1(): +# start = dt +# effort = task_1.planned_hours +# title = "Task 1" +## project_1 = BalancedProject(Project_1) +## print 'Title::::::',project_1.title +## for t in project_1: +## print 'details:::',t.indent_name(), t.start, t.end, t.effort + + def _str_get(self, task, level=0, border='***', context={}): return border+' '+(task.user_id and task.user_id.name.upper() or '')+(level and (': L'+str(level)) or '')+(' - %.1fh / %.1fh'%(task.effective_hours or 0.0,task.planned_hours))+' '+border+'\n'+ \ border[0]+' '+(task.name or '')+'\n'+ \ @@ -266,14 +302,10 @@ class task(osv.osv): if date_start and planned: resource_id = self.pool.get('resource.resource').search(cr,uid,[('user_id','=',res.user_id.id)]) resource_obj = self.pool.get('resource.resource').browse(cr,uid,resource_id)[0] - print 'Resource Calendar::::',resource_obj.calendar_id.id d = mx.DateTime.strptime(date_start,'%Y-%m-%d %H:%M:%S') hrs = (planned)/(occupation_rate) - print 'Hours::::',hrs work_times = self.pool.get('resource.calendar').interval_get(cr, uid, resource_obj.calendar_id.id or False, d, hrs or 0.0, resource_obj.id) - print 'Date_end',work_times result['date_end'] = work_times[-1][1].strftime('%Y-%m-%d %H:%M:%S') - print 'Date End',result['date_end'] result['remaining_hours'] = planned-effective return {'value':result} diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml index fe6122bd559..5dffaac2b34 100644 --- a/addons/project/project_view.xml +++ b/addons/project/project_view.xml @@ -309,8 +309,9 @@ - - + + + @@ -324,6 +325,7 @@ + diff --git a/addons/project_long_term/project.py b/addons/project_long_term/project.py index f04e18babfd..c5734263ea5 100644 --- a/addons/project_long_term/project.py +++ b/addons/project_long_term/project.py @@ -33,32 +33,44 @@ class project_phase(osv.osv): _description = "Project Phase" def _check_recursion(self,cr,uid,ids): - level = 100 - while len(ids): - cr.execute('select distinct next_phase_id from project_phase_next_rel where phase_id in ('+','.join(map(str, ids))+')') - ids = filter(None, map(lambda x:x[0], cr.fetchall())) - next_ids = ids - while(next_ids): - cr.execute('select distinct prev_phase_id from project_phase_prev_rel where phase_id in ('+','.join(map(str, ids))+')') - prev_ids = filter(None, map(lambda x:x[0], cr.fetchall())) - - return True - - while(ids): - cr.execute('select distinct child_id from account_account_consol_rel where parent_id in ('+','.join(map(str, ids))+')') - child_ids = filter(None, map(lambda x: x[0], cr.fetchall())) - c_ids = child_ids - if (p_id and (p_id in c_ids)) or (obj_self.id in c_ids): - return False - while len(c_ids): - s_ids = self.search(cr, uid, [('parent_id', 'in', c_ids)]) - if p_id and (p_id in s_ids): - return False - c_ids = s_ids - ids = child_ids - return True - + obj_self = self.browse(cr, uid, ids[0]) + prev_ids = obj_self.previous_phase_ids + next_ids = obj_self.next_phase_ids + #it should nither be in prev_ids nor in next_ids + if (obj_self in prev_ids) or (obj_self in next_ids): + return False + ids = [id for id in prev_ids if id in next_ids] + + #both prev_ids and next_ids must be unique + if ids: + return False + #unrelated project + + prev_ids = [rec.id for rec in prev_ids] + next_ids = [rec.id for rec in next_ids] + #iter prev_ids + while prev_ids: + cr.execute('select distinct prv_phase_id from project_phase_previous_rel where phase_id in ('+','.join(map(str, prev_ids))+')') + prv_phase_ids = filter(None, map(lambda x: x[0], cr.fetchall())) + if obj_self.id in prv_phase_ids: + return False + ids = [id for id in prv_phase_ids if id in next_ids] + if ids: + return False + prev_ids = prv_phase_ids + + #iter next_ids + while next_ids: + cr.execute('select distinct next_phase_id from project_phase_next_rel where phase_id in ('+','.join(map(str, next_ids))+')') + next_phase_ids = filter(None, map(lambda x: x[0], cr.fetchall())) + if obj_self.id in next_phase_ids: + return False + ids = [id for id in next_phase_ids if id in prev_ids] + if ids: + return False + next_ids = next_phase_ids + return True _columns = { 'name': fields.char("Phase Name", size=64, required=True), @@ -113,6 +125,16 @@ class task(osv.osv): _columns = { 'phase_id': fields.many2one('project.phase', 'Project Phase') } + def _check_dates(self, cr, uid, ids): + leave = self.read(cr, uid, ids[0],['date_start','date_end']) + if leave['date_start'] and leave['date_end']: + if leave['date_start'] > leave['date_end']: + return False + return True + + _constraints = [ + (_check_dates, 'Error! task start-date must be lower then task end-date.', ['date_start', 'date_end']) + ] task() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/resource/resource.py b/addons/resource/resource.py index dad8aedf5cf..7ac36e5e7bd 100755 --- a/addons/resource/resource.py +++ b/addons/resource/resource.py @@ -176,7 +176,16 @@ class resource_calendar_leaves(osv.osv): '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): + leave = self.read(cr, uid, ids[0],['date_from','date_to']) + if leave['date_from'] and leave['date_to']: + if leave['date_from'] > leave['date_to']: + return False + return True + + _constraints = [ + (check_dates, 'Error! leave start-date must be lower then leave end-date.', ['date_from', 'date_to']) + ] resource_calendar_leaves() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From aa41d4010c1dbd338f0133a1176a90f3c4090e0b Mon Sep 17 00:00:00 2001 From: "pap (openerp)" Date: Mon, 18 Jan 2010 19:46:37 +0530 Subject: [PATCH 18/23] [REM]:removed print statement bzr revid: pap@tinyerp.co.in-20100118141637-lo24jfayx1qxr6fx --- addons/hr_holidays/hr.py | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/hr_holidays/hr.py b/addons/hr_holidays/hr.py index a77eb046a33..ff33621cbe0 100755 --- a/addons/hr_holidays/hr.py +++ b/addons/hr_holidays/hr.py @@ -165,7 +165,6 @@ class hr_holidays(osv.osv): _order = 'date_from desc' def create(self, cr, uid, vals, context={}): - print 'create', vals, context if context: if context.has_key('type'): vals['type'] = context['type'] From 24f5a5152eda41550491d71ce7d9290fac0a77a0 Mon Sep 17 00:00:00 2001 From: "sbh (Open ERP)" Date: Tue, 19 Jan 2010 11:17:36 +0530 Subject: [PATCH 19/23] [Fix]:Event Add the missing field of crm bzr revid: sbh@tinyerp.com-20100119054736-cvhvch4uxp5ta7d0 --- addons/event/event.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/addons/event/event.py b/addons/event/event.py index 3e4cf5566d2..cad4d7f23d1 100644 --- a/addons/event/event.py +++ b/addons/event/event.py @@ -25,6 +25,7 @@ import netsvc import pooler import tools from tools.translate import _ +from crm import crm class crm_case_log(osv.osv): _inherit = 'crm.case.log' @@ -241,6 +242,16 @@ class event_registration(osv.osv): "invoice_label":fields.char("Label Invoice",size=128,required=True), "tobe_invoiced":fields.boolean("To be Invoiced"), "invoice_id":fields.many2one("account.invoice","Invoice"), + 'date_closed': fields.datetime('Closed', readonly=True), + 'ref' : fields.reference('Reference', selection=crm._links_get, size=128), + 'ref2' : fields.reference('Reference 2', selection=crm._links_get, size=128), + 'categ_id': fields.many2one('crm.case.categ','Category', domain="[('section_id','=',section_id)]"), + 'canal_id': fields.many2one('res.partner.canal', 'Channel',help="The channels represent the different communication modes available with the customer." \ + " With each commercial opportunity, you can indicate the canall which is this opportunity source."), + 'som': fields.many2one('res.partner.som', 'State of Mind', help="The minds states allow to define a value scale which represents" \ + "the partner mentality in relation to our services.The scale has" \ + "to be created with a factor for each level from 0 (Very dissatisfied) to 10 (Extremely satisfied)."), + } _defaults = { 'nb_register': lambda *a: 1, From fbe0cd494f95a20ca30a2274f15bf64825e1116f Mon Sep 17 00:00:00 2001 From: "nch@tinyerp.com" <> Date: Tue, 19 Jan 2010 11:23:05 +0530 Subject: [PATCH 20/23] [IMP]:readgroup bzr revid: nch@tinyerp.com-20100119055305-h36ot0qc2lmeh1cg --- bin/osv/orm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index 9f25796ed1d..30b03608bb6 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -351,7 +351,7 @@ class orm_template(object): def read_group(self, cr, user, ids, fields, groupby, context=None): context = context or {} if not ids:return - if fields[groupby]['type'] not in ('many2one,date,datetime'): + if fields[groupby]['type'] not in ('many2one','date','datetime'): raise Exception(_("Type Not supported for Group By: %s :Only many2one,date and datetime are supported ") %(fields[groupby]['type'],)) qu1 = ' where id in (' + ','.join([str(id) for id in ids]) + ')' qu2 = '' From 3a3a5731c0665527fbbb03d9a32db559913a3154 Mon Sep 17 00:00:00 2001 From: "nch@tinyerp.com" <> Date: Tue, 19 Jan 2010 13:59:07 +0530 Subject: [PATCH 21/23] [IMP]:read_group bzr revid: nch@tinyerp.com-20100119082907-2hdt70viea5eu1ek --- bin/osv/orm.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index a3892e281a4..134929fcefa 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -351,12 +351,15 @@ class orm_template(object): def read_group(self, cr, user, ids, fields, groupby, context=None): context = context or {} if not ids:return + if fields[groupby]['type'] not in ('many2one','date','datetime'): raise Exception(_("Type Not supported for Group By: %s :Only many2one,date and datetime are supported ") %(fields[groupby]['type'],)) + qu1 = ' where id in (' + ','.join([str(id) for id in ids]) + ')' qu2 = '' # construct a clause for the rules : - d1, d2 = self.pool.get('ir.rule').domain_get(cr, user, self._name) + d1, d2, d3 = self.pool.get('ir.rule').domain_get(cr, user, self._name) + if d1: qu1 = qu1 and qu1+' and '+d1 or ' where '+d1 qu2 += d2 @@ -377,6 +380,7 @@ class orm_template(object): if fields[groupby]['type'] == 'many2one': groupby_name = dict(self.pool.get(fields[groupby]['relation']).name_get(cr,user,groupby_ids,context)) + chqu1 =' where id in (' + ','.join([str(id) for id in ids]) + ') and ' # get child ids From 760b70c3ec84e884f610ac682fab8007e31c06a1 Mon Sep 17 00:00:00 2001 From: "nch@tinyerp.com" <> Date: Tue, 19 Jan 2010 14:35:02 +0530 Subject: [PATCH 22/23] [IMP]:added group by filter (by users,project,type) on project task tree view bzr revid: nch@tinyerp.com-20100119090502-jdn7xepbm1q81tsu --- addons/project/project_view.xml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml index f0a0d846e4b..4658b339348 100644 --- a/addons/project/project_view.xml +++ b/addons/project/project_view.xml @@ -344,7 +344,7 @@
- + @@ -358,13 +358,13 @@ - +