From 970b19b8b44632937baf3e3a8f80f2b20030ab7b Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Wed, 8 Jun 2011 05:03:30 +0200 Subject: [PATCH 01/56] [IMP] new tools.cache cleaner, 10% speedup and more to come... bzr revid: al@openerp.com-20110608030330-d0dsv2k6n0w3lyd5 --- openerp/addons/base/ir/ir_model.py | 13 +- openerp/addons/base/ir/ir_rule.py | 12 +- openerp/addons/base/ir/ir_translation.py | 22 +-- openerp/addons/base/res/res_company.py | 4 +- openerp/addons/base/res/res_lang.py | 4 +- openerp/addons/base/res/res_user.py | 6 +- openerp/osv/orm.py | 20 +- openerp/tools/lru.py | 7 +- openerp/tools/misc.py | 241 +++++++++-------------- 9 files changed, 142 insertions(+), 187 deletions(-) diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py index ad0912a59ee..7121833156d 100644 --- a/openerp/addons/base/ir/ir_model.py +++ b/openerp/addons/base/ir/ir_model.py @@ -450,6 +450,7 @@ class ir_model_access(osv.osv): # pass no groups -> no access return False + @tools.ormcache() def check(self, cr, uid, model, mode='read', raise_exception=True, context=None): if uid==1: # User root have all accesses @@ -513,8 +514,6 @@ class ir_model_access(osv.osv): raise except_orm(_('AccessError'), msgs[mode] % (model_name, groups) ) return r - check = tools.cache()(check) - __cache_clearing_methods = [] def register_cache_clearing_method(self, model, method): @@ -528,7 +527,7 @@ class ir_model_access(osv.osv): pass def call_cache_clearing_methods(self, cr): - self.check.clear_cache(cr.dbname) # clear the cache of check function + self.check.clear_cache(self) # clear the cache of check function for model, method in self.__cache_clearing_methods: object_ = self.pool.get(model) if object_: @@ -593,7 +592,7 @@ class ir_model_data(osv.osv): if not cr.fetchone(): cr.execute('CREATE INDEX ir_model_data_module_name_index ON ir_model_data (module, name)') - @tools.cache() + @tools.ormcache() def _get_id(self, cr, uid, module, xml_id): """Returns the id of the ir.model.data record corresponding to a given module and xml_id (cached) or raise a ValueError if not found""" ids = self.search(cr, uid, [('module','=',module), ('name','=', xml_id)]) @@ -602,7 +601,7 @@ class ir_model_data(osv.osv): # the sql constraints ensure us we have only one result return ids[0] - @tools.cache() + @tools.ormcache() def get_object_reference(self, cr, uid, module, xml_id): """Returns (model, res_id) corresponding to a given module and xml_id (cached) or raise ValueError if not found""" data_id = self._get_id(cr, uid, module, xml_id) @@ -652,8 +651,8 @@ class ir_model_data(osv.osv): results = cr.fetchall() for imd_id2,res_id2,real_id2 in results: if not real_id2: - self._get_id.clear_cache(cr.dbname, uid, module, xml_id) - self.get_object_reference.clear_cache(cr.dbname, uid, module, xml_id) + self._get_id.clear_cache(self, uid, module, xml_id) + self.get_object_reference.clear_cache(self, uid, module, xml_id) cr.execute('delete from ir_model_data where id=%s', (imd_id2,)) res_id = False else: diff --git a/openerp/addons/base/ir/ir_rule.py b/openerp/addons/base/ir/ir_rule.py index befa47e25b0..b62da2ac4ff 100644 --- a/openerp/addons/base/ir/ir_rule.py +++ b/openerp/addons/base/ir/ir_rule.py @@ -94,7 +94,7 @@ class ir_rule(osv.osv): return ['&'] * (count-1) + dom return [] - @tools.cache() + @tools.ormcache() def _compute_domain(self, cr, uid, model_name, mode="read"): if mode not in self._MODES: raise ValueError('Invalid mode: %r' % (mode,)) @@ -147,12 +147,12 @@ class ir_rule(osv.osv): AND u_rel.uid = %s) """, (uid,)) models = map(itemgetter(0), cr.fetchall()) - clear = partial(self._compute_domain.clear_cache, cr.dbname, uid) + clear = partial(self._compute_domain.clear_cache, self, uid) [clear(model, mode) for model in models for mode in self._MODES] def domain_get(self, cr, uid, model_name, mode='read', context=None): - dom = self._compute_domain(cr, uid, model_name, mode=mode) + dom = self._compute_domain(cr, uid, model_name, mode) if dom: # _where_calc is called as superuser. This means that rules can # involve objects on which the real uid has no acces rights. @@ -165,19 +165,19 @@ class ir_rule(osv.osv): def unlink(self, cr, uid, ids, context=None): res = super(ir_rule, self).unlink(cr, uid, ids, context=context) # Restart the cache on the _compute_domain method of ir.rule - self._compute_domain.clear_cache(cr.dbname) + self._compute_domain.clear_cache(self) return res def create(self, cr, user, vals, context=None): res = super(ir_rule, self).create(cr, user, vals, context=context) # Restart the cache on the _compute_domain method of ir.rule - self._compute_domain.clear_cache(cr.dbname) + self._compute_domain.clear_cache(self) return res def write(self, cr, uid, ids, vals, context=None): res = super(ir_rule, self).write(cr, uid, ids, vals, context=context) # Restart the cache on the _compute_domain method - self._compute_domain.clear_cache(cr.dbname) + self._compute_domain.clear_cache(self) return res ir_rule() diff --git a/openerp/addons/base/ir/ir_translation.py b/openerp/addons/base/ir/ir_translation.py index eb900363669..0e6374b0143 100644 --- a/openerp/addons/base/ir/ir_translation.py +++ b/openerp/addons/base/ir/ir_translation.py @@ -92,7 +92,7 @@ class ir_translation(osv.osv): cr.execute('CREATE INDEX ir_translation_ltn ON ir_translation (name, lang, type)') cr.commit() - @tools.cache(skiparg=3, multi='ids') + @tools.ormcache_multi(skiparg=3, multi=7) def _get_ids(self, cr, uid, name, tt, lang, ids): translations = dict.fromkeys(ids, False) if ids: @@ -112,9 +112,9 @@ class ir_translation(osv.osv): tr = self._get_ids(cr, uid, name, tt, lang, ids) for res_id in tr: if tr[res_id]: - self._get_source.clear_cache(cr.dbname, uid, name, tt, lang, tr[res_id]) - self._get_source.clear_cache(cr.dbname, uid, name, tt, lang) - self._get_ids.clear_cache(cr.dbname, uid, name, tt, lang, ids) + self._get_source.clear_cache(self, uid, name, tt, lang, tr[res_id]) + self._get_source.clear_cache(self, uid, name, tt, lang) + self._get_ids.clear_cache(self, uid, name, tt, lang, ids) cr.execute('delete from ir_translation ' \ 'where lang=%s ' \ @@ -133,7 +133,7 @@ class ir_translation(osv.osv): }) return len(ids) - @tools.cache(skiparg=3) + @tools.ormcache(skiparg=3) def _get_source(self, cr, uid, name, types, lang, source=None): """ Returns the translation for the given combination of name, type, language @@ -183,8 +183,8 @@ class ir_translation(osv.osv): context = {} ids = super(ir_translation, self).create(cursor, user, vals, context=context) for trans_obj in self.read(cursor, user, [ids], ['name','type','res_id','src','lang'], context=context): - self._get_source.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], source=trans_obj['src']) - self._get_ids.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], [trans_obj['res_id']]) + self._get_source.clear_cache(self, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], source=trans_obj['src']) + self._get_ids.clear_cache(self, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], [trans_obj['res_id']]) return ids def write(self, cursor, user, ids, vals, context=None): @@ -194,8 +194,8 @@ class ir_translation(osv.osv): ids = [ids] result = super(ir_translation, self).write(cursor, user, ids, vals, context=context) for trans_obj in self.read(cursor, user, ids, ['name','type','res_id','src','lang'], context=context): - self._get_source.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], source=trans_obj['src']) - self._get_ids.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], [trans_obj['res_id']]) + self._get_source.clear_cache(self, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], source=trans_obj['src']) + self._get_ids.clear_cache(self, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], [trans_obj['res_id']]) return result def unlink(self, cursor, user, ids, context=None): @@ -204,8 +204,8 @@ class ir_translation(osv.osv): if isinstance(ids, (int, long)): ids = [ids] for trans_obj in self.read(cursor, user, ids, ['name','type','res_id','src','lang'], context=context): - self._get_source.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], source=trans_obj['src']) - self._get_ids.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], [trans_obj['res_id']]) + self._get_source.clear_cache(self, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], source=trans_obj['src']) + self._get_ids.clear_cache(self, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], [trans_obj['res_id']]) result = super(ir_translation, self).unlink(cursor, user, ids, context=context) return result diff --git a/openerp/addons/base/res/res_company.py b/openerp/addons/base/res/res_company.py index 0143b03fd2a..bb281b9c0ea 100644 --- a/openerp/addons/base/res/res_company.py +++ b/openerp/addons/base/res/res_company.py @@ -132,7 +132,7 @@ class res_company(osv.osv): ids = self._get_company_children(cr, uid, company) return ids - @tools.cache() + @tools.ormcache() def _get_company_children(self, cr, uid=None, company=None): if not company: return [] @@ -159,7 +159,7 @@ class res_company(osv.osv): # This function restart the cache on the _get_company_children method # def cache_restart(self, cr): - self._get_company_children.clear_cache(cr.dbname) + self._get_company_children.clear_cache(self) def create(self, cr, uid, vals, context=None): if not vals.get('name', False) or vals.get('partner_id', False): diff --git a/openerp/addons/base/res/res_lang.py b/openerp/addons/base/res/res_lang.py index 600f31aead2..f9a7bd00dc5 100644 --- a/openerp/addons/base/res/res_lang.py +++ b/openerp/addons/base/res/res_lang.py @@ -160,7 +160,7 @@ class lang(osv.osv): (_check_format, 'Invalid date/time format directive specified. Please refer to the list of allowed directives, displayed when you edit a language.', ['time_format', 'date_format']) ] - @tools.cache(skiparg=3) + @tools.ormcache(skiparg=3) def _lang_data_get(self, cr, uid, lang_id, monetary=False): conv = localeconv() lang_obj = self.browse(cr, uid, lang_id) @@ -171,7 +171,7 @@ class lang(osv.osv): def write(self, cr, uid, ids, vals, context=None): for lang_id in ids : - self._lang_data_get.clear_cache(cr.dbname,lang_id= lang_id) + self._lang_data_get.clear_cache(self,lang_id= lang_id) return super(lang, self).write(cr, uid, ids, vals, context) def unlink(self, cr, uid, ids, context=None): diff --git a/openerp/addons/base/res/res_user.py b/openerp/addons/base/res/res_user.py index 8a76ba9a6f4..c9eb1da381c 100644 --- a/openerp/addons/base/res/res_user.py +++ b/openerp/addons/base/res/res_user.py @@ -267,7 +267,7 @@ class users(osv.osv): o['password'] = '********' return o result = super(users, self).read(cr, uid, ids, fields, context, load) - canwrite = self.pool.get('ir.model.access').check(cr, uid, 'res.users', 'write', raise_exception=False) + canwrite = self.pool.get('ir.model.access').check(cr, uid, 'res.users', 'write', False) if not canwrite: if isinstance(ids, (int, float)): result = override_password(result) @@ -351,7 +351,7 @@ class users(osv.osv): 'menu_tips':True } - @tools.cache() + @tools.ormcache() def company_get(self, cr, uid, uid2, context=None): return self._get_company(cr, uid, context=context, uid2=uid2) @@ -374,7 +374,7 @@ class users(osv.osv): res = super(users, self).write(cr, uid, ids, values, context=context) # clear caches linked to the users - self.company_get.clear_cache(cr.dbname) + self.company_get.clear_cache(self) self.pool.get('ir.model.access').call_cache_clearing_methods(cr) clear = partial(self.pool.get('ir.rule').clear_cache, cr) map(clear, ids) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 5197f92f3d0..1041e7ac73c 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -1981,7 +1981,7 @@ class orm_template(object): def read_string(self, cr, uid, id, langs, fields=None, context=None): res = {} res2 = {} - self.pool.get('ir.model.access').check(cr, uid, 'ir.translation', 'read', context=context) + self.pool.get('ir.model.access').check(cr, uid, 'ir.translation', 'read') if not fields: fields = self._columns.keys() + self._inherit_fields.keys() #FIXME: collect all calls to _get_source into one SQL call. @@ -2005,7 +2005,7 @@ class orm_template(object): return res def write_string(self, cr, uid, id, langs, vals, context=None): - self.pool.get('ir.model.access').check(cr, uid, 'ir.translation', 'write', context=context) + self.pool.get('ir.model.access').check(cr, uid, 'ir.translation', 'write') #FIXME: try to only call the translation in one SQL for lang in langs: for field in vals: @@ -2312,7 +2312,7 @@ class orm(orm_template): """ context = context or {} - self.pool.get('ir.model.access').check(cr, uid, self._name, 'read', context=context) + self.pool.get('ir.model.access').check(cr, uid, self._name, 'read') if not fields: fields = self._columns.keys() @@ -3122,14 +3122,14 @@ class orm(orm_template): """ ira = self.pool.get('ir.model.access') - write_access = ira.check(cr, user, self._name, 'write', raise_exception=False, context=context) or \ - ira.check(cr, user, self._name, 'create', raise_exception=False, context=context) + write_access = ira.check(cr, user, self._name, 'write', False) or \ + ira.check(cr, user, self._name, 'create', False) return super(orm, self).fields_get(cr, user, fields, context, write_access) def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'): if not context: context = {} - self.pool.get('ir.model.access').check(cr, user, self._name, 'read', context=context) + self.pool.get('ir.model.access').check(cr, user, self._name, 'read') if not fields: fields = list(set(self._columns.keys() + self._inherit_fields.keys())) if isinstance(ids, (int, long)): @@ -3415,7 +3415,7 @@ class orm(orm_template): self._check_concurrency(cr, ids, context) - self.pool.get('ir.model.access').check(cr, uid, self._name, 'unlink', context=context) + self.pool.get('ir.model.access').check(cr, uid, self._name, 'unlink') properties = self.pool.get('ir.property') domain = [('res_id', '=', False), @@ -3549,7 +3549,7 @@ class orm(orm_template): ids = [ids] self._check_concurrency(cr, ids, context) - self.pool.get('ir.model.access').check(cr, user, self._name, 'write', context=context) + self.pool.get('ir.model.access').check(cr, user, self._name, 'write') result = self._store_get_values(cr, user, ids, vals.keys(), context) or [] @@ -3758,7 +3758,7 @@ class orm(orm_template): """ if not context: context = {} - self.pool.get('ir.model.access').check(cr, user, self._name, 'create', context=context) + self.pool.get('ir.model.access').check(cr, user, self._name, 'create') vals = self._add_missing_default_values(cr, user, vals, context) @@ -4214,7 +4214,7 @@ class orm(orm_template): """ if context is None: context = {} - self.pool.get('ir.model.access').check(cr, access_rights_uid or user, self._name, 'read', context=context) + self.pool.get('ir.model.access').check(cr, access_rights_uid or user, self._name, 'read') query = self._where_calc(cr, user, args, context=context) self._apply_ir_rules(cr, user, query, 'read', context=context) diff --git a/openerp/tools/lru.py b/openerp/tools/lru.py index 190fe5e4ff6..aa7b14a745c 100644 --- a/openerp/tools/lru.py +++ b/openerp/tools/lru.py @@ -12,7 +12,7 @@ class LRUNode(object): self.me = me self.next = None -class LRU: +class LRU(object): """ Implementation of a length-limited O(1) LRU queue. Built for and used by PyPE: @@ -113,3 +113,8 @@ class LRU: del self[key] return v + @synchronized() + def clear(self): + self.d = {} + self.first = None + self.last = None diff --git a/openerp/tools/misc.py b/openerp/tools/misc.py index 5aa01d4f267..307cf04ce68 100644 --- a/openerp/tools/misc.py +++ b/openerp/tools/misc.py @@ -639,162 +639,113 @@ class currency(float): # display_value = int(self*(10**(-self.accuracy))/self.rounding)*self.rounding/(10**(-self.accuracy)) # return str(display_value) +class ormcache(object): + """ LRU cache decorator for orm methods + """ -def is_hashable(h): - try: - hash(h) - return True - except TypeError: - return False + def __init__(self, skiparg=2, size=8192, multi=None, timeout=None): + self.skiparg = skiparg + self.size = size + self.method = None + self.stat_miss = 0 + self.stat_hit = 0 + self.stat_err = 0 + + def __call__(self,m): + self.method = m + def lookup(self2, cr, *args): + r = self.lookup(m, m, self2, cr, *args) +# print "lookup-stats hit miss err",self.stat_hit,self.stat_miss,self.stat_err + return r + def clear(self2, *args): + return self.clear(self2, *args) + lookup.clear_cache = self.clear + print "returned",lookup + return lookup + + def lookup(self, cacheid, method, self2, cr, *args): + try: + ormcache = getattr(self2, '_ormcache') + except AttributeError: + ormcache = self2._ormcache = {} + try: + d = ormcache[cacheid] + except KeyError: + d = ormcache[cacheid] = LRU(self.size) + key = args[self.skiparg-2:] + try: + r = d[key] +# print "lookup-hit",self2,cr,key,r + self.stat_hit += 1 + return r + except KeyError: + self.stat_miss += 1 +# print "lookup-miss",self2,cr,key + value = d[args] = method(self2, cr, *args) +# print "lookup-miss-value",value + return value + except TypeError: + self.stat_err += 1 +# print "lookup-typeerror",self2,cr,key + return method(self2, cr, *args) + + def clear(self, self2, *args, **kw): + """ Remove *args entry from the cache or all keys if *args is undefined + """ + try: + ormcache = getattr(self2, '_ormcache') + except AttributeError: + ormcache = self2._ormcache = {} + try: + d = ormcache[self.method] + except KeyError: + d = ormcache[self.method] = LRU(self.size) + d.clear() + +class ormcache_multi(ormcache): + def __init__(self, skiparg=2, size=8192, multi=4): + super(ormcache_multi,self).__init__(skiparg,size) + self.multi = multi - 3 + + def lookup(self, cacheid, method, self2, cr, *args): + superlookup = super(ormcache_multi,self).lookup + args = list(args) + multi = self.multi +# print args,multi + ids = args[multi] + r = {} + miss = [] + + def add_to_miss(_self2, _cr, *_args): + miss.append(_args[multi]) + + for i in ids: + args[multi] = i + r[i] = superlookup(method, add_to_miss, self2, cr, *args) + + args[multi] = miss + r.update(method(self2, cr, *args)) + + for i in miss: + args[multi] = i + key = tuple(args[self.skiparg-2:]) + self2._ormcache[cacheid][key] = r[i] + + return r class dummy_cache(object): """ Cache decorator replacement to actually do no caching. - - This can be useful to benchmark and/or track memory leak. - """ - - def __init__(self, timeout=None, skiparg=2, multi=None, size=8192): + def __init__(self, *l, **kw): pass - - def clear(self, dbname, *args, **kwargs): + def clear(self, *l, **kw): pass - - @classmethod - def clean_caches_for_db(cls, dbname): - pass - def __call__(self, fn): fn.clear_cache = self.clear return fn -class real_cache(object): - """ - Use it as a decorator of the function you plan to cache - Timeout: 0 = no timeout, otherwise in seconds - """ - - __caches = [] - - def __init__(self, timeout=None, skiparg=2, multi=None, size=8192): - assert skiparg >= 2 # at least self and cr - if timeout is None: - self.timeout = config['cache_timeout'] - else: - self.timeout = timeout - self.skiparg = skiparg - self.multi = multi - self.lasttime = time.time() - self.cache = LRU(size) # TODO take size from config - self.fun = None - cache.__caches.append(self) - - - def _generate_keys(self, dbname, kwargs2): - """ - Generate keys depending of the arguments and the self.mutli value - """ - - def to_tuple(d): - pairs = d.items() - pairs.sort(key=lambda (k,v): k) - for i, (k, v) in enumerate(pairs): - if isinstance(v, dict): - pairs[i] = (k, to_tuple(v)) - if isinstance(v, (list, set)): - pairs[i] = (k, tuple(v)) - elif not is_hashable(v): - pairs[i] = (k, repr(v)) - return tuple(pairs) - - if not self.multi: - key = (('dbname', dbname),) + to_tuple(kwargs2) - yield key, None - else: - multis = kwargs2[self.multi][:] - for id in multis: - kwargs2[self.multi] = (id,) - key = (('dbname', dbname),) + to_tuple(kwargs2) - yield key, id - - def _unify_args(self, *args, **kwargs): - # Update named arguments with positional argument values (without self and cr) - kwargs2 = self.fun_default_values.copy() - kwargs2.update(kwargs) - kwargs2.update(dict(zip(self.fun_arg_names, args[self.skiparg-2:]))) - return kwargs2 - - def clear(self, dbname, *args, **kwargs): - """clear the cache for database dbname - if *args and **kwargs are both empty, clear all the keys related to this database - """ - if not args and not kwargs: - keys_to_del = [key for key in self.cache.keys() if key[0][1] == dbname] - else: - kwargs2 = self._unify_args(*args, **kwargs) - keys_to_del = [key for key, _ in self._generate_keys(dbname, kwargs2) if key in self.cache.keys()] - - for key in keys_to_del: - self.cache.pop(key) - - @classmethod - def clean_caches_for_db(cls, dbname): - for c in cls.__caches: - c.clear(dbname) - - def __call__(self, fn): - if self.fun is not None: - raise Exception("Can not use a cache instance on more than one function") - self.fun = fn - - argspec = inspect.getargspec(fn) - self.fun_arg_names = argspec[0][self.skiparg:] - self.fun_default_values = {} - if argspec[3]: - self.fun_default_values = dict(zip(self.fun_arg_names[-len(argspec[3]):], argspec[3])) - - def cached_result(self2, cr, *args, **kwargs): - if time.time()-int(self.timeout) > self.lasttime: - self.lasttime = time.time() - t = time.time()-int(self.timeout) - old_keys = [key for key in self.cache.keys() if self.cache[key][1] < t] - for key in old_keys: - self.cache.pop(key) - - kwargs2 = self._unify_args(*args, **kwargs) - - result = {} - notincache = {} - for key, id in self._generate_keys(cr.dbname, kwargs2): - if key in self.cache: - result[id] = self.cache[key][0] - else: - notincache[id] = key - - if notincache: - if self.multi: - kwargs2[self.multi] = notincache.keys() - - result2 = fn(self2, cr, *args[:self.skiparg-2], **kwargs2) - if not self.multi: - key = notincache[None] - self.cache[key] = (result2, time.time()) - result[None] = result2 - else: - for id in result2: - key = notincache[id] - self.cache[key] = (result2[id], time.time()) - result.update(result2) - - if not self.multi: - return result[None] - return result - - cached_result.clear_cache = self.clear - return cached_result - -# TODO make it an option -cache = real_cache +#ormcache = dummy_cache +cache = dummy_cache def to_xml(s): return s.replace('&','&').replace('<','<').replace('>','>') From b5bf0e8c1c9bb0ad104c292d58d31d657e46aeb5 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Wed, 8 Jun 2011 11:25:15 +0200 Subject: [PATCH 02/56] [IMP] tools.cache cleanup, 15% speedup bzr revid: al@openerp.com-20110608092515-gum2y4snkrcrpjqb --- openerp/addons/base/ir/ir_rule.py | 30 +---- openerp/addons/base/ir/ir_translation.py | 12 +- openerp/tools/cache.py | 149 +++++++++++++++++++++++ openerp/tools/misc.py | 111 +---------------- 4 files changed, 161 insertions(+), 141 deletions(-) create mode 100644 openerp/tools/cache.py diff --git a/openerp/addons/base/ir/ir_rule.py b/openerp/addons/base/ir/ir_rule.py index b62da2ac4ff..86ded0387e0 100644 --- a/openerp/addons/base/ir/ir_rule.py +++ b/openerp/addons/base/ir/ir_rule.py @@ -134,22 +134,7 @@ class ir_rule(osv.osv): return [] def clear_cache(self, cr, uid): - cr.execute("""SELECT DISTINCT m.model - FROM ir_rule r - JOIN ir_model m - ON r.model_id = m.id - WHERE r.global - OR EXISTS (SELECT 1 - FROM rule_group_rel g_rel - JOIN res_groups_users_rel u_rel - ON g_rel.group_id = u_rel.gid - WHERE g_rel.rule_group_id = r.id - AND u_rel.uid = %s) - """, (uid,)) - models = map(itemgetter(0), cr.fetchall()) - clear = partial(self._compute_domain.clear_cache, self, uid) - [clear(model, mode) for model in models for mode in self._MODES] - + self._compute_domain.clear_cache(self) def domain_get(self, cr, uid, model_name, mode='read', context=None): dom = self._compute_domain(cr, uid, model_name, mode) @@ -164,20 +149,17 @@ class ir_rule(osv.osv): def unlink(self, cr, uid, ids, context=None): res = super(ir_rule, self).unlink(cr, uid, ids, context=context) - # Restart the cache on the _compute_domain method of ir.rule - self._compute_domain.clear_cache(self) + self.clear_cache() return res - def create(self, cr, user, vals, context=None): - res = super(ir_rule, self).create(cr, user, vals, context=context) - # Restart the cache on the _compute_domain method of ir.rule - self._compute_domain.clear_cache(self) + def create(self, cr, uid, vals, context=None): + res = super(ir_rule, self).create(cr, uid, vals, context=context) + self.clear_cache(cr, uid) return res def write(self, cr, uid, ids, vals, context=None): res = super(ir_rule, self).write(cr, uid, ids, vals, context=context) - # Restart the cache on the _compute_domain method - self._compute_domain.clear_cache(self) + self.clear_cache(cr,uid) return res ir_rule() diff --git a/openerp/addons/base/ir/ir_translation.py b/openerp/addons/base/ir/ir_translation.py index 0e6374b0143..02aa8f4a8fe 100644 --- a/openerp/addons/base/ir/ir_translation.py +++ b/openerp/addons/base/ir/ir_translation.py @@ -92,7 +92,7 @@ class ir_translation(osv.osv): cr.execute('CREATE INDEX ir_translation_ltn ON ir_translation (name, lang, type)') cr.commit() - @tools.ormcache_multi(skiparg=3, multi=7) + @tools.ormcache_multi(skiparg=3, multi=6) def _get_ids(self, cr, uid, name, tt, lang, ids): translations = dict.fromkeys(ids, False) if ids: @@ -178,13 +178,11 @@ class ir_translation(osv.osv): return tools.ustr(source) return trad - def create(self, cursor, user, vals, context=None): + def create(self, cr, uid, vals, context=None): if not context: context = {} - ids = super(ir_translation, self).create(cursor, user, vals, context=context) - for trans_obj in self.read(cursor, user, [ids], ['name','type','res_id','src','lang'], context=context): - self._get_source.clear_cache(self, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], source=trans_obj['src']) - self._get_ids.clear_cache(self, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], [trans_obj['res_id']]) + ids = super(ir_translation, self).create(cr, uid, vals, context=context) + self._get_source.clear_cache(self, vals.get('name',0), vals.get('type',0), vals.get('lang',0), vals.get('src',0)) return ids def write(self, cursor, user, ids, vals, context=None): @@ -193,8 +191,8 @@ class ir_translation(osv.osv): if isinstance(ids, (int, long)): ids = [ids] result = super(ir_translation, self).write(cursor, user, ids, vals, context=context) + self._get_source.clear_cache(self, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], source=trans_obj['src']) for trans_obj in self.read(cursor, user, ids, ['name','type','res_id','src','lang'], context=context): - self._get_source.clear_cache(self, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], source=trans_obj['src']) self._get_ids.clear_cache(self, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], [trans_obj['res_id']]) return result diff --git a/openerp/tools/cache.py b/openerp/tools/cache.py new file mode 100644 index 00000000000..db4115aef36 --- /dev/null +++ b/openerp/tools/cache.py @@ -0,0 +1,149 @@ +import lru + +class ormcache(object): + """ LRU cache decorator for orm methods + """ + + def __init__(self, skiparg=2, size=8192, multi=None, timeout=None): + self.skiparg = skiparg + self.size = size + self.method = None + self.stat_miss = 0 + self.stat_hit = 0 + self.stat_err = 0 + + def __call__(self,m): + self.method = m + def lookup(self2, cr, *args): + r = self.lookup(self2, cr, *args) + #self.stat() + return r + def clear(self2, *args): + return self.clear(self2, *args) + lookup.clear_cache = self.clear + #print "lookup-func",lookup + return lookup + + def stat(self): + print "lookup-stats hit=%s miss=%s err=%s ratio=%.1f" % (self.stat_hit,self.stat_miss,self.stat_err, (100*float(self.stat_hit))/(self.stat_miss+self.stat_hit) ) + + def lru(self, self2): + try: + ormcache = getattr(self2, '_ormcache') + except AttributeError: + ormcache = self2._ormcache = {} + try: + d = ormcache[self.method] + except KeyError: + d = ormcache[self.method] = lru.LRU(self.size) + return d + + def lookup(self, self2, cr, *args): + d = self.lru(self2) + key = args[self.skiparg-2:] + try: + r = d[key] + #print "lookup-hit",self2,cr,key,r + self.stat_hit += 1 + return r + except KeyError: + self.stat_miss += 1 + #print "lookup-miss",self2,cr,key + value = d[args] = self.method(self2, cr, *args) + #print "lookup-miss-value",value + return value + except TypeError: + self.stat_err += 1 + #print "lookup-error",self2,cr,key + return self.method(self2, cr, *args) + + def clear(self, self2, *args): + """ Remove *args entry from the cache or all keys if *args is undefined + """ + d = self.lru(self2) + if args: + try: + key = args[self.skiparg-2:] + #print "del",key + del d[key] + except KeyError: + pass + else: + d.clear() + +class ormcache_multi(ormcache): + def __init__(self, skiparg=2, size=8192, multi=3): + super(ormcache_multi,self).__init__(skiparg,size) + self.multi = multi - 2 + + def lookup(self, self2, cr, *args): + d = self.lru(self2) + args = list(args) + multi = self.multi + #print args, multi + ids = args[multi] + r = {} + miss = [] + + for i in ids: + args[multi] = i + key = tuple(args[self.skiparg-2:]) + try: + r[i] = d[key] + #print "lookup-hit",self2,cr,key,r[i] + self.stat_hit += 1 + except Exception: + self.stat_miss += 1 + miss.append(i) + #print "lookup-miss",self2,cr,key + + if miss: + args[multi] = miss + r.update(self.method(self2, cr, *args)) + + for i in miss: + args[multi] = i + key = tuple(args[self.skiparg-2:]) + d[key] = r[i] + + return r + +class dummy_cache(object): + """ Cache decorator replacement to actually do no caching. + """ + def __init__(self, *l, **kw): + pass + def __call__(self, fn): + fn.clear_cache = self.clear + return fn + def clear(self, *l, **kw): + pass + +#ormcache = dummy_cache +cache = dummy_cache + +if __name__ == '__main__': + + class A(): + @ormcache() + def m(self,a,b): + print "A::m(", self,a,b + return 1 + + @ormcache_multi(multi=3) + def n(self,cr,uid,ids): + print "m", self,cr,uid,ids + return dict([(i,i) for i in ids]) + + a=A() + #r=a.m(1,2) + #r=a.m(1,2) + r=a.n("cr",1,[1,2,3,4]) + r=a.n("cr",1,[1,2]) + print r + for i in a._ormcache: + print a._ormcache[i].d + a.n.clear_cache(a,1,1) + r=a.n("cr",1,[1,2]) + print r + #r=a.n("cr",1,[1,2]) diff --git a/openerp/tools/misc.py b/openerp/tools/misc.py index 307cf04ce68..48a9a936783 100644 --- a/openerp/tools/misc.py +++ b/openerp/tools/misc.py @@ -57,7 +57,7 @@ except ImportError: import openerp.loglevels as loglevels from config import config -from lru import LRU +from cache import * # get_encodings, ustr and exception_to_unicode were originally from tools.misc. # There are moved to loglevels until we refactor tools. @@ -622,7 +622,6 @@ class UpdateableDict(local): def __ne__(self, y): return self.dict.__ne__(y) - # Don't use ! Use res.currency.round() class currency(float): @@ -639,114 +638,6 @@ class currency(float): # display_value = int(self*(10**(-self.accuracy))/self.rounding)*self.rounding/(10**(-self.accuracy)) # return str(display_value) -class ormcache(object): - """ LRU cache decorator for orm methods - """ - - def __init__(self, skiparg=2, size=8192, multi=None, timeout=None): - self.skiparg = skiparg - self.size = size - self.method = None - self.stat_miss = 0 - self.stat_hit = 0 - self.stat_err = 0 - - def __call__(self,m): - self.method = m - def lookup(self2, cr, *args): - r = self.lookup(m, m, self2, cr, *args) -# print "lookup-stats hit miss err",self.stat_hit,self.stat_miss,self.stat_err - return r - def clear(self2, *args): - return self.clear(self2, *args) - lookup.clear_cache = self.clear - print "returned",lookup - return lookup - - def lookup(self, cacheid, method, self2, cr, *args): - try: - ormcache = getattr(self2, '_ormcache') - except AttributeError: - ormcache = self2._ormcache = {} - try: - d = ormcache[cacheid] - except KeyError: - d = ormcache[cacheid] = LRU(self.size) - key = args[self.skiparg-2:] - try: - r = d[key] -# print "lookup-hit",self2,cr,key,r - self.stat_hit += 1 - return r - except KeyError: - self.stat_miss += 1 -# print "lookup-miss",self2,cr,key - value = d[args] = method(self2, cr, *args) -# print "lookup-miss-value",value - return value - except TypeError: - self.stat_err += 1 -# print "lookup-typeerror",self2,cr,key - return method(self2, cr, *args) - - def clear(self, self2, *args, **kw): - """ Remove *args entry from the cache or all keys if *args is undefined - """ - try: - ormcache = getattr(self2, '_ormcache') - except AttributeError: - ormcache = self2._ormcache = {} - try: - d = ormcache[self.method] - except KeyError: - d = ormcache[self.method] = LRU(self.size) - d.clear() - -class ormcache_multi(ormcache): - def __init__(self, skiparg=2, size=8192, multi=4): - super(ormcache_multi,self).__init__(skiparg,size) - self.multi = multi - 3 - - def lookup(self, cacheid, method, self2, cr, *args): - superlookup = super(ormcache_multi,self).lookup - args = list(args) - multi = self.multi -# print args,multi - ids = args[multi] - r = {} - miss = [] - - def add_to_miss(_self2, _cr, *_args): - miss.append(_args[multi]) - - for i in ids: - args[multi] = i - r[i] = superlookup(method, add_to_miss, self2, cr, *args) - - args[multi] = miss - r.update(method(self2, cr, *args)) - - for i in miss: - args[multi] = i - key = tuple(args[self.skiparg-2:]) - self2._ormcache[cacheid][key] = r[i] - - return r - -class dummy_cache(object): - """ Cache decorator replacement to actually do no caching. - """ - def __init__(self, *l, **kw): - pass - def clear(self, *l, **kw): - pass - def __call__(self, fn): - fn.clear_cache = self.clear - return fn - -#ormcache = dummy_cache -cache = dummy_cache - def to_xml(s): return s.replace('&','&').replace('<','<').replace('>','>') From 2f4330bbb32ec294843158fb16f50ff08e55314c Mon Sep 17 00:00:00 2001 From: Mustufa Rangwala Date: Thu, 14 Jul 2011 14:57:37 +0530 Subject: [PATCH 03/56] [ADD] Base: add res.currency.rate.type object and its m2o on res.currency.rate bzr revid: mra@mra-laptop-20110714092737-9jlk0xjc3hkb4rog --- openerp/addons/base/res/res_currency.py | 11 +++++++++++ openerp/addons/base/res/res_currency_view.xml | 1 + 2 files changed, 12 insertions(+) diff --git a/openerp/addons/base/res/res_currency.py b/openerp/addons/base/res/res_currency.py index d81248a735d..fa718ddffbc 100644 --- a/openerp/addons/base/res/res_currency.py +++ b/openerp/addons/base/res/res_currency.py @@ -133,6 +133,15 @@ class res_currency(osv.osv): res_currency() +class res_currency_rate_type(osv.osv): + _name = "res.currency.rate.type" + _description = "Currency Rate Type" + _columns = { + 'name': fields.char('Name', size=32, required=True), + } + +res_currency_rate_type() + class res_currency_rate(osv.osv): _name = "res.currency.rate" _description = "Currency Rate" @@ -141,11 +150,13 @@ class res_currency_rate(osv.osv): 'rate': fields.float('Rate', digits=(12,6), required=True, help='The rate of the currency to the currency of rate 1'), 'currency_id': fields.many2one('res.currency', 'Currency', readonly=True), + 'currency_rate_type_id': fields.many2one('res.currency.rate.type', 'Currency Rate Type'), } _defaults = { 'name': lambda *a: time.strftime('%Y-%m-%d'), } _order = "name desc" + res_currency_rate() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/res/res_currency_view.xml b/openerp/addons/base/res/res_currency_view.xml index 37a8693e5b3..346da2488c9 100644 --- a/openerp/addons/base/res/res_currency_view.xml +++ b/openerp/addons/base/res/res_currency_view.xml @@ -48,6 +48,7 @@
+ From 72db8f87cbacb53b7f098531aa0b9607516ed353 Mon Sep 17 00:00:00 2001 From: Mustufa Rangwala Date: Thu, 14 Jul 2011 16:15:17 +0530 Subject: [PATCH 04/56] [IMP] Base: add argument on compute method bzr revid: mra@mra-laptop-20110714104517-11w0ptxmob5s481n --- openerp/addons/base/res/res_currency.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/openerp/addons/base/res/res_currency.py b/openerp/addons/base/res/res_currency.py index fa718ddffbc..957c0fb625f 100644 --- a/openerp/addons/base/res/res_currency.py +++ b/openerp/addons/base/res/res_currency.py @@ -43,6 +43,7 @@ class res_currency(osv.osv): res[id] = rate else: res[id] = 0 + return res _name = "res.currency" _description = "Currency" @@ -68,7 +69,7 @@ class res_currency(osv.osv): _order = "name" def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'): - res=super(osv.osv, self).read(cr, user, ids, fields, context, load) + res = super(osv.osv, self).read(cr, user, ids, fields, context, load) for r in res: if r.__contains__('rate_ids'): rates=r['rate_ids'] @@ -76,6 +77,7 @@ class res_currency(osv.osv): currency_rate_obj= self.pool.get('res.currency.rate') currency_date = currency_rate_obj.read(cr,user,rates[0],['name'])['name'] r['date'] = currency_date + return res def name_get(self, cr, uid, ids, context=None): @@ -109,13 +111,17 @@ class res_currency(osv.osv): raise osv.except_osv(_('Error'), _('No rate found \n' \ 'for the currency: %s \n' \ 'at the date: %s') % (currency_symbol, date)) + return to_currency.rate/from_currency.rate - def compute(self, cr, uid, from_currency_id, to_currency_id, from_amount, round=True, context=None): + def compute(self, cr, uid, from_currency_id, to_currency_id, from_amount, round=True, rate_type=False, context=None): if not from_currency_id: from_currency_id = to_currency_id if not to_currency_id: to_currency_id = from_currency_id + + if rate_type: + context.update({'currency_rate_type_id': rate_type}) xc = self.browse(cr, uid, [from_currency_id,to_currency_id], context=context) from_currency = (xc[0].id == from_currency_id and xc[0]) or xc[1] to_currency = (xc[0].id == to_currency_id and xc[0]) or xc[1] From 5c7075cac6ae44b6daf2bb55793f10aa855c0a44 Mon Sep 17 00:00:00 2001 From: "Ujjvala Collins (OpenERP)" Date: Tue, 12 Jul 2011 17:06:01 +0530 Subject: [PATCH 05/56] [IMP] base: Added a condition to check currency rate type. bzr revid: uco@tinyerp.com-20110712113601-slvo0c3590a7dkxf --- openerp/addons/base/res/res_currency.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openerp/addons/base/res/res_currency.py b/openerp/addons/base/res/res_currency.py index 957c0fb625f..46b4dd45207 100644 --- a/openerp/addons/base/res/res_currency.py +++ b/openerp/addons/base/res/res_currency.py @@ -36,8 +36,12 @@ class res_currency(osv.osv): else: date = time.strftime('%Y-%m-%d') date = date or time.strftime('%Y-%m-%d') + currency_rate_type_id = context.get('currency_rate_type_id', 0) for id in ids: - cr.execute("SELECT currency_id, rate FROM res_currency_rate WHERE currency_id = %s AND name <= %s ORDER BY name desc LIMIT 1" ,(id, date)) + cr.execute("SELECT currency_id, rate FROM res_currency_rate "\ + "WHERE currency_id = %s AND name <= %s AND currency_rate_type_id = %s "\ + "ORDER BY name desc LIMIT 1" ,(id, date, currency_rate_type_id)) + if cr.rowcount: id, rate = cr.fetchall()[0] res[id] = rate From b9cc3d22b6c9cd4f79c05aa4a91c054494392467 Mon Sep 17 00:00:00 2001 From: "Ujjvala Collins (OpenERP)" Date: Tue, 12 Jul 2011 18:12:53 +0530 Subject: [PATCH 06/56] [IMP] base: Improved currency rate function to avoid sql query. bzr revid: uco@tinyerp.com-20110712124253-vy1g8lq40jsdmyi8 --- openerp/addons/base/res/res_currency.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/openerp/addons/base/res/res_currency.py b/openerp/addons/base/res/res_currency.py index 46b4dd45207..9d6b183bba8 100644 --- a/openerp/addons/base/res/res_currency.py +++ b/openerp/addons/base/res/res_currency.py @@ -28,6 +28,7 @@ from tools.translate import _ class res_currency(osv.osv): def _current_rate(self, cr, uid, ids, name, arg, context=None): + currency_rate_obj = self.pool.get('res.currency.rate') if context is None: context = {} res = {} @@ -36,15 +37,16 @@ class res_currency(osv.osv): else: date = time.strftime('%Y-%m-%d') date = date or time.strftime('%Y-%m-%d') - currency_rate_type_id = context.get('currency_rate_type_id', 0) + domain = [('currency_id','in',ids), ('name','<=',date)] + currency_rate_type_id = context.get('currency_rate_type_id', False) + if currency_rate_type_id: + domain.append(('currency_rate_type_id','=',currency_rate_type_id)) + curr_rate_ids = currency_rate_obj.search(cr, uid, domain, context=context) for id in ids: - cr.execute("SELECT currency_id, rate FROM res_currency_rate "\ - "WHERE currency_id = %s AND name <= %s AND currency_rate_type_id = %s "\ - "ORDER BY name desc LIMIT 1" ,(id, date, currency_rate_type_id)) - - if cr.rowcount: - id, rate = cr.fetchall()[0] - res[id] = rate + if curr_rate_ids: + for cur in currency_rate_obj.browse(cr, uid, curr_rate_ids, context=context): + if cur.currency_id.id == id: + res[id] = cur.rate else: res[id] = 0 From a6b7507ae5b4e4385ca2d34305be3293e29b1659 Mon Sep 17 00:00:00 2001 From: "Ujjvala Collins (OpenERP)" Date: Wed, 13 Jul 2011 11:05:03 +0530 Subject: [PATCH 07/56] [IMP] base: Improved _currency_rate function. bzr revid: uco@tinyerp.com-20110713053503-rejienqc30ocr78g --- openerp/addons/base/res/res_currency.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/openerp/addons/base/res/res_currency.py b/openerp/addons/base/res/res_currency.py index 9d6b183bba8..e4b5c73bd02 100644 --- a/openerp/addons/base/res/res_currency.py +++ b/openerp/addons/base/res/res_currency.py @@ -41,14 +41,14 @@ class res_currency(osv.osv): currency_rate_type_id = context.get('currency_rate_type_id', False) if currency_rate_type_id: domain.append(('currency_rate_type_id','=',currency_rate_type_id)) - curr_rate_ids = currency_rate_obj.search(cr, uid, domain, context=context) + curr_rate_ids = currency_rate_obj.search(cr, uid, domain, order='name desc', context=context) + curr_rates = currency_rate_obj.browse(cr, uid, curr_rate_ids, context=context) for id in ids: - if curr_rate_ids: - for cur in currency_rate_obj.browse(cr, uid, curr_rate_ids, context=context): - if cur.currency_id.id == id: - res[id] = cur.rate - else: - res[id] = 0 + res[id] = 0 + for cur in curr_rates: + if cur.currency_id.id == id: + res[id] = cur.rate + break return res _name = "res.currency" From 33947346e4393d7861c792e08452ec74e3da20e4 Mon Sep 17 00:00:00 2001 From: Mustufa Rangwala Date: Fri, 15 Jul 2011 11:25:41 +0530 Subject: [PATCH 08/56] [IMP] Base: Currency improve code bzr revid: mra@mra-laptop-20110715055541-il3hhp42b9jiojo4 --- openerp/addons/base/res/res_currency.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/openerp/addons/base/res/res_currency.py b/openerp/addons/base/res/res_currency.py index e4b5c73bd02..30d93921bd3 100644 --- a/openerp/addons/base/res/res_currency.py +++ b/openerp/addons/base/res/res_currency.py @@ -29,18 +29,17 @@ from tools.translate import _ class res_currency(osv.osv): def _current_rate(self, cr, uid, ids, name, arg, context=None): currency_rate_obj = self.pool.get('res.currency.rate') + res = {} if context is None: context = {} - res = {} if 'date' in context: date = context['date'] else: date = time.strftime('%Y-%m-%d') - date = date or time.strftime('%Y-%m-%d') - domain = [('currency_id','in',ids), ('name','<=',date)] + domain = [('currency_id', 'in', ids), ('name', '<=', date)] currency_rate_type_id = context.get('currency_rate_type_id', False) if currency_rate_type_id: - domain.append(('currency_rate_type_id','=',currency_rate_type_id)) + domain.append(('currency_rate_type_id', '=', currency_rate_type_id)) curr_rate_ids = currency_rate_obj.search(cr, uid, domain, order='name desc', context=context) curr_rates = currency_rate_obj.browse(cr, uid, curr_rate_ids, context=context) for id in ids: @@ -49,8 +48,8 @@ class res_currency(osv.osv): if cur.currency_id.id == id: res[id] = cur.rate break - return res + _name = "res.currency" _description = "Currency" _columns = { @@ -75,15 +74,14 @@ class res_currency(osv.osv): _order = "name" def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'): + currency_rate_obj= self.pool.get('res.currency.rate') res = super(osv.osv, self).read(cr, user, ids, fields, context, load) for r in res: if r.__contains__('rate_ids'): rates=r['rate_ids'] if rates: - currency_rate_obj= self.pool.get('res.currency.rate') - currency_date = currency_rate_obj.read(cr,user,rates[0],['name'])['name'] + currency_date = currency_rate_obj.read(cr, user, rates[0], ['name'])['name'] r['date'] = currency_date - return res def name_get(self, cr, uid, ids, context=None): From efe44324d194c7e58b324ae8d9f18c533897d0bf Mon Sep 17 00:00:00 2001 From: "Ujjvala Collins (OpenERP)" Date: Fri, 15 Jul 2011 11:58:37 +0530 Subject: [PATCH 09/56] [ADD] base: Added view and menu item for currency rate type object. bzr revid: uco@tinyerp.com-20110715062837-bw70on2op2b0pv1z --- openerp/addons/base/res/res_currency_view.xml | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/openerp/addons/base/res/res_currency_view.xml b/openerp/addons/base/res/res_currency_view.xml index 346da2488c9..63a55c0fddf 100644 --- a/openerp/addons/base/res/res_currency_view.xml +++ b/openerp/addons/base/res/res_currency_view.xml @@ -67,5 +67,28 @@ + + + res.currency.rate.type.form + res.currency.rate.type + form + +
+ + +
+
+ + + Currency Rate Type + res.currency.rate.type + form + tree,form + + + + From 416b2693ac0185d0d706c805319a3a3bcc3104d3 Mon Sep 17 00:00:00 2001 From: "Ujjvala Collins (OpenERP)" Date: Fri, 19 Aug 2011 16:37:19 +0530 Subject: [PATCH 10/56] [IMP] base: Improved arguments in compute method to avoid error of No rate found. bzr revid: uco@tinyerp.com-20110819110719-r82nsaui8a2kk58i --- openerp/addons/base/res/res_currency.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openerp/addons/base/res/res_currency.py b/openerp/addons/base/res/res_currency.py index 30d93921bd3..5e69daddb13 100644 --- a/openerp/addons/base/res/res_currency.py +++ b/openerp/addons/base/res/res_currency.py @@ -118,17 +118,17 @@ class res_currency(osv.osv): return to_currency.rate/from_currency.rate - def compute(self, cr, uid, from_currency_id, to_currency_id, from_amount, round=True, rate_type=False, context=None): + def compute(self, cr, uid, from_currency_id, to_currency_id, from_amount, + round=True, currency_rate_type_from=False, currency_rate_type_to=False, context=None): if not from_currency_id: from_currency_id = to_currency_id if not to_currency_id: to_currency_id = from_currency_id - if rate_type: - context.update({'currency_rate_type_id': rate_type}) - xc = self.browse(cr, uid, [from_currency_id,to_currency_id], context=context) + xc = self.browse(cr, uid, [from_currency_id], context={'currency_rate_type_id': currency_rate_type_from}) + xc1 = self.browse(cr, uid, [to_currency_id], context={'currency_rate_type_id': currency_rate_type_to}) from_currency = (xc[0].id == from_currency_id and xc[0]) or xc[1] - to_currency = (xc[0].id == to_currency_id and xc[0]) or xc[1] + to_currency = (xc1[0].id == to_currency_id and xc1[0]) or xc1[1] if to_currency_id == from_currency_id: if round: return self.round(cr, uid, to_currency, from_amount) From bd5cb5e54af9a311753037b96f032503a35e65bc Mon Sep 17 00:00:00 2001 From: "Ujjvala Collins (OpenERP)" Date: Tue, 23 Aug 2011 17:31:16 +0530 Subject: [PATCH 11/56] [IMP] base: Improved code to update the context. bzr revid: uco@tinyerp.com-20110823120116-6mrgalyg77jthxnt --- openerp/addons/base/res/res_currency.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/openerp/addons/base/res/res_currency.py b/openerp/addons/base/res/res_currency.py index 5e69daddb13..8a8067c6ff4 100644 --- a/openerp/addons/base/res/res_currency.py +++ b/openerp/addons/base/res/res_currency.py @@ -125,8 +125,14 @@ class res_currency(osv.osv): if not to_currency_id: to_currency_id = from_currency_id - xc = self.browse(cr, uid, [from_currency_id], context={'currency_rate_type_id': currency_rate_type_from}) - xc1 = self.browse(cr, uid, [to_currency_id], context={'currency_rate_type_id': currency_rate_type_to}) + context.update({'currency_rate_type_id': False}) + if currency_rate_type_from: + context.update({'currency_rate_type_id': currency_rate_type_from}) + if currency_rate_type_to: + context.update({'currency_rate_type_id': currency_rate_type_to}) + + xc = self.browse(cr, uid, [from_currency_id], context=context) + xc1 = self.browse(cr, uid, [to_currency_id], context=context) from_currency = (xc[0].id == from_currency_id and xc[0]) or xc[1] to_currency = (xc1[0].id == to_currency_id and xc1[0]) or xc1[1] if to_currency_id == from_currency_id: From 8de550dea8de6316b760f9a366cb59d060e053c3 Mon Sep 17 00:00:00 2001 From: "Amit Bhavsar (Open ERP)" Date: Wed, 24 Aug 2011 11:07:29 +0530 Subject: [PATCH 12/56] [usability],hide the partner categories in simple view bzr revid: amb@tinyerp.com-20110824053729-dkyk9e282azevs6q --- openerp/addons/base/res/partner/partner_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/res/partner/partner_view.xml b/openerp/addons/base/res/partner/partner_view.xml index 763147fb47e..8d56087fd6c 100644 --- a/openerp/addons/base/res/partner/partner_view.xml +++ b/openerp/addons/base/res/partner/partner_view.xml @@ -584,7 +584,7 @@ Manage the partner categories in order to better classify them for tracking and analysis purposes. A partner may belong to several categories and categories have a hierarchy structure: a partner belonging to a category also belong to his parent category. - + Date: Wed, 24 Aug 2011 11:14:16 +0530 Subject: [PATCH 13/56] [REF] base: Changed code to avoid overriding of context values. bzr revid: uco@tinyerp.com-20110824054416-ngrtkk5oh1v9jgb3 --- openerp/addons/base/res/res_currency.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/openerp/addons/base/res/res_currency.py b/openerp/addons/base/res/res_currency.py index 8a8067c6ff4..13bb14d0578 100644 --- a/openerp/addons/base/res/res_currency.py +++ b/openerp/addons/base/res/res_currency.py @@ -125,13 +125,9 @@ class res_currency(osv.osv): if not to_currency_id: to_currency_id = from_currency_id - context.update({'currency_rate_type_id': False}) - if currency_rate_type_from: - context.update({'currency_rate_type_id': currency_rate_type_from}) - if currency_rate_type_to: - context.update({'currency_rate_type_id': currency_rate_type_to}) - + context.update({'currency_rate_type_id': currency_rate_type_from}) xc = self.browse(cr, uid, [from_currency_id], context=context) + context.update({'currency_rate_type_id': currency_rate_type_to}) xc1 = self.browse(cr, uid, [to_currency_id], context=context) from_currency = (xc[0].id == from_currency_id and xc[0]) or xc[1] to_currency = (xc1[0].id == to_currency_id and xc1[0]) or xc1[1] From 2ef83855446422320dea2bc3f9739647db523bfe Mon Sep 17 00:00:00 2001 From: "Ujjvala Collins (OpenERP)" Date: Wed, 24 Aug 2011 14:40:22 +0530 Subject: [PATCH 14/56] [FIX] base: Fixed currency rate argument problem in context. bzr revid: uco@tinyerp.com-20110824091022-0n1iwkefv2h4nh74 --- openerp/addons/base/res/res_currency.py | 32 ++++++++++++++++--------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/openerp/addons/base/res/res_currency.py b/openerp/addons/base/res/res_currency.py index 13bb14d0578..495a931f91d 100644 --- a/openerp/addons/base/res/res_currency.py +++ b/openerp/addons/base/res/res_currency.py @@ -103,41 +103,51 @@ class res_currency(osv.osv): def is_zero(self, cr, uid, currency, amount): return abs(self.round(cr, uid, currency, amount)) < currency.rounding - def _get_conversion_rate(self, cr, uid, from_currency, to_currency, context=None): + def _get_conversion_rate(self, cr, uid, from_currency_rate, to_currency_rate, context=None): if context is None: context = {} - if from_currency['rate'] == 0 or to_currency['rate'] == 0: + if from_currency_rate == 0 or to_currency_rate == 0: date = context.get('date', time.strftime('%Y-%m-%d')) - if from_currency['rate'] == 0: - currency_symbol = from_currency.symbol + if from_currency_rate == 0: + currency_symbol = context.get('from_curr_symbol') else: - currency_symbol = to_currency.symbol + currency_symbol = context.get('to_curr_symbol') raise osv.except_osv(_('Error'), _('No rate found \n' \ 'for the currency: %s \n' \ 'at the date: %s') % (currency_symbol, date)) - return to_currency.rate/from_currency.rate + return to_currency_rate/from_currency_rate def compute(self, cr, uid, from_currency_id, to_currency_id, from_amount, round=True, currency_rate_type_from=False, currency_rate_type_to=False, context=None): + if not context: + context = {} if not from_currency_id: from_currency_id = to_currency_id if not to_currency_id: to_currency_id = from_currency_id - context.update({'currency_rate_type_id': currency_rate_type_from}) - xc = self.browse(cr, uid, [from_currency_id], context=context) - context.update({'currency_rate_type_id': currency_rate_type_to}) - xc1 = self.browse(cr, uid, [to_currency_id], context=context) + ctx1 = context.copy() + ctx1.update({'currency_rate_type_id': currency_rate_type_from}) + xc = self.browse(cr, uid, [from_currency_id], context=ctx1) from_currency = (xc[0].id == from_currency_id and xc[0]) or xc[1] + from_currency_rate = from_currency['rate'] + context.update({'from_curr_symbol': from_currency.symbol}) + + ctx2 = context.copy() + ctx2.update({'currency_rate_type_id': currency_rate_type_to}) + xc1 = self.browse(cr, uid, [to_currency_id], context=ctx2) to_currency = (xc1[0].id == to_currency_id and xc1[0]) or xc1[1] + to_currency_rate = to_currency['rate'] + context.update({'to_curr_symbol': to_currency.symbol}) + if to_currency_id == from_currency_id: if round: return self.round(cr, uid, to_currency, from_amount) else: return from_amount else: - rate = self._get_conversion_rate(cr, uid, from_currency, to_currency, context=context) + rate = self._get_conversion_rate(cr, uid, from_currency_rate, to_currency_rate, context=context) if round: return self.round(cr, uid, to_currency, from_amount * rate) else: From b687cc3bb4c035cce3975d49313e96b76a768da2 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Wed, 24 Aug 2011 17:01:22 +0200 Subject: [PATCH 15/56] [FIX] remove unused clear function bzr revid: al@openerp.com-20110824150122-ejryb7ni1l92d1hp --- openerp/tools/cache.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openerp/tools/cache.py b/openerp/tools/cache.py index db4115aef36..b9323fa0d02 100644 --- a/openerp/tools/cache.py +++ b/openerp/tools/cache.py @@ -18,8 +18,6 @@ class ormcache(object): r = self.lookup(self2, cr, *args) #self.stat() return r - def clear(self2, *args): - return self.clear(self2, *args) lookup.clear_cache = self.clear #print "lookup-func",lookup return lookup From 362399c6ac4c71ea5ac1fa68b81d47e75e77219b Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Wed, 24 Aug 2011 17:29:05 +0200 Subject: [PATCH 16/56] [FIX] remove cache on used function bzr revid: al@openerp.com-20110824152905-8en0wclyumjz5105 --- openerp/addons/base/res/res_user.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openerp/addons/base/res/res_user.py b/openerp/addons/base/res/res_user.py index c9eb1da381c..a7e28730657 100644 --- a/openerp/addons/base/res/res_user.py +++ b/openerp/addons/base/res/res_user.py @@ -351,7 +351,6 @@ class users(osv.osv): 'menu_tips':True } - @tools.ormcache() def company_get(self, cr, uid, uid2, context=None): return self._get_company(cr, uid, context=context, uid2=uid2) From 8d08cbf5610bd2df8b9186f2cc3b05e33b191d02 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Wed, 24 Aug 2011 17:30:42 +0200 Subject: [PATCH 17/56] [FIX] remove cache on used function bzr revid: al@openerp.com-20110824153042-w6wgegxjruu06ln1 --- openerp/addons/base/res/res_user.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openerp/addons/base/res/res_user.py b/openerp/addons/base/res/res_user.py index a7e28730657..dc672fc5146 100644 --- a/openerp/addons/base/res/res_user.py +++ b/openerp/addons/base/res/res_user.py @@ -373,7 +373,6 @@ class users(osv.osv): res = super(users, self).write(cr, uid, ids, values, context=context) # clear caches linked to the users - self.company_get.clear_cache(self) self.pool.get('ir.model.access').call_cache_clearing_methods(cr) clear = partial(self.pool.get('ir.rule').clear_cache, cr) map(clear, ids) From 93f9a0b0cd51595e8706f4c5faec87ee487e5070 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Wed, 24 Aug 2011 18:19:18 +0200 Subject: [PATCH 18/56] [IMP] ir_rule distribute clear_cache bzr revid: al@openerp.com-20110824161918-dkexqhuc1mzpx9fs --- openerp/addons/base/ir/ir_rule.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/openerp/addons/base/ir/ir_rule.py b/openerp/addons/base/ir/ir_rule.py index 1c43227a76e..d7144cfa01b 100644 --- a/openerp/addons/base/ir/ir_rule.py +++ b/openerp/addons/base/ir/ir_rule.py @@ -138,9 +138,6 @@ class ir_rule(osv.osv): return domain return [] - def clear_cache(self, cr, uid): - self._compute_domain.clear_cache(self) - def domain_get(self, cr, uid, model_name, mode='read', context=None): dom = self._compute_domain(cr, uid, model_name, mode) if dom: @@ -154,17 +151,17 @@ class ir_rule(osv.osv): def unlink(self, cr, uid, ids, context=None): res = super(ir_rule, self).unlink(cr, uid, ids, context=context) - self.clear_cache() + self._compute_domain.clear_cache(self) return res def create(self, cr, uid, vals, context=None): res = super(ir_rule, self).create(cr, uid, vals, context=context) - self.clear_cache(cr, uid) + self._compute_domain.clear_cache(self) return res def write(self, cr, uid, ids, vals, context=None): res = super(ir_rule, self).write(cr, uid, ids, vals, context=context) - self.clear_cache(cr,uid) + self._compute_domain.clear_cache(self) return res ir_rule() From 52a84f0758fefa2174e7a6bf27508551ef9ef521 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Wed, 24 Aug 2011 19:22:37 +0200 Subject: [PATCH 19/56] [FIX] revert previous commit ir_rule clear_cache bzr revid: al@openerp.com-20110824172237-arzved9kk54u3hwu --- openerp/addons/base/ir/ir_rule.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/openerp/addons/base/ir/ir_rule.py b/openerp/addons/base/ir/ir_rule.py index d7144cfa01b..734d00eb9a2 100644 --- a/openerp/addons/base/ir/ir_rule.py +++ b/openerp/addons/base/ir/ir_rule.py @@ -138,6 +138,9 @@ class ir_rule(osv.osv): return domain return [] + def clear_cache(self, cr, uid): + self._compute_domain.clear_cache(self) + def domain_get(self, cr, uid, model_name, mode='read', context=None): dom = self._compute_domain(cr, uid, model_name, mode) if dom: @@ -151,17 +154,17 @@ class ir_rule(osv.osv): def unlink(self, cr, uid, ids, context=None): res = super(ir_rule, self).unlink(cr, uid, ids, context=context) - self._compute_domain.clear_cache(self) + self.clear_cache(cr, uid) return res def create(self, cr, uid, vals, context=None): res = super(ir_rule, self).create(cr, uid, vals, context=context) - self._compute_domain.clear_cache(self) + self.clear_cache(cr, uid) return res def write(self, cr, uid, ids, vals, context=None): res = super(ir_rule, self).write(cr, uid, ids, vals, context=context) - self._compute_domain.clear_cache(self) + self.clear_cache(cr,uid) return res ir_rule() From 8d31082408b8d650c724ead0a53da93416a6c599 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Wed, 24 Aug 2011 23:19:48 +0200 Subject: [PATCH 20/56] [FIX] ir.model.access check use positional args bzr revid: al@openerp.com-20110824211948-gvtc7uv9e3oeeo3e --- openerp/addons/base/ir/ir_attachment.py | 4 ++-- openerp/addons/base/ir/ir_ui_menu.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openerp/addons/base/ir/ir_attachment.py b/openerp/addons/base/ir/ir_attachment.py index 2c3d4e61e84..ecdd2ceca37 100644 --- a/openerp/addons/base/ir/ir_attachment.py +++ b/openerp/addons/base/ir/ir_attachment.py @@ -33,7 +33,6 @@ class ir_attachment(osv.osv): """ if not ids: return - ima = self.pool.get('ir.model.access') res_ids = {} if ids: if isinstance(ids, (int, long)): @@ -47,12 +46,13 @@ class ir_attachment(osv.osv): if 'res_model' in values and 'res_id' in values: res_ids.setdefault(values['res_model'],set()).add(values['res_id']) + ima = self.pool.get('ir.model.access') for model, mids in res_ids.items(): # ignore attachments that are not attached to a resource anymore when checking access rights # (resource was deleted but attachment was not) cr.execute('select id from '+self.pool.get(model)._table+' where id in %s', (tuple(mids),)) mids = [x[0] for x in cr.fetchall()] - ima.check(cr, uid, model, mode, context=context) + ima.check(cr, uid, model, mode) self.pool.get(model).check_access_rule(cr, uid, mids, mode, context=context) def search(self, cr, uid, args, offset=0, limit=None, order=None, diff --git a/openerp/addons/base/ir/ir_ui_menu.py b/openerp/addons/base/ir/ir_ui_menu.py index 9ed4d7806bc..83660cfe753 100644 --- a/openerp/addons/base/ir/ir_ui_menu.py +++ b/openerp/addons/base/ir/ir_ui_menu.py @@ -88,7 +88,7 @@ class ir_ui_menu(osv.osv): field = model_field.get(menu.action._name) if field and data[field]: - if not modelaccess.check(cr, uid, data[field], raise_exception=False): + if not modelaccess.check(cr, uid, data[field], False): continue else: # if there is no action, it's a 'folder' menu From 8c0fb375b45804cc037b9d2976427f4f6e1b774c Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Wed, 24 Aug 2011 23:44:16 +0200 Subject: [PATCH 21/56] [FIX] ir.model clear_cache use self bzr revid: al@openerp.com-20110824214416-9eby8h7mnqmlr8a3 --- openerp/addons/base/ir/ir_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py index 4dba1d57dad..0c4b52ac1ac 100644 --- a/openerp/addons/base/ir/ir_model.py +++ b/openerp/addons/base/ir/ir_model.py @@ -638,8 +638,8 @@ class ir_model_data(osv.osv): """ Regular unlink method, but make sure to clear the caches. """ ref_ids = self.browse(cr, uid, ids, context=context) for ref_id in ref_ids: - self._get_id.clear_cache(cr.dbname, uid, ref_id.module, ref_id.name) - self.get_object_reference.clear_cache(cr.dbname, uid, ref_id.module, ref_id.name) + self._get_id.clear_cache(self, uid, ref_id.module, ref_id.name) + self.get_object_reference.clear_cache(self, uid, ref_id.module, ref_id.name) return super(ir_model_data,self).unlink(cr, uid, ids, context=context) def _update(self,cr, uid, model, module, values, xml_id=False, store=True, noupdate=False, mode='init', res_id=False, context=None): From 7a52778235730d039cfcd11ce11ff15264364f16 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Wed, 24 Aug 2011 23:48:43 +0200 Subject: [PATCH 22/56] [IMP] ir.model.data unlink clear full cache bzr revid: al@openerp.com-20110824214843-c75b3jl1fad0mv5a --- openerp/addons/base/ir/ir_model.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py index 0c4b52ac1ac..a9d2a21b7a5 100644 --- a/openerp/addons/base/ir/ir_model.py +++ b/openerp/addons/base/ir/ir_model.py @@ -636,10 +636,8 @@ class ir_model_data(osv.osv): def unlink(self, cr, uid, ids, context=None): """ Regular unlink method, but make sure to clear the caches. """ - ref_ids = self.browse(cr, uid, ids, context=context) - for ref_id in ref_ids: - self._get_id.clear_cache(self, uid, ref_id.module, ref_id.name) - self.get_object_reference.clear_cache(self, uid, ref_id.module, ref_id.name) + self._get_id.clear_cache(self) + self.get_object_reference.clear_cache(self) return super(ir_model_data,self).unlink(cr, uid, ids, context=context) def _update(self,cr, uid, model, module, values, xml_id=False, store=True, noupdate=False, mode='init', res_id=False, context=None): From c7076adb06e7b77ad77bb801b1e98e111a448614 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Thu, 25 Aug 2011 00:03:24 +0200 Subject: [PATCH 23/56] [FIX] ir_attachement check use positional args bzr revid: al@openerp.com-20110824220324-xfo7swm45stcooun --- openerp/addons/base/ir/ir_attachment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/ir/ir_attachment.py b/openerp/addons/base/ir/ir_attachment.py index ecdd2ceca37..95a4cd8cab0 100644 --- a/openerp/addons/base/ir/ir_attachment.py +++ b/openerp/addons/base/ir/ir_attachment.py @@ -80,7 +80,7 @@ class ir_attachment(osv.osv): # performed in batch as much as possible. ima = self.pool.get('ir.model.access') for model, targets in model_attachments.iteritems(): - if not ima.check(cr, uid, model, 'read', raise_exception=False, context=context): + if not ima.check(cr, uid, model, 'read', False): # remove all corresponding attachment ids for attach_id in itertools.chain(*targets.values()): ids.remove(attach_id) From 4be82ffd5223b9dc1ea23d32a57e2789590883ef Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Thu, 25 Aug 2011 00:23:30 +0200 Subject: [PATCH 24/56] [FIX] remove debugging bzr revid: al@openerp.com-20110824222330-zrfnr4qme71r9oqi --- openerp/tools/cache.py | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/openerp/tools/cache.py b/openerp/tools/cache.py index b9323fa0d02..fd28a659377 100644 --- a/openerp/tools/cache.py +++ b/openerp/tools/cache.py @@ -1,7 +1,7 @@ import lru class ormcache(object): - """ LRU cache decorator for orm methods + """ LRU cache decorator for orm methods, """ def __init__(self, skiparg=2, size=8192, multi=None, timeout=None): @@ -16,14 +16,12 @@ class ormcache(object): self.method = m def lookup(self2, cr, *args): r = self.lookup(self2, cr, *args) - #self.stat() return r lookup.clear_cache = self.clear - #print "lookup-func",lookup return lookup def stat(self): - print "lookup-stats hit=%s miss=%s err=%s ratio=%.1f" % (self.stat_hit,self.stat_miss,self.stat_err, (100*float(self.stat_hit))/(self.stat_miss+self.stat_hit) ) + return "lookup-stats hit=%s miss=%s err=%s ratio=%.1f" % (self.stat_hit,self.stat_miss,self.stat_err, (100*float(self.stat_hit))/(self.stat_miss+self.stat_hit) ) def lru(self, self2): try: @@ -41,18 +39,14 @@ class ormcache(object): key = args[self.skiparg-2:] try: r = d[key] - #print "lookup-hit",self2,cr,key,r self.stat_hit += 1 return r except KeyError: self.stat_miss += 1 - #print "lookup-miss",self2,cr,key value = d[args] = self.method(self2, cr, *args) - #print "lookup-miss-value",value return value except TypeError: self.stat_err += 1 - #print "lookup-error",self2,cr,key return self.method(self2, cr, *args) def clear(self, self2, *args): @@ -62,7 +56,6 @@ class ormcache(object): if args: try: key = args[self.skiparg-2:] - #print "del",key del d[key] except KeyError: pass @@ -78,7 +71,6 @@ class ormcache_multi(ormcache): d = self.lru(self2) args = list(args) multi = self.multi - #print args, multi ids = args[multi] r = {} miss = [] @@ -88,12 +80,10 @@ class ormcache_multi(ormcache): key = tuple(args[self.skiparg-2:]) try: r[i] = d[key] - #print "lookup-hit",self2,cr,key,r[i] self.stat_hit += 1 except Exception: self.stat_miss += 1 miss.append(i) - #print "lookup-miss",self2,cr,key if miss: args[multi] = miss @@ -134,8 +124,8 @@ if __name__ == '__main__': return dict([(i,i) for i in ids]) a=A() - #r=a.m(1,2) - #r=a.m(1,2) + r=a.m(1,2) + r=a.m(1,2) r=a.n("cr",1,[1,2,3,4]) r=a.n("cr",1,[1,2]) print r @@ -144,4 +134,4 @@ if __name__ == '__main__': a.n.clear_cache(a,1,1) r=a.n("cr",1,[1,2]) print r - #r=a.n("cr",1,[1,2]) + r=a.n("cr",1,[1,2]) From 86965e38848baa706d5948d3837485e63b1b8e0f Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Thu, 25 Aug 2011 01:11:31 +0200 Subject: [PATCH 25/56] [FIX] orm ir.translation get_source to use positional args bzr revid: al@openerp.com-20110824231131-y33ng5x4d6j2vr6w --- openerp/osv/orm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index b721de5accc..9c099355427 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -1264,7 +1264,7 @@ class orm_template(object): else: translated_msg = tmp_msg else: - translated_msg = trans._get_source(cr, uid, self._name, 'constraint', lng, source=msg) or msg + translated_msg = trans._get_source(cr, uid, self._name, 'constraint', lng, msg) or msg error_msgs.append( _("Error occurred while validating the field(s) %s: %s") % (','.join(fields), translated_msg) ) From 5b17d2ccb7638543f02ac4d018a984441c7f2ce2 Mon Sep 17 00:00:00 2001 From: "Ujjvala Collins (OpenERP)" Date: Thu, 25 Aug 2011 17:26:45 +0530 Subject: [PATCH 26/56] [FIX] base: Fixed problem of browse method in _get_conversion_rate method. bzr revid: uco@tinyerp.com-20110825115645-85ya32yjnpirbuga --- openerp/addons/base/res/res_currency.py | 34 ++++++++++++------------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/openerp/addons/base/res/res_currency.py b/openerp/addons/base/res/res_currency.py index 495a931f91d..f8bd4f21893 100644 --- a/openerp/addons/base/res/res_currency.py +++ b/openerp/addons/base/res/res_currency.py @@ -103,15 +103,24 @@ class res_currency(osv.osv): def is_zero(self, cr, uid, currency, amount): return abs(self.round(cr, uid, currency, amount)) < currency.rounding - def _get_conversion_rate(self, cr, uid, from_currency_rate, to_currency_rate, context=None): + def _get_conversion_rate(self, cr, uid, from_currency, to_currency, context=None): if context is None: context = {} + ctx = context.copy() + ctx.update({'currency_rate_type_id': ctx.get('currency_rate_type_from')}) + from_currency = self.browse(cr, uid, [from_currency.id], context=ctx)[0] + from_currency_rate = from_currency['rate'] + + ctx.update({'currency_rate_type_id': ctx.get('currency_rate_type_to')}) + to_currency = self.browse(cr, uid, [to_currency.id], context=ctx)[0] + to_currency_rate = to_currency['rate'] + if from_currency_rate == 0 or to_currency_rate == 0: date = context.get('date', time.strftime('%Y-%m-%d')) if from_currency_rate == 0: - currency_symbol = context.get('from_curr_symbol') + currency_symbol = from_currency.symbol else: - currency_symbol = context.get('to_curr_symbol') + currency_symbol = to_currency.symbol raise osv.except_osv(_('Error'), _('No rate found \n' \ 'for the currency: %s \n' \ 'at the date: %s') % (currency_symbol, date)) @@ -126,28 +135,17 @@ class res_currency(osv.osv): from_currency_id = to_currency_id if not to_currency_id: to_currency_id = from_currency_id - - ctx1 = context.copy() - ctx1.update({'currency_rate_type_id': currency_rate_type_from}) - xc = self.browse(cr, uid, [from_currency_id], context=ctx1) + xc = self.browse(cr, uid, [from_currency_id,to_currency_id], context=context) from_currency = (xc[0].id == from_currency_id and xc[0]) or xc[1] - from_currency_rate = from_currency['rate'] - context.update({'from_curr_symbol': from_currency.symbol}) - - ctx2 = context.copy() - ctx2.update({'currency_rate_type_id': currency_rate_type_to}) - xc1 = self.browse(cr, uid, [to_currency_id], context=ctx2) - to_currency = (xc1[0].id == to_currency_id and xc1[0]) or xc1[1] - to_currency_rate = to_currency['rate'] - context.update({'to_curr_symbol': to_currency.symbol}) - + to_currency = (xc[0].id == to_currency_id and xc[0]) or xc[1] if to_currency_id == from_currency_id: if round: return self.round(cr, uid, to_currency, from_amount) else: return from_amount else: - rate = self._get_conversion_rate(cr, uid, from_currency_rate, to_currency_rate, context=context) + context.update({'currency_rate_type_from': currency_rate_type_from, 'currency_rate_type_to': currency_rate_type_to}) + rate = self._get_conversion_rate(cr, uid, from_currency, to_currency, context=context) if round: return self.round(cr, uid, to_currency, from_amount * rate) else: From 6fdadb04f51c468c772a9dcc9e5f344d77d7be66 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Thu, 25 Aug 2011 14:47:11 +0200 Subject: [PATCH 27/56] [IMP] tools.cache: added missing clean_caches_for_db replacement. bzr revid: vmt@openerp.com-20110825124711-y2uckmvcoa0arz4h --- openerp/modules/registry.py | 24 ++++++++++++++++++++++++ openerp/osv/orm.py | 12 ++++++++++++ openerp/service/web_services.py | 4 +++- openerp/sql_db.py | 1 - 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/openerp/modules/registry.py b/openerp/modules/registry.py index 11f484a71a0..19b6227d621 100644 --- a/openerp/modules/registry.py +++ b/openerp/modules/registry.py @@ -82,6 +82,15 @@ class Registry(object): return res + def clear_caches + """ Clear the caches + + This clears the caches associated to methods decorated with + ``tools.ormcache`` or ``tools.ormcache_multi`` for all the models. + """ + for model in self.models.itervalues(): + model.clear_caches() + class RegistryManager(object): """ Model registries manager. @@ -155,4 +164,19 @@ class RegistryManager(object): del cls.registries[db_name] + @classmethod + def clear_caches(db_name) + """ Clear the caches + + This clears the caches associated to methods decorated with + ``tools.ormcache`` or ``tools.ormcache_multi`` for all the models + of the given database name. + + This method is given to spare you a ``RegistryManager.get(db_name)`` + that would loads the given database if it was not already loaded. + """ + if db_name in cls.registries: + del cls.registries[db_name].clear_caches() + + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 9c099355427..d2e1cb95487 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -2251,6 +2251,18 @@ class orm_template(object): values = defaults return values + def clear_caches(self): + """ Clear the caches + + This clears the caches associated to methods decorated with + ``tools.ormcache`` or ``tools.ormcache_multi``. + """ + try: + getattr(self, '_ormcache') + self._ormcache = {} + except AttributeError: + pass + class orm_memory(orm_template): _protected = ['read', 'write', 'create', 'default_get', 'perm_read', 'unlink', 'fields_get', 'fields_view_get', 'search', 'name_get', 'distinct_field_get', 'name_search', 'copy', 'import_data', 'search_count', 'exists'] diff --git a/openerp/service/web_services.py b/openerp/service/web_services.py index c3b23a4dbb7..c768a3cb877 100644 --- a/openerp/service/web_services.py +++ b/openerp/service/web_services.py @@ -155,6 +155,7 @@ class db(netsvc.ExportService): def exp_drop(self, db_name): sql_db.close_db(db_name) + openerp.modules.registry.RegistryManager.clear_caches(db_name) openerp.netsvc.Agent.cancel(db_name) logger = netsvc.Logger() @@ -258,7 +259,8 @@ class db(netsvc.ExportService): def exp_rename(self, old_name, new_name): sql_db.close_db(old_name) - openerp.netsvc.Agent.cancel(db_name) + openerp.modules.registry.RegistryManager.clear_caches(old_name) + openerp.netsvc.Agent.cancel(old_name) logger = netsvc.Logger() db = sql_db.db_connect('template1') diff --git a/openerp/sql_db.py b/openerp/sql_db.py index 18efb62eb18..f4a899c8db2 100644 --- a/openerp/sql_db.py +++ b/openerp/sql_db.py @@ -500,7 +500,6 @@ def db_connect(db_name): def close_db(db_name): """ You might want to call openerp.netsvc.Agent.cancel(db_name) along this function.""" _Pool.close_all(dsn(db_name)) - tools.cache.clean_caches_for_db(db_name) ct = currentThread() if hasattr(ct, 'dbname'): delattr(ct, 'dbname') From e117018b7b0d7896ad886c871589a7defb45dec5 Mon Sep 17 00:00:00 2001 From: "Mustufa Rangwala (OpenERP)" Date: Thu, 25 Aug 2011 22:36:57 +0530 Subject: [PATCH 28/56] [REF] Base: small improvement bzr revid: mra@tinyerp.com-20110825170657-tgajqc4yknz9f83b --- openerp/addons/base/res/res_currency.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openerp/addons/base/res/res_currency.py b/openerp/addons/base/res/res_currency.py index f8bd4f21893..8182a207c5c 100644 --- a/openerp/addons/base/res/res_currency.py +++ b/openerp/addons/base/res/res_currency.py @@ -107,11 +107,11 @@ class res_currency(osv.osv): if context is None: context = {} ctx = context.copy() - ctx.update({'currency_rate_type_id': ctx.get('currency_rate_type_from')}) + ctx.update({'currency_rate_type_id': ctx.get('currency_rate_type_from', False)}) from_currency = self.browse(cr, uid, [from_currency.id], context=ctx)[0] from_currency_rate = from_currency['rate'] - ctx.update({'currency_rate_type_id': ctx.get('currency_rate_type_to')}) + ctx.update({'currency_rate_type_id': ctx.get('currency_rate_type_to', False)}) to_currency = self.browse(cr, uid, [to_currency.id], context=ctx)[0] to_currency_rate = to_currency['rate'] @@ -124,7 +124,6 @@ class res_currency(osv.osv): raise osv.except_osv(_('Error'), _('No rate found \n' \ 'for the currency: %s \n' \ 'at the date: %s') % (currency_symbol, date)) - return to_currency_rate/from_currency_rate def compute(self, cr, uid, from_currency_id, to_currency_id, from_amount, From 46f690d64c0200cf72e22e5ccaad489ed5f11c1d Mon Sep 17 00:00:00 2001 From: "Mustufa Rangwala (OpenERP)" Date: Thu, 25 Aug 2011 23:06:51 +0530 Subject: [PATCH 29/56] [IMP] Base: added currency rate type on tree view bzr revid: mra@tinyerp.com-20110825173651-5rn1vsukicpdo331 --- openerp/addons/base/res/res_currency_view.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/openerp/addons/base/res/res_currency_view.xml b/openerp/addons/base/res/res_currency_view.xml index 63a55c0fddf..ddfee8fa090 100644 --- a/openerp/addons/base/res/res_currency_view.xml +++ b/openerp/addons/base/res/res_currency_view.xml @@ -53,6 +53,7 @@ +
From dad3528ab7191bd4097d0fac275b89bccbfd6119 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Fri, 26 Aug 2011 14:10:26 +0200 Subject: [PATCH 30/56] [FIX] registry.py: typos (invalid syntax). I wonder how come I made the previous commit. bzr revid: vmt@openerp.com-20110826121026-da90yx3iapj6y1v1 --- openerp/modules/registry.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openerp/modules/registry.py b/openerp/modules/registry.py index 19b6227d621..e651c5d7994 100644 --- a/openerp/modules/registry.py +++ b/openerp/modules/registry.py @@ -82,7 +82,7 @@ class Registry(object): return res - def clear_caches + def clear_caches(): """ Clear the caches This clears the caches associated to methods decorated with @@ -165,7 +165,7 @@ class RegistryManager(object): @classmethod - def clear_caches(db_name) + def clear_caches(db_name): """ Clear the caches This clears the caches associated to methods decorated with @@ -176,7 +176,7 @@ class RegistryManager(object): that would loads the given database if it was not already loaded. """ if db_name in cls.registries: - del cls.registries[db_name].clear_caches() + cls.registries[db_name].clear_caches() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From 174e25e66fcb69fe44080b644b42fa3eb33279e9 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Fri, 26 Aug 2011 14:16:39 +0200 Subject: [PATCH 31/56] [IMP] tools.cache: removed unused variable. bzr revid: vmt@openerp.com-20110826121639-irm0g0eh5yec1c88 --- openerp/tools/cache.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/openerp/tools/cache.py b/openerp/tools/cache.py index fd28a659377..090651cf6a4 100644 --- a/openerp/tools/cache.py +++ b/openerp/tools/cache.py @@ -107,9 +107,6 @@ class dummy_cache(object): def clear(self, *l, **kw): pass -#ormcache = dummy_cache -cache = dummy_cache - if __name__ == '__main__': class A(): From 3f00bfc405a75e8980505dbc3aa2d731361962a2 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Fri, 26 Aug 2011 18:17:36 +0200 Subject: [PATCH 32/56] [FIX] registry: use a unique list of models to load per module This is necessary to preserve the model loading order as defined in the module. This was broken when the metaclass was introduced to make the explicit model constructor call optional. One consequence is that the order in which the classes are declared in the module really defines their initialization order, even if the constructors are later called explcitly in a different order. This latter case should be fairly rare, and easy to fix too - simply putting the class declaration in the right order. bzr revid: odo@openerp.com-20110826161736-lgnpurtbcqtbseey --- openerp/modules/registry.py | 11 +++-------- openerp/osv/orm.py | 17 ++++++----------- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/openerp/modules/registry.py b/openerp/modules/registry.py index 11f484a71a0..1cb31cd8d28 100644 --- a/openerp/modules/registry.py +++ b/openerp/modules/registry.py @@ -70,15 +70,10 @@ class Registry(object): res = [] - # Instanciate classes registered through their constructor and - # add them to the pool. - for klass in openerp.osv.orm.module_class_list.get(module, []): - res.append(klass.createInstance(self, cr)) - - # Instanciate classes automatically discovered. + # Instantiate registered classes (via metamodel discovery or via explicit + # constructor call), and add them to the pool. for cls in openerp.osv.orm.MetaModel.module_to_models.get(module, []): - if cls not in openerp.osv.orm.module_class_list.get(module, []): - res.append(cls.createInstance(self, cr)) + res.append(cls.createInstance(self, cr)) return res diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index d4a5d808990..d328d54059e 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -70,9 +70,6 @@ from openerp.tools import SKIPPED_ELEMENT_TYPES regex_order = re.compile('^(([a-z0-9_]+|"[a-z0-9_]+")( *desc| *asc)?( *, *|))+$', re.I) regex_object_name = re.compile(r'^[a-z0-9_.]+$') -# Mapping between openerp module names and their osv classes. -module_class_list = {} - # Super-user identifier (aka Administrator aka root) ROOT_USER_ID = 1 @@ -806,23 +803,21 @@ class orm_template(object): return obj def __new__(cls): - """ Register this model. + """Register this model. This doesn't create an instance but simply register the model as being part of the module where it is defined. - - TODO make it possible to not even have to call the constructor - to be registered. - """ - # Set the module name (e.g. base, sale, accounting, ...) on the class. module = cls.__module__.split('.')[0] if not hasattr(cls, '_module'): cls._module = module - # Remember which models to instanciate for this module. - module_class_list.setdefault(cls._module, []).append(cls) + # Record this class in the list of models to instantiate for this module, + # managed by the metaclass. + module_model_list = MetaModel.module_to_models.setdefault(cls._module, []) + if cls not in module_model_list: + module_model_list.append(cls) # Since we don't return an instance here, the __init__ # method won't be called. From 9421188847a74992ffab17eea99674ba2a49feb0 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Sun, 28 Aug 2011 00:53:30 +0200 Subject: [PATCH 33/56] [IMP] base/res_currency: improved res.currency.rate.type. Added search view and help tooltip. Made some code cleaning bzr revid: qdp-launchpad@openerp.com-20110827225330-3ng37d8yg31psgsd --- openerp/addons/base/res/res_currency.py | 45 +++++++++---------- openerp/addons/base/res/res_currency_view.xml | 12 ++++- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/openerp/addons/base/res/res_currency.py b/openerp/addons/base/res/res_currency.py index 8182a207c5c..5333a8eab20 100644 --- a/openerp/addons/base/res/res_currency.py +++ b/openerp/addons/base/res/res_currency.py @@ -28,28 +28,24 @@ from tools.translate import _ class res_currency(osv.osv): def _current_rate(self, cr, uid, ids, name, arg, context=None): - currency_rate_obj = self.pool.get('res.currency.rate') - res = {} if context is None: context = {} + res = {} if 'date' in context: date = context['date'] else: date = time.strftime('%Y-%m-%d') - domain = [('currency_id', 'in', ids), ('name', '<=', date)] - currency_rate_type_id = context.get('currency_rate_type_id', False) - if currency_rate_type_id: - domain.append(('currency_rate_type_id', '=', currency_rate_type_id)) - curr_rate_ids = currency_rate_obj.search(cr, uid, domain, order='name desc', context=context) - curr_rates = currency_rate_obj.browse(cr, uid, curr_rate_ids, context=context) + date = date or time.strftime('%Y-%m-%d') + currency_rate_type = context.get('currency_rate_type_id', None) + operator = currency_rate_type and '=' or 'is' for id in ids: - res[id] = 0 - for cur in curr_rates: - if cur.currency_id.id == id: - res[id] = cur.rate - break + cr.execute("SELECT currency_id, rate FROM res_currency_rate WHERE currency_id = %s AND name <= %s AND currency_rate_type_id " + operator +" %s ORDER BY name desc LIMIT 1" ,(id, date, currency_rate_type)) + if cr.rowcount: + id, rate = cr.fetchall()[0] + res[id] = rate + else: + res[id] = 0 return res - _name = "res.currency" _description = "Currency" _columns = { @@ -107,24 +103,22 @@ class res_currency(osv.osv): if context is None: context = {} ctx = context.copy() - ctx.update({'currency_rate_type_id': ctx.get('currency_rate_type_from', False)}) - from_currency = self.browse(cr, uid, [from_currency.id], context=ctx)[0] - from_currency_rate = from_currency['rate'] + ctx.update({'currency_rate_type_id': ctx.get('currency_rate_type_from', None)}) + from_currency = self.browse(cr, uid, from_currency.id, context=ctx) - ctx.update({'currency_rate_type_id': ctx.get('currency_rate_type_to', False)}) - to_currency = self.browse(cr, uid, [to_currency.id], context=ctx)[0] - to_currency_rate = to_currency['rate'] + ctx.update({'currency_rate_type_id': ctx.get('currency_rate_type_to', None)}) + to_currency = self.browse(cr, uid, to_currency.id, context=ctx) - if from_currency_rate == 0 or to_currency_rate == 0: + if from_currency.rate == 0 or to_currency.rate == 0: date = context.get('date', time.strftime('%Y-%m-%d')) - if from_currency_rate == 0: + if from_currency.rate == 0: currency_symbol = from_currency.symbol else: currency_symbol = to_currency.symbol raise osv.except_osv(_('Error'), _('No rate found \n' \ 'for the currency: %s \n' \ 'at the date: %s') % (currency_symbol, date)) - return to_currency_rate/from_currency_rate + return to_currency.rate/from_currency.rate def compute(self, cr, uid, from_currency_id, to_currency_id, from_amount, round=True, currency_rate_type_from=False, currency_rate_type_to=False, context=None): @@ -156,7 +150,7 @@ class res_currency_rate_type(osv.osv): _name = "res.currency.rate.type" _description = "Currency Rate Type" _columns = { - 'name': fields.char('Name', size=32, required=True), + 'name': fields.char('Name', size=64, required=True, translate=True), } res_currency_rate_type() @@ -164,12 +158,13 @@ res_currency_rate_type() class res_currency_rate(osv.osv): _name = "res.currency.rate" _description = "Currency Rate" + _columns = { 'name': fields.date('Date', required=True, select=True), 'rate': fields.float('Rate', digits=(12,6), required=True, help='The rate of the currency to the currency of rate 1'), 'currency_id': fields.many2one('res.currency', 'Currency', readonly=True), - 'currency_rate_type_id': fields.many2one('res.currency.rate.type', 'Currency Rate Type'), + 'currency_rate_type_id': fields.many2one('res.currency.rate.type', 'Currency Rate Type', help="Allow you to define your own currency rate types, like average or Day to Year. Leave empty if you simply want to use the normal 'spot' rate type"), } _defaults = { 'name': lambda *a: time.strftime('%Y-%m-%d'), diff --git a/openerp/addons/base/res/res_currency_view.xml b/openerp/addons/base/res/res_currency_view.xml index ddfee8fa090..4220832606b 100644 --- a/openerp/addons/base/res/res_currency_view.xml +++ b/openerp/addons/base/res/res_currency_view.xml @@ -88,7 +88,17 @@ form tree,form - + + res.currency.rate.type.search + res.currency.rate.type + search + + + + + + + From 3f691a6c49bc7046d693a54229ff6084227feb70 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Sun, 28 Aug 2011 01:32:22 +0200 Subject: [PATCH 34/56] [IMP] res.partner.canal into crm.case.channel bzr revid: al@openerp.com-20110827233222-cy0w9z3jdm8ye1b2 --- openerp/addons/base/__openerp__.py | 1 - openerp/addons/base/res/partner/crm.py | 16 ---------- openerp/addons/base/res/partner/crm_demo.xml | 18 ----------- openerp/addons/base/res/partner/crm_view.xml | 32 ------------------- .../addons/base/security/ir.model.access.csv | 2 -- 5 files changed, 69 deletions(-) delete mode 100644 openerp/addons/base/res/partner/crm_demo.xml diff --git a/openerp/addons/base/__openerp__.py b/openerp/addons/base/__openerp__.py index c36dcecdf30..d7c73930b5f 100644 --- a/openerp/addons/base/__openerp__.py +++ b/openerp/addons/base/__openerp__.py @@ -82,7 +82,6 @@ 'demo_xml': [ 'base_demo.xml', 'res/partner/partner_demo.xml', - 'res/partner/crm_demo.xml', 'res/res_widget_demo.xml', ], 'test': [ diff --git a/openerp/addons/base/res/partner/crm.py b/openerp/addons/base/res/partner/crm.py index d7decade3ca..4425b7e6984 100644 --- a/openerp/addons/base/res/partner/crm.py +++ b/openerp/addons/base/res/partner/crm.py @@ -23,22 +23,6 @@ import time from osv import osv from osv import fields -# -# Sale/Purchase Canal, Media -# -class res_partner_canal(osv.osv): - _name = "res.partner.canal" - _description = "Channels" - _order = 'name' - _columns = { - 'name': fields.char('Channel Name', size=64, required=True), - 'active': fields.boolean('Active'), - } - _defaults = { - 'active': lambda *a: 1, - } -res_partner_canal() - class res_partner_event(osv.osv): _name = "res.partner.event" _columns = { diff --git a/openerp/addons/base/res/partner/crm_demo.xml b/openerp/addons/base/res/partner/crm_demo.xml deleted file mode 100644 index 03c69ef51d7..00000000000 --- a/openerp/addons/base/res/partner/crm_demo.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - website - - - phone - - - direct - - - E-mail - - - - diff --git a/openerp/addons/base/res/partner/crm_view.xml b/openerp/addons/base/res/partner/crm_view.xml index 51944da65c8..bc5904c9e9f 100644 --- a/openerp/addons/base/res/partner/crm_view.xml +++ b/openerp/addons/base/res/partner/crm_view.xml @@ -2,39 +2,7 @@ - - res.partner.canal.tree - res.partner.canal - tree - - - - - - - - - res.partner.canal.form - res.partner.canal - form - -
- - - - -
- - Channels - res.partner.canal - form - tree,form - Track from where is coming your leads and opportunities by creating specific channels that will be maintained at the creation of a document in the system. Some examples of channels can be: Website, Phone Call, Reseller, etc. - - - res.partner.event.form diff --git a/openerp/addons/base/security/ir.model.access.csv b/openerp/addons/base/security/ir.model.access.csv index f3e19f49535..8949052f89b 100644 --- a/openerp/addons/base/security/ir.model.access.csv +++ b/openerp/addons/base/security/ir.model.access.csv @@ -64,8 +64,6 @@ "access_res_partner_bank_type_group_user","res_partner_bank_type group_user","model_res_partner_bank_type",,1,0,0,0 "access_res_partner_bank_type_field_group_partner_manager","res_partner_bank_type_field group_partner_manager","model_res_partner_bank_type_field","group_partner_manager",1,1,1,1 "access_res_partner_bank_type_field_group_user","res_partner_bank_type_field group_user","model_res_partner_bank_type_field",,1,0,0,0 -"access_res_partner_canal_group_user","res_partner_canal group_user","model_res_partner_canal","group_user",1,0,0,0 -"access_res_partner_canal_group_partner_manager","res_partner_canal group_partner_manager","model_res_partner_canal","group_partner_manager",1,1,1,1 "access_res_partner_category_group_user","res_partner_category group_user","model_res_partner_category","group_user",1,0,0,0 "access_res_partner_category_group_partner_manager","res_partner_category group_partner_manager","model_res_partner_category","group_partner_manager",1,1,1,1 "access_res_partner_event_group_user","res_partner_event group_user","model_res_partner_event","group_user",1,0,0,0 From e6db9e4b715150d3756d56ad2f1980770039b97f Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Sun, 28 Aug 2011 02:13:14 +0200 Subject: [PATCH 35/56] [IMP] renames in base/res bzr revid: al@openerp.com-20110828001314-roc7o38bz22mr580 --- openerp/addons/base/__openerp__.py | 24 ++++++------- openerp/addons/base/res/__init__.py | 13 +++++-- openerp/addons/base/res/partner/__init__.py | 34 ------------------- .../base/res/partner/partner_report.xml | 9 ----- .../base/res/{partner => }/report/__init__.py | 0 .../{partner => }/report/business_card.xml | 0 .../{partner => }/report/business_card.xsl | 0 .../{partner => }/report/partner_address.xml | 0 .../{partner => }/report/partner_address.xsl | 0 .../base/res/{partner/bank.py => res_bank.py} | 0 .../bank_view.xml => res_bank_view.xml} | 0 .../base/res/{country.py => res_country.py} | 0 ...{country_view.xml => res_country_view.xml} | 0 .../{partner/partner.py => res_partner.py} | 0 .../partner_data.xml => res_partner_data.xml} | 0 .../partner_demo.xml => res_partner_demo.xml} | 0 .../{partner/crm.py => res_partner_event.py} | 0 ...rm_view.xml => res_partner_event_view.xml} | 0 .../addons/base/res/res_partner_report.xml | 9 +++++ ...data.xml => res_partner_shortcut_data.xml} | 0 .../partner_view.xml => res_partner_view.xml} | 0 .../base/res/{partner => }/wizard/__init__.py | 0 .../{partner => }/wizard/partner_clear_ids.py | 0 .../wizard/partner_clear_ids_view.xml | 0 .../{partner => }/wizard/partner_sms_send.py | 0 .../wizard/partner_sms_send_view.xml | 0 .../wizard/partner_wizard_ean_check.py | 0 .../wizard/partner_wizard_ean_check_view.xml | 0 .../wizard/partner_wizard_spam.py | 0 .../wizard/partner_wizard_spam_view.xml | 0 30 files changed, 31 insertions(+), 58 deletions(-) delete mode 100644 openerp/addons/base/res/partner/__init__.py delete mode 100644 openerp/addons/base/res/partner/partner_report.xml rename openerp/addons/base/res/{partner => }/report/__init__.py (100%) rename openerp/addons/base/res/{partner => }/report/business_card.xml (100%) rename openerp/addons/base/res/{partner => }/report/business_card.xsl (100%) rename openerp/addons/base/res/{partner => }/report/partner_address.xml (100%) rename openerp/addons/base/res/{partner => }/report/partner_address.xsl (100%) rename openerp/addons/base/res/{partner/bank.py => res_bank.py} (100%) rename openerp/addons/base/res/{partner/bank_view.xml => res_bank_view.xml} (100%) rename openerp/addons/base/res/{country.py => res_country.py} (100%) rename openerp/addons/base/res/{country_view.xml => res_country_view.xml} (100%) rename openerp/addons/base/res/{partner/partner.py => res_partner.py} (100%) rename openerp/addons/base/res/{partner/partner_data.xml => res_partner_data.xml} (100%) rename openerp/addons/base/res/{partner/partner_demo.xml => res_partner_demo.xml} (100%) rename openerp/addons/base/res/{partner/crm.py => res_partner_event.py} (100%) rename openerp/addons/base/res/{partner/crm_view.xml => res_partner_event_view.xml} (100%) create mode 100644 openerp/addons/base/res/res_partner_report.xml rename openerp/addons/base/res/{partner/partner_shortcut_data.xml => res_partner_shortcut_data.xml} (100%) rename openerp/addons/base/res/{partner/partner_view.xml => res_partner_view.xml} (100%) rename openerp/addons/base/res/{partner => }/wizard/__init__.py (100%) rename openerp/addons/base/res/{partner => }/wizard/partner_clear_ids.py (100%) rename openerp/addons/base/res/{partner => }/wizard/partner_clear_ids_view.xml (100%) rename openerp/addons/base/res/{partner => }/wizard/partner_sms_send.py (100%) rename openerp/addons/base/res/{partner => }/wizard/partner_sms_send_view.xml (100%) rename openerp/addons/base/res/{partner => }/wizard/partner_wizard_ean_check.py (100%) rename openerp/addons/base/res/{partner => }/wizard/partner_wizard_ean_check_view.xml (100%) rename openerp/addons/base/res/{partner => }/wizard/partner_wizard_spam.py (100%) rename openerp/addons/base/res/{partner => }/wizard/partner_wizard_spam_view.xml (100%) diff --git a/openerp/addons/base/__openerp__.py b/openerp/addons/base/__openerp__.py index d7c73930b5f..37f26edc177 100644 --- a/openerp/addons/base/__openerp__.py +++ b/openerp/addons/base/__openerp__.py @@ -59,18 +59,18 @@ 'res/res_request_view.xml', 'res/res_lang_view.xml', 'res/res_log_view.xml', - 'res/partner/partner_report.xml', - 'res/partner/partner_view.xml', - 'res/partner/partner_shortcut_data.xml', - 'res/partner/bank_view.xml', - 'res/country_view.xml', + 'res/res_partner_report.xml', + 'res/res_partner_view.xml', + 'res/res_partner_shortcut_data.xml', + 'res/res_bank_view.xml', + 'res/res_country_view.xml', 'res/res_currency_view.xml', - 'res/partner/crm_view.xml', - 'res/partner/wizard/partner_sms_send_view.xml', - 'res/partner/wizard/partner_wizard_spam_view.xml', - 'res/partner/wizard/partner_clear_ids_view.xml', - 'res/partner/wizard/partner_wizard_ean_check_view.xml', - 'res/partner/partner_data.xml', + 'res/res_partner_event_view.xml', + 'res/wizard/partner_sms_send_view.xml', + 'res/wizard/partner_wizard_spam_view.xml', + 'res/wizard/partner_clear_ids_view.xml', + 'res/wizard/partner_wizard_ean_check_view.xml', + 'res/res_partner_data.xml', 'res/ir_property_view.xml', 'security/base_security.xml', 'publisher_warranty/publisher_warranty_view.xml', @@ -81,7 +81,7 @@ ], 'demo_xml': [ 'base_demo.xml', - 'res/partner/partner_demo.xml', + 'res/res_partner_demo.xml', 'res/res_widget_demo.xml', ], 'test': [ diff --git a/openerp/addons/base/res/__init__.py b/openerp/addons/base/res/__init__.py index de00fc54153..9ce69f0c317 100644 --- a/openerp/addons/base/res/__init__.py +++ b/openerp/addons/base/res/__init__.py @@ -21,9 +21,11 @@ import tools -import country +import res_country import res_lang -import partner +import res_partner +import res_partner_event +import res_bank import res_config import res_currency import res_company @@ -31,6 +33,11 @@ import res_user import res_request import res_lang import res_log -import ir_property import res_widget +import ir_property + +import wizard +import report + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/res/partner/__init__.py b/openerp/addons/base/res/partner/__init__.py deleted file mode 100644 index 3a9b989162f..00000000000 --- a/openerp/addons/base/res/partner/__init__.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- 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 tools - -from partner import * -from bank import * -from crm import * - -import wizard -import report - - - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: - diff --git a/openerp/addons/base/res/partner/partner_report.xml b/openerp/addons/base/res/partner/partner_report.xml deleted file mode 100644 index 61e3876527f..00000000000 --- a/openerp/addons/base/res/partner/partner_report.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/openerp/addons/base/res/partner/report/__init__.py b/openerp/addons/base/res/report/__init__.py similarity index 100% rename from openerp/addons/base/res/partner/report/__init__.py rename to openerp/addons/base/res/report/__init__.py diff --git a/openerp/addons/base/res/partner/report/business_card.xml b/openerp/addons/base/res/report/business_card.xml similarity index 100% rename from openerp/addons/base/res/partner/report/business_card.xml rename to openerp/addons/base/res/report/business_card.xml diff --git a/openerp/addons/base/res/partner/report/business_card.xsl b/openerp/addons/base/res/report/business_card.xsl similarity index 100% rename from openerp/addons/base/res/partner/report/business_card.xsl rename to openerp/addons/base/res/report/business_card.xsl diff --git a/openerp/addons/base/res/partner/report/partner_address.xml b/openerp/addons/base/res/report/partner_address.xml similarity index 100% rename from openerp/addons/base/res/partner/report/partner_address.xml rename to openerp/addons/base/res/report/partner_address.xml diff --git a/openerp/addons/base/res/partner/report/partner_address.xsl b/openerp/addons/base/res/report/partner_address.xsl similarity index 100% rename from openerp/addons/base/res/partner/report/partner_address.xsl rename to openerp/addons/base/res/report/partner_address.xsl diff --git a/openerp/addons/base/res/partner/bank.py b/openerp/addons/base/res/res_bank.py similarity index 100% rename from openerp/addons/base/res/partner/bank.py rename to openerp/addons/base/res/res_bank.py diff --git a/openerp/addons/base/res/partner/bank_view.xml b/openerp/addons/base/res/res_bank_view.xml similarity index 100% rename from openerp/addons/base/res/partner/bank_view.xml rename to openerp/addons/base/res/res_bank_view.xml diff --git a/openerp/addons/base/res/country.py b/openerp/addons/base/res/res_country.py similarity index 100% rename from openerp/addons/base/res/country.py rename to openerp/addons/base/res/res_country.py diff --git a/openerp/addons/base/res/country_view.xml b/openerp/addons/base/res/res_country_view.xml similarity index 100% rename from openerp/addons/base/res/country_view.xml rename to openerp/addons/base/res/res_country_view.xml diff --git a/openerp/addons/base/res/partner/partner.py b/openerp/addons/base/res/res_partner.py similarity index 100% rename from openerp/addons/base/res/partner/partner.py rename to openerp/addons/base/res/res_partner.py diff --git a/openerp/addons/base/res/partner/partner_data.xml b/openerp/addons/base/res/res_partner_data.xml similarity index 100% rename from openerp/addons/base/res/partner/partner_data.xml rename to openerp/addons/base/res/res_partner_data.xml diff --git a/openerp/addons/base/res/partner/partner_demo.xml b/openerp/addons/base/res/res_partner_demo.xml similarity index 100% rename from openerp/addons/base/res/partner/partner_demo.xml rename to openerp/addons/base/res/res_partner_demo.xml diff --git a/openerp/addons/base/res/partner/crm.py b/openerp/addons/base/res/res_partner_event.py similarity index 100% rename from openerp/addons/base/res/partner/crm.py rename to openerp/addons/base/res/res_partner_event.py diff --git a/openerp/addons/base/res/partner/crm_view.xml b/openerp/addons/base/res/res_partner_event_view.xml similarity index 100% rename from openerp/addons/base/res/partner/crm_view.xml rename to openerp/addons/base/res/res_partner_event_view.xml diff --git a/openerp/addons/base/res/res_partner_report.xml b/openerp/addons/base/res/res_partner_report.xml new file mode 100644 index 00000000000..06ea859d007 --- /dev/null +++ b/openerp/addons/base/res/res_partner_report.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/openerp/addons/base/res/partner/partner_shortcut_data.xml b/openerp/addons/base/res/res_partner_shortcut_data.xml similarity index 100% rename from openerp/addons/base/res/partner/partner_shortcut_data.xml rename to openerp/addons/base/res/res_partner_shortcut_data.xml diff --git a/openerp/addons/base/res/partner/partner_view.xml b/openerp/addons/base/res/res_partner_view.xml similarity index 100% rename from openerp/addons/base/res/partner/partner_view.xml rename to openerp/addons/base/res/res_partner_view.xml diff --git a/openerp/addons/base/res/partner/wizard/__init__.py b/openerp/addons/base/res/wizard/__init__.py similarity index 100% rename from openerp/addons/base/res/partner/wizard/__init__.py rename to openerp/addons/base/res/wizard/__init__.py diff --git a/openerp/addons/base/res/partner/wizard/partner_clear_ids.py b/openerp/addons/base/res/wizard/partner_clear_ids.py similarity index 100% rename from openerp/addons/base/res/partner/wizard/partner_clear_ids.py rename to openerp/addons/base/res/wizard/partner_clear_ids.py diff --git a/openerp/addons/base/res/partner/wizard/partner_clear_ids_view.xml b/openerp/addons/base/res/wizard/partner_clear_ids_view.xml similarity index 100% rename from openerp/addons/base/res/partner/wizard/partner_clear_ids_view.xml rename to openerp/addons/base/res/wizard/partner_clear_ids_view.xml diff --git a/openerp/addons/base/res/partner/wizard/partner_sms_send.py b/openerp/addons/base/res/wizard/partner_sms_send.py similarity index 100% rename from openerp/addons/base/res/partner/wizard/partner_sms_send.py rename to openerp/addons/base/res/wizard/partner_sms_send.py diff --git a/openerp/addons/base/res/partner/wizard/partner_sms_send_view.xml b/openerp/addons/base/res/wizard/partner_sms_send_view.xml similarity index 100% rename from openerp/addons/base/res/partner/wizard/partner_sms_send_view.xml rename to openerp/addons/base/res/wizard/partner_sms_send_view.xml diff --git a/openerp/addons/base/res/partner/wizard/partner_wizard_ean_check.py b/openerp/addons/base/res/wizard/partner_wizard_ean_check.py similarity index 100% rename from openerp/addons/base/res/partner/wizard/partner_wizard_ean_check.py rename to openerp/addons/base/res/wizard/partner_wizard_ean_check.py diff --git a/openerp/addons/base/res/partner/wizard/partner_wizard_ean_check_view.xml b/openerp/addons/base/res/wizard/partner_wizard_ean_check_view.xml similarity index 100% rename from openerp/addons/base/res/partner/wizard/partner_wizard_ean_check_view.xml rename to openerp/addons/base/res/wizard/partner_wizard_ean_check_view.xml diff --git a/openerp/addons/base/res/partner/wizard/partner_wizard_spam.py b/openerp/addons/base/res/wizard/partner_wizard_spam.py similarity index 100% rename from openerp/addons/base/res/partner/wizard/partner_wizard_spam.py rename to openerp/addons/base/res/wizard/partner_wizard_spam.py diff --git a/openerp/addons/base/res/partner/wizard/partner_wizard_spam_view.xml b/openerp/addons/base/res/wizard/partner_wizard_spam_view.xml similarity index 100% rename from openerp/addons/base/res/partner/wizard/partner_wizard_spam_view.xml rename to openerp/addons/base/res/wizard/partner_wizard_spam_view.xml From 863fdc0808da90278ed86ee18877aca37045e387 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 29 Aug 2011 10:29:29 +0200 Subject: [PATCH 36/56] [FIX] reinstate bail out in clean_action in case the action is not an act_window bzr revid: xmo@openerp.com-20110829082929-c6uhkcq0wmiis2wp --- addons/base/controllers/main.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index 56ce25476c5..562571f10de 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -432,10 +432,13 @@ def load_actions_from_ir_values(req, key, key2, models, meta): for id, name, action in actions] def clean_action(req, action): + action.setdefault('flags', {}) + if action['type'] != 'ir.actions.act_window': + return action + context = req.session.eval_context(req.context) eval_ctx = req.session.evaluation_context(context) - action.setdefault('flags', {}) - + # values come from the server, we can just eval them if isinstance(action.get('context'), basestring): action['context'] = eval( action['context'], eval_ctx ) or {} From 3d3783d7407d8700e90d0829932b733f817d5036 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 29 Aug 2011 14:13:30 +0200 Subject: [PATCH 37/56] [fix] fixed problem with o2m when we re-open a previously created row bzr revid: nicolas.vanhoren@openerp.com-20110829121330-ulj3hnyo3jfs9fq4 --- addons/base/static/src/js/form.js | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index 212f48717bd..818a69bf093 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -1863,7 +1863,10 @@ openerp.base.form.One2ManyListView = openerp.base.ListView.extend({ pop.show_element(self.o2m.field.relation, id, self.o2m.build_context(),{ auto_write: false, alternative_form_view: self.o2m.field.views ? self.o2m.field.views["form"] : undefined, - parent_view: self.o2m.view + parent_view: self.o2m.view, + read_function: function() { + return self.o2m.dataset.read_ids.apply(self.o2m.dataset, arguments); + } }); pop.on_write.add(function(id, data) { self.o2m.dataset.write(id, data, function(r) { @@ -2135,6 +2138,7 @@ openerp.base.form.FormOpenPopup = openerp.base.OldWidget.extend({ * options: * - alternative_form_view * - auto_write (default true) + * - read_function * - parent_view */ show_element: function(model, row_id, context, options) { @@ -2150,7 +2154,8 @@ openerp.base.form.FormOpenPopup = openerp.base.OldWidget.extend({ }, start: function() { this._super(); - this.dataset = new openerp.base.ReadOnlyDataSetSearch(this, this.model, this.context); + this.dataset = new openerp.base.form.FormOpenDataset(this, this.model, this.context); + this.dataset.fop = this; this.dataset.ids = [this.row_id]; this.dataset.index = 0; this.dataset.parent_view = this.options.parent_view; @@ -2192,6 +2197,16 @@ openerp.base.form.FormOpenPopup = openerp.base.OldWidget.extend({ } }); +openerp.base.form.FormOpenDataset = openerp.base.ReadOnlyDataSetSearch.extend({ + read_ids: function() { + if (this.fop.options.read_function) { + return this.fop.options.read_function.apply(null, arguments); + } else { + this._super.apply(this, arguments); + } + } +}); + openerp.base.form.FieldReference = openerp.base.form.Field.extend({ init: function(view, node) { this._super(view, node); From 550387fd919a7b2e458a5cd8d1cd846ca26d2ae6 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 29 Aug 2011 14:28:37 +0200 Subject: [PATCH 38/56] [fix] small thing i forgot in the preceding fix bzr revid: nicolas.vanhoren@openerp.com-20110829122837-ahv6bhb6720jk0ld --- addons/base/static/src/js/form.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index 818a69bf093..581ec4a2456 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -2202,7 +2202,7 @@ openerp.base.form.FormOpenDataset = openerp.base.ReadOnlyDataSetSearch.extend({ if (this.fop.options.read_function) { return this.fop.options.read_function.apply(null, arguments); } else { - this._super.apply(this, arguments); + return this._super.apply(this, arguments); } } }); From 61809cf537e4e173d9661afee1ebef1d5fcd65ec Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 29 Aug 2011 14:40:06 +0200 Subject: [PATCH 39/56] [fix] problem with context menu being displayed under the popups bzr revid: nicolas.vanhoren@openerp.com-20110829124006-ct7semd2cxddus0n --- .../lib/jquery.contextmenu/jquery.contextmenu.r2.packed.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/base/static/lib/jquery.contextmenu/jquery.contextmenu.r2.packed.js b/addons/base/static/lib/jquery.contextmenu/jquery.contextmenu.r2.packed.js index cb456eed14c..2356f3b606b 100644 --- a/addons/base/static/lib/jquery.contextmenu/jquery.contextmenu.r2.packed.js +++ b/addons/base/static/lib/jquery.contextmenu/jquery.contextmenu.r2.packed.js @@ -32,7 +32,7 @@ if(!menu) { menu=$('
').hide().css({ position:'absolute', - zIndex:'500' + zIndex:'2000' }).appendTo('body').bind('click', function(e) { e.stopPropagation() }) From 1ada45a439b830c806ba520e38e952a1a73a1e68 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 29 Aug 2011 15:25:03 +0200 Subject: [PATCH 40/56] [fix] problem with m2o that doesn't validate correctly if they were not modified by the user bzr revid: nicolas.vanhoren@openerp.com-20110829132503-p4tfevsfxyea3ytr --- addons/base/static/src/js/form.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index 581ec4a2456..23e9617c3ba 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -1519,12 +1519,14 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({ }, set_value: function(value) { value = value || null; + this.invalid = false; var self = this; - var _super = this._super; this.tmp_value = value; + self.update_dom(); + self.on_value_changed(); var real_set_value = function(rval) { self.tmp_value = undefined; - _super.apply(self, rval); + self.value = rval; self.original_value = undefined; self._change_int_ext_value(rval); }; @@ -1550,7 +1552,8 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({ }, validate: function() { this.invalid = false; - if (this.value === null) { + var val = this.tmp_value !== undefined ? this.tmp_value : this.value; + if (val === null) { this.invalid = this.required; } }, From a24d5ee08d35401b42606849965728b4440c3cbd Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Mon, 29 Aug 2011 16:08:39 +0200 Subject: [PATCH 41/56] [IMP] Improved translate dialog bzr revid: fme@openerp.com-20110829140839-vr0mvylotmm9w5hg --- addons/base/static/src/css/base.css | 3 ++ addons/base/static/src/js/data.js | 5 +- addons/base/static/src/js/form.js | 10 ++-- addons/base/static/src/js/views.js | 54 +++++++++++++++---- addons/base/static/src/xml/base.xml | 4 +- .../base_calendar/static/src/js/calendar.js | 2 +- .../base_dashboard/static/src/js/dashboard.js | 2 +- addons/base_gantt/static/src/js/gantt.js | 2 +- 8 files changed, 61 insertions(+), 21 deletions(-) diff --git a/addons/base/static/src/css/base.css b/addons/base/static/src/css/base.css index 46364c4fa1d..b0a7dd3c8c8 100644 --- a/addons/base/static/src/css/base.css +++ b/addons/base/static/src/css/base.css @@ -895,6 +895,9 @@ label.error { position: relative; top: 4px; } +.openerp .oe_trad_field.touched { + border: 1px solid green !important; +} /* http://www.quirksmode.org/dom/inputfile.html * http://stackoverflow.com/questions/2855589/replace-input-type-file-by-an-image diff --git a/addons/base/static/src/js/data.js b/addons/base/static/src/js/data.js index 668898dd66c..e95adaf8870 100644 --- a/addons/base/static/src/js/data.js +++ b/addons/base/static/src/js/data.js @@ -355,12 +355,13 @@ openerp.base.DataSet = openerp.base.Widget.extend( /** @lends openerp.base.Data * @param {Function} error_callback function called in case of write error * @returns {$.Deferred} */ - write: function (id, data, callback, error_callback) { + write: function (id, data, options, callback, error_callback) { + var options = options || {}; return this.rpc('/base/dataset/save', { model: this.model, id: id, data: data, - context: this.get_context() + context: this.get_context(options.context) }, callback, error_callback); }, /** diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index 23e9617c3ba..7970173780e 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -157,6 +157,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi this.do_update_pager(record.id == null); if (this.sidebar) { this.sidebar.attachments.do_update(); + this.sidebar.$element.find('.oe_sidebar_translate').toggleClass('oe_hide', !record.id); } if (this.default_focus_field && !this.embedded_view) { this.default_focus_field.focus(); @@ -342,7 +343,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi self.on_created(r, success, prepend_on_create); }); } else { - return this.dataset.write(this.datarecord.id, values, function(r) { + return this.dataset.write(this.datarecord.id, values, {}, function(r) { self.on_saved(r, success); }); } @@ -879,6 +880,9 @@ openerp.base.form.Field = openerp.base.form.Widget.extend({ }, update_dom: function() { this._super.apply(this, arguments); + if (this.field.translate) { + this.$element.find('.oe_field_translate').toggle(!!this.view.datarecord.id); + } if (!this.disable_utility_classes) { this.$element.toggleClass('disabled', this.readonly); this.$element.toggleClass('required', this.required); @@ -1872,7 +1876,7 @@ openerp.base.form.One2ManyListView = openerp.base.ListView.extend({ } }); pop.on_write.add(function(id, data) { - self.o2m.dataset.write(id, data, function(r) { + self.o2m.dataset.write(id, data, {}, function(r) { self.o2m.reload_current_view(); }); }); @@ -2171,7 +2175,7 @@ openerp.base.form.FormOpenPopup = openerp.base.OldWidget.extend({ var self = this; var wdataset = new openerp.base.DataSetSearch(this, this.model, this.context, this.domain); wdataset.parent_view = this.options.parent_view; - wdataset.write(id, data, function(r) { + wdataset.write(id, data, {}, function(r) { self.on_write_completed(); }); }, diff --git a/addons/base/static/src/js/views.js b/addons/base/static/src/js/views.js index 689a72ef7f1..0fd3df3998d 100644 --- a/addons/base/static/src/js/views.js +++ b/addons/base/static/src/js/views.js @@ -472,6 +472,9 @@ openerp.base.Sidebar = openerp.base.Widget.extend({ openerp.base.TranslateDialog = openerp.base.Dialog.extend({ dialog_title: _t("Translations"), init: function(view) { + // TODO fme: should add the language to fields_view_get because between the fields view get + // and the moment the user opens the translation dialog, the user language could have been changed + this.view_language = view.session.user_context.lang; this['on_button' + _t("Save")] = this.on_button_Save; this['on_button' + _t("Close")] = this.on_button_Close; this._super(view, { @@ -500,6 +503,9 @@ openerp.base.TranslateDialog = openerp.base.Dialog.extend({ self.select_tab('view'); } self.$fields_form = self.$element.find('.oe_translation_form'); + self.$fields_form.find('.oe_trad_field').change(function() { + $(this).toggleClass('touched', ($(this).val() != $(this).attr('data-value'))); + }); }); return this; }, @@ -514,19 +520,27 @@ openerp.base.TranslateDialog = openerp.base.Dialog.extend({ _.each(self.languages, function(lg) { var deff = $.Deferred(); deffered.push(deff); - self.rpc('/base/dataset/get', { - model: self.view.dataset.model, - ids: [self.view.datarecord.id], - fields: self.translatable_fields_keys, - context: self.view.dataset.get_context({ - 'lang': lg.code - }) - }, function(values) { + var callback = function(values) { _.each(self.translatable_fields_keys, function(f) { - self.$fields_form.find('.oe_trad_field[name="' + lg.code + '-' + f + '"]').val(values[0][f] || ''); + self.$fields_form.find('.oe_trad_field[name="' + lg.code + '-' + f + '"]').val(values[0][f] || '').attr('data-value', values[0][f] || ''); }); deff.resolve(); - }); + } + if (lg.code === self.view_language) { + var values = {}; + _.each(self.translatable_fields_keys, function(field) { + values[field] = self.view.fields[field].get_value(); + }); + callback([values]); + } else { + self.rpc('/base/dataset/get', { + model: self.view.dataset.model, + ids: [self.view.datarecord.id], + fields: self.translatable_fields_keys, + context: self.view.dataset.get_context({ + 'lang': lg.code + })}, callback); + } }); $.when.apply(null, deffered).then(callback); }, @@ -562,6 +576,24 @@ openerp.base.TranslateDialog = openerp.base.Dialog.extend({ }); }, on_button_Save: function() { + var trads = {}, + self = this; + self.$fields_form.find('.oe_trad_field.touched').each(function() { + var field = $(this).attr('name').split('-'); + if (!trads[field[0]]) { + trads[field[0]] = {}; + } + trads[field[0]][field[1]] = $(this).val(); + }); + _.each(trads, function(data, code) { + if (code === self.view_language) { + _.each(data, function(value, field) { + self.view.fields[field].set_value(value); + }); + } else { + self.view.dataset.write(self.view.datarecord.id, data, { 'lang': code }); + } + }); this.close(); }, on_button_Close: function() { @@ -667,7 +699,7 @@ openerp.base.View = openerp.base.Widget.extend({ }, { label: "Translate", callback: this.on_sidebar_translate, - classname: 'oe_sidebar_translate' + classname: 'oe_sidebar_translate oe_hide' }, { label: "View Log", callback: this.on_sidebar_view_log, diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index 0c17e70cfc7..40bc7cb4c5a 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -474,8 +474,8 @@ - - + + diff --git a/addons/base_calendar/static/src/js/calendar.js b/addons/base_calendar/static/src/js/calendar.js index 7a0b561ccef..808c1ba31ab 100644 --- a/addons/base_calendar/static/src/js/calendar.js +++ b/addons/base_calendar/static/src/js/calendar.js @@ -251,7 +251,7 @@ openerp.base_calendar.CalendarView = openerp.base.View.extend({ do_save_event: function(event_id, event_obj) { var self = this, data = this.get_event_data(event_obj); - this.dataset.write(parseInt(event_id, 10), data, function() { + this.dataset.write(parseInt(event_id, 10), data, {}, function() { self.refresh_minical(); }); }, diff --git a/addons/base_dashboard/static/src/js/dashboard.js b/addons/base_dashboard/static/src/js/dashboard.js index 3f9da51b157..f83d841d19a 100644 --- a/addons/base_dashboard/static/src/js/dashboard.js +++ b/addons/base_dashboard/static/src/js/dashboard.js @@ -327,7 +327,7 @@ openerp.base_dashboard.ConfigOverview = openerp.base.View.extend({ e.stopImmediatePropagation(); var new_state = this.checked ? 'done' : 'open', todo_id = parseInt($(this).val(), 10); - self.dataset.write(todo_id, {state: new_state}, function () { + self.dataset.write(todo_id, {state: new_state}, {}, function () { self.start(); }); }) diff --git a/addons/base_gantt/static/src/js/gantt.js b/addons/base_gantt/static/src/js/gantt.js index ed28785c90b..ad44382397b 100644 --- a/addons/base_gantt/static/src/js/gantt.js +++ b/addons/base_gantt/static/src/js/gantt.js @@ -459,7 +459,7 @@ init: function(parent, element_id, dataset, view_id) { }else{ data[this.date_delay] = task.getDuration(); } - this.dataset.write(event_id, data, function(result) {}); + this.dataset.write(event_id, data, {}, function(result) {}); }, From 4836945bc9aeafe855b20777f566b620c3d3078d Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 29 Aug 2011 17:24:38 +0200 Subject: [PATCH 42/56] [imp] default setup for reports + put active_id in all actions coming from the sidebar bzr revid: nicolas.vanhoren@openerp.com-20110829152438-47y13wwh01ssq9ts --- addons/base/controllers/main.py | 12 ++++++++++++ addons/base/static/src/js/views.js | 21 ++++++++++++++++----- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index 562571f10de..a198fbde0d1 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -1275,3 +1275,15 @@ class Export(View): return export_xls(field, result) else: return export_csv(field, result) + +class Export(View): + _cp_path = "/base/report" + + @openerpweb.jsonrequest + def get_report(self, req, action): + report_srv = req.session.proxy("report") + context = req.session.eval_context(openerpweb.nonliterals.CompoundContext(req.context, \ + action["context"])) + return False + #report_srv.report(req.session._db, req.session._uid, req.session._password) + diff --git a/addons/base/static/src/js/views.js b/addons/base/static/src/js/views.js index 0fd3df3998d..1fc04bf8965 100644 --- a/addons/base/static/src/js/views.js +++ b/addons/base/static/src/js/views.js @@ -123,6 +123,14 @@ openerp.base.ActionManager = openerp.base.Widget.extend({ this.content_stop(); var ClientWidget = openerp.base.client_actions.get_object(action.tag); (this.client_widget = new ClientWidget(this, action.params)).appendTo(this); + }, + ir_actions_report_xml: function(action) { + this.rpc('/base/report/get_report', { + action: action, + context: {} + }).then(function(result) { + debugger; + }); } }); @@ -438,14 +446,17 @@ openerp.base.Sidebar = openerp.base.Widget.extend({ //TODO niv: maybe show a warning? return false; } + var additional_context = { + active_id: ids[0], + active_ids: ids, + active_model: self.widget_parent.dataset.model + }; self.rpc("/base/action/load", { action_id: item.action.id, - context: { - active_id: ids[0], - active_ids: ids, - active_model: self.widget_parent.dataset.model - } + context: additional_context }, function(result) { + result.result.context = _.extend(result.result.context || {}, + additional_context); result.result.flags = result.result.flags || {}; result.result.flags.new_window = true; self.do_action(result.result); From 73d5d3eaf8d93078e1e5259f397cc9612843653c Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 29 Aug 2011 17:26:43 +0200 Subject: [PATCH 43/56] [imp] added active_id in related coming from m2o bzr revid: nicolas.vanhoren@openerp.com-20110829152643-2yy0p52fqxd6chre --- addons/base/static/src/js/form.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index 7970173780e..e2a99e9b8c5 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -1565,14 +1565,16 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({ var self = this; if (!self.value) return; - self.rpc("/base/action/load", { - action_id: related[2].id, - context: { + var additional_context = { active_id: self.value[0], active_ids: [self.value[0]], active_model: self.field.relation - } + }; + self.rpc("/base/action/load", { + action_id: related[2].id, + context: additional_context }, function(result) { + result.result.context = _.extend(result.result.context || {}, additional_context); self.do_action(result.result); }); } From b479464a36840cd7f83220e182b36cac7f30372e Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 29 Aug 2011 17:52:56 +0200 Subject: [PATCH 44/56] [imp] made web server able to get a report, but still can't get it from the browser bzr revid: nicolas.vanhoren@openerp.com-20110829155256-myi3mr8wlp006u0i --- addons/base/controllers/main.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index a198fbde0d1..c9bd7ddfeab 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -9,6 +9,7 @@ import re import simplejson import textwrap import xmlrpclib +import time from xml.etree import ElementTree from cStringIO import StringIO @@ -20,6 +21,8 @@ import openerpweb.nonliterals from babel.messages.pofile import read_po +_REPORT_POLLER_DELAY = 0.05 + # Should move to openerpweb.Xml2Json class Xml2Json: # xml2json-direct @@ -1284,6 +1287,16 @@ class Export(View): report_srv = req.session.proxy("report") context = req.session.eval_context(openerpweb.nonliterals.CompoundContext(req.context, \ action["context"])) - return False - #report_srv.report(req.session._db, req.session._uid, req.session._password) + + args = [req.session._db, req.session._uid, req.session._password, action["report_name"], context["active_ids"], {"id": context["active_id"], "model": context["active_model"], "report_type": action["report_type"]}, context] + report_id = report_srv.report(*args) + report = None + while True: + args2 = [req.session._db, req.session._uid, req.session._password, report_id] + report = report_srv.report_get(*args2) + if report["state"]: + break + time.sleep(_REPORT_POLLER_DELAY) + #TODO: ok now we've got the report, and so what? + return False From 7ed910290354e52951baef4d6b55556bd62f74d1 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Tue, 30 Aug 2011 10:53:28 +0200 Subject: [PATCH 45/56] [imp] cleaned header a bit, refactored to Widget design and made it disapear on unlog bzr revid: nicolas.vanhoren@openerp.com-20110830085328-zfme7wls9211vzaq --- addons/base/static/src/js/chrome.js | 29 +++++++++++++++++------------ addons/base/static/src/xml/base.xml | 18 +++++++++++------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/addons/base/static/src/js/chrome.js b/addons/base/static/src/js/chrome.js index a4a3b73cc77..e73e0c39445 100644 --- a/addons/base/static/src/js/chrome.js +++ b/addons/base/static/src/js/chrome.js @@ -564,22 +564,25 @@ openerp.base.Login = openerp.base.Widget.extend({ }); openerp.base.Header = openerp.base.Widget.extend({ - init: function(parent, element_id) { - this._super(parent, element_id); - if (jQuery.deparam(jQuery.param.querystring()).debug !== undefined) { - this.qs = '?debug' - } else { - this.qs = '' - } + template: "Header", + identifier_prefix: 'oe-app-header-', + init: function(parent) { + this._super(parent); + this.qs = "?" + jQuery.param.querystring(); + this.$content = $(); }, start: function() { - return this.do_update(); + this._super(); }, do_update: function () { - this.$element.html(QWeb.render("Header", this)); + this.$content = $(QWeb.render("Header-content", {widget: this})); + this.$content.appendTo(this.$element); this.$element.find(".logout").click(this.on_logout); return this.shortcut_load(); }, + do_reset: function() { + this.$content.remove(); + }, shortcut_load :function(){ var self = this, sc = self.session.shortcuts, @@ -749,21 +752,23 @@ openerp.base.WebClient = openerp.base.Widget.extend({ // Do you autorize this ? will be replaced by notify() in controller openerp.base.Widget.prototype.notification = new openerp.base.Notification(this, "oe_notification"); - this.header = new openerp.base.Header(this, "oe_header"); + + this.header = new openerp.base.Header(this); this.login = new openerp.base.Login(this, "oe_login"); this.header.on_logout.add(this.login.on_logout); + this.header.on_action.add(this.on_menu_action); this.session.on_session_invalid.add(this.login.do_ask_login); this.session.on_session_valid.add_last(this.header.do_update); + this.session.on_session_invalid.add_last(this.header.do_reset); this.session.on_session_valid.add_last(this.on_logged); this.menu = new openerp.base.Menu(this, "oe_menu", "oe_secondary_menu"); this.menu.on_action.add(this.on_menu_action); - this.header.on_action.add(this.on_menu_action); }, start: function() { + this.header.appendTo($("#oe_header")); this.session.start(); - this.header.start(); this.login.start(); this.menu.start(); this.notification.notify("OpenERP Client", "The openerp client has been initialized."); diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index 40bc7cb4c5a..c6bd9a1ee19 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -326,15 +326,19 @@ - -