From 6085c0d63d57625234bf18d964c67a53a2796674 Mon Sep 17 00:00:00 2001 From: ced <> Date: Mon, 23 Apr 2007 13:13:47 +0000 Subject: [PATCH] MULTI_COMPANY_ACCOUNT, ACCOUNT, KERNEL, SALE, PURCHASE: add multi-company for accounting with a lot improvement bzr revid: ced-f64ff379976afb70dac3ba7baaf68eef393645c5 --- bin/addons/base/res/res_company.py | 3 --- bin/osv/fields.py | 30 +++++++++++++++++++++++----- bin/osv/orm.py | 32 +++++++++++++++++++++++------- bin/osv/osv.py | 2 +- bin/tools/misc.py | 14 +++++++++++++ 5 files changed, 65 insertions(+), 16 deletions(-) diff --git a/bin/addons/base/res/res_company.py b/bin/addons/base/res/res_company.py index 08f772a73ac..fbef52b1790 100644 --- a/bin/addons/base/res/res_company.py +++ b/bin/addons/base/res/res_company.py @@ -56,13 +56,11 @@ class res_company(osv.osv): _get_company_children = tools.cache()(_get_company_children) def _get_partner_hierarchy(self, cr, uid, company_id, context={}): - print "Company ID is %s: Looking for parent..." % company_id if company_id: parent_id = self.browse(cr, uid, company_id)['parent_id'] if parent_id: return self._get_partner_hierarchy(cr, uid, parent_id.id, context) else: - print "No parent: starting descendance search!" return self._get_partner_descendance(cr, uid, company_id, [], context) return [] @@ -70,7 +68,6 @@ class res_company(osv.osv): descendance.append(self.browse(cr, uid, company_id).partner_id.id) for child_id in self._get_company_children(cr, uid, company_id): if child_id != company_id: - print "Hello, I'm %s, child of %s" % (child_id, company_id) descendance = self._get_partner_descendance(cr, uid, child_id, descendance) return descendance diff --git a/bin/osv/fields.py b/bin/osv/fields.py index fed5de780e9..7c522af865d 100644 --- a/bin/osv/fields.py +++ b/bin/osv/fields.py @@ -46,6 +46,8 @@ import netsvc import psycopg import warnings +import tools + def _symbol_set(symb): if symb==None or symb==False: return None @@ -275,7 +277,16 @@ class many2one(_column): res.setdefault(id, '') obj = obj.pool.get(self._obj) # build a dictionary of the form {'id_of_distant_resource': name_of_distant_resource} - names = dict(obj.name_get(cr, user, filter(None, res.values()), context)) + from orm import except_orm + try: + names = dict(obj.name_get(cr, user, filter(None, res.values()), context)) + except except_orm: + names={} + for id in filter(None, res.values()): + try: + names[id] = dict(obj.name_get(cr, user, [id], context))[id] + except except_orm: + names[id] = "===Access error===" for r in res.keys(): if res[r] and res[r] in names: res[r] = (res[r], names[res[r]]) @@ -381,11 +392,16 @@ class many2many(_column): res = {} if not ids: return res - ids_s = ','.join(map(str,ids)) - limit_str = self._limit is not None and ' limit %d' % self._limit or '' - cr.execute('select '+self._id2+','+self._id1+' from '+self._rel+' where '+self._id1+' in ('+ids_s+')'+limit_str+' offset %d', (offset,)) for id in ids: res[id] = [] + ids_s = ','.join(map(str,ids)) + limit_str = self._limit is not None and ' limit %d' % self._limit or '' + obj = obj.pool.get(self._obj) + if 'company_id' in obj._columns: + compids = tools.get_user_companies(cr, user) + cr.execute('SELECT r.'+self._id2+', r.'+self._id1+' FROM '+self._rel+' AS r, '+obj._table+' AS o WHERE r.'+self._id1+' in ('+ids_s+') AND r.'+self._id2+' = o.id AND (o.company_id IN ('+','.join(map(str,compids))+') OR o.company_id IS NULL)'+limit_str+' OFFSET %d', (offset,)) + else: + cr.execute('select '+self._id2+','+self._id1+' from '+self._rel+' where '+self._id1+' in ('+ids_s+')'+limit_str+' offset %d', (offset,)) for r in cr.fetchall(): res[r[1]].append(r[0]) return res @@ -409,7 +425,11 @@ class many2many(_column): elif act[0]==5: cr.execute('update '+self._rel+' set '+self._id2+'=null where '+self._id2+'=%d', (id,)) elif act[0]==6: - cr.execute('delete from '+self._rel+' where '+self._id1+'=%d', (id, )) + if 'company_id' in obj._columns and not user == 1: + compids = tools.get_user_companies(cr, user) + cr.execute('delete from '+self._rel+' where '+self._id1+'=%d AND '+self._id2+' IN (SELECT r.'+self._id2+' FROM '+self._rel+' AS r, '+obj._table+' AS o WHERE r.'+self._id1+'=%d AND r.'+self._id2+' = o.id AND (o.company_id IN ('+','.join(map(str,compids))+') OR o.company_id IS NULL))', (id, id, )) + else: + cr.execute('delete from '+self._rel+' where '+self._id1+'=%d', (id, )) for act_nbr in act[2]: cr.execute('insert into '+self._rel+' ('+self._id1+','+self._id2+') values (%d, %d)', (id, act_nbr)) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index 54ace39387d..dbab4f50b0d 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -173,6 +173,13 @@ class browse_record(object): if isinstance(f, fields.many2one) or isinstance(f, fields.one2one): if data[n]: obj = self._table.pool.get(f._obj) + compids=False + if 'company_id' in obj._columns and not self._uid == 1: + compids = tools.get_user_companies(self._cr, self._uid) + if compids: + self._cr.execute('SELECT id FROM '+obj._table+' where id = %d AND (company_id in ('+','.join(map(str,compids))+') or company_id is null)', (data[n],)) + if not self._cr.fetchall(): + raise except_orm('BrowseError', 'Object %s (id:%d) is linked to the object %s (id:%d) that is not in your company' %(self._table._description, self._id, obj._description, data[n])) data[n] = browse_record(self._cr, self._uid, data[n], obj, self._cache, context=self._context, list_class=self._list_class) else: data[n] = browse_null() @@ -703,14 +710,25 @@ class orm(object): if fields==None: fields = self._columns.keys() + # if the object has a field named 'company_id', filter out all + # records which do not concern the current company (the company + # of the current user) or its "childs" + company_clause='true' + compids=False + if 'company_id' in self._columns and not user == 1: + compids = tools.get_user_companies(cr, user) + if compids: + company_clause = '(company_id in ('+','.join(map(str,compids))+') or company_id is null)' + # all inherited fields + all non inherited fields for which the attribute whose name is in load is True fields_pre = filter(lambda x: x in self._columns and getattr(self._columns[x],'_classic_write'), fields) + self._inherits.values() - if len(fields_pre): - cr.execute('select %s from %s where id = any(array[%s]) order by %s' % (','.join(fields_pre + ['id']), self._table, ','.join([str(x) for x in ids]), self._order)) - - if not cr.rowcount: - return [] + if len(fields_pre) or compids: + cr.execute('select %s from %s where id = any(array[%s]) and %s order by %s' % (','.join(fields_pre + ['id']), self._table, ','.join([str(x) for x in ids]), company_clause, self._order)) + uniq_id = [] + [uniq_id.append(i) for i in ids if not uniq_id.count(i)] + if not cr.rowcount == len(uniq_id) and compids: + raise except_orm('ReadError', 'You try to read objects (%s) that is not in your company' % self._description) res = cr.dictfetchall() else: res = map(lambda x: {'id':x}, ids) @@ -1363,8 +1381,8 @@ class orm(object): # if the object has a field named 'company_id', filter out all # records which do not concern the current company (the company # of the current user) or its "childs" - if 'company_id' in self._columns: - compids = self.pool.get('res.company')._get_child_ids(cr, user, user) + if 'company_id' in self._columns and not user == 1: + compids = tools.get_user_companies(cr, user) if compids: compids.append(False) args.append(('company_id','in',compids)) diff --git a/bin/osv/osv.py b/bin/osv/osv.py index 1ec02b910dd..c87251706ee 100644 --- a/bin/osv/osv.py +++ b/bin/osv/osv.py @@ -86,7 +86,7 @@ class osv_pool(netsvc.Service): return res except orm.except_orm, inst: #self.abortResponse(1, inst.value[0], inst.name, inst.value[1]) - self.abortResponse(1, inst.value[0], 'warning', inst.value[1]) + self.abortResponse(1, inst.name, 'warning', inst.value) except except_osv, inst: self.abortResponse(1, inst.name, inst.exc_type, inst.value) except psycopg.IntegrityError, inst: diff --git a/bin/tools/misc.py b/bin/tools/misc.py index c41c144e7d6..803e30c901f 100644 --- a/bin/tools/misc.py +++ b/bin/tools/misc.py @@ -380,4 +380,18 @@ def scan_languages(): lang_dict = get_languages() return [(lang, lang_dict.get(lang, lang)) for lang in file_list] + +def get_user_companies(cr, user): + def _get_company_children(cr, ids): + if not ids: + return [] + cr.execute('SELECT id FROM res_company WHERE parent_id = any(array[%s])' %(','.join([str(x) for x in ids]),)) + res=[x[0] for x in cr.fetchall()] + res.extend(_get_company_children(cr, res)) + return res + cr.execute('SELECT comp.id FROM res_company AS comp, res_users AS u WHERE u.id = %d AND comp.id = u.company_id' % (user,)) + compids=[cr.fetchone()[0]] + compids.extend(_get_company_children(cr, compids)) + return compids + # vim:noexpandtab