From 49c441b3a494fe561573d9c3e3fdc0856b294c4f Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Tue, 2 Dec 2008 17:47:26 +0100 Subject: [PATCH 001/137] [IMP] move parse_version to tools directory [IMP] release.py set major_version variable bzr revid: christophe@tinyerp.com-20081202164726-0d9d0gz89d6y7v2l --- bin/addons/base/module/module.py | 9 ++++----- bin/release.py | 1 + bin/tools/convert.py | 2 +- bin/tools/misc.py | 2 +- bin/{addons/base/module => tools}/parse_version.py | 0 5 files changed, 7 insertions(+), 7 deletions(-) rename bin/{addons/base/module => tools}/parse_version.py (100%) diff --git a/bin/addons/base/module/module.py b/bin/addons/base/module/module.py index 71005bcec34..32519086e77 100644 --- a/bin/addons/base/module/module.py +++ b/bin/addons/base/module/module.py @@ -35,7 +35,7 @@ import addons import pooler import netsvc -from parse_version import parse_version +from tools.parse_version import parse_version class module_repository(osv.osv): _name = "ir.module.repository" @@ -53,7 +53,7 @@ class module_repository(osv.osv): } _defaults = { 'sequence': lambda *a: 5, - 'filter': lambda *a: 'href="([a-zA-Z0-9_]+)-('+release.version.rsplit('.', 1)[0]+'.(\\d+)((\\.\\d+)*)([a-z]?)((_(pre|p|beta|alpha|rc)\\d*)*)(-r(\\d+))?)(\.zip)"', + 'filter': lambda *a: 'href="([a-zA-Z0-9_]+)-('+release.major_version+'.(\\d+)((\\.\\d+)*)([a-z]?)((_(pre|p|beta|alpha|rc)\\d*)*)(-r(\\d+))?)(\.zip)"', 'active': lambda *a: 1, } _order = "sequence" @@ -91,7 +91,7 @@ class module(osv.osv): data = f.read() info = eval(data) if 'version' in info: - info['version'] = release.version.rsplit('.', 1)[0] + '.' + info['version'] + info['version'] = release.major_version + '.' + info['version'] f.close() except: return {} @@ -326,8 +326,7 @@ class module(osv.osv): if not os.path.isfile( mod_path ): import imp - # XXX must restrict to only addons paths - path = imp.find_module(mod_name) + path = imp.find_module(mod_name, [addons.ad, addons._ad]) imp.load_module(name, *path) else: import zipimport diff --git a/bin/release.py b/bin/release.py index 0a256895bb2..0930f6214aa 100644 --- a/bin/release.py +++ b/bin/release.py @@ -23,6 +23,7 @@ name = 'openerp-server' version = '5.0.0-rc1' +major_version = version.rsplit('.', 1)[0] description = 'OpenERP Server' long_desc = '''\ OpenERP is a complete ERP and CRM. The main features are accounting (analytic diff --git a/bin/tools/convert.py b/bin/tools/convert.py index 01b6a0f0af8..ee7c1c53ee8 100644 --- a/bin/tools/convert.py +++ b/bin/tools/convert.py @@ -92,7 +92,7 @@ def _eval_xml(self,node, pool, cr, uid, idref, context=None): idref2['time'] = time idref2['DateTime'] = DateTime import release - idref2['version'] = release.version.rsplit('.', 1)[0] + idref2['version'] = release.major_version idref2['ref'] = lambda x: self.id_get(cr, False, x) if len(f_model): idref2['obj'] = _obj(self.pool, cr, uid, f_model, context=context) diff --git a/bin/tools/misc.py b/bin/tools/misc.py index cc71dd6886f..6d65a425484 100644 --- a/bin/tools/misc.py +++ b/bin/tools/misc.py @@ -104,7 +104,7 @@ def init_db(cr): category_id, state) \ values (%d, %s, %s, %s, %s, %s, %s, %d, %s)', ( id, info.get('author', ''), - release.version.rsplit('.', 1)[0] + '.' + info.get('version', ''), + release.major_version + '.' + info.get('version', ''), info.get('website', ''), i, info.get('name', False), info.get('description', ''), p_id, state)) dependencies = info.get('depends', []) diff --git a/bin/addons/base/module/parse_version.py b/bin/tools/parse_version.py similarity index 100% rename from bin/addons/base/module/parse_version.py rename to bin/tools/parse_version.py From a5e5b5b8fc35572b4be95ab78a9ebe2a506f9858 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Tue, 2 Dec 2008 19:38:21 +0100 Subject: [PATCH 002/137] [IMP] views don't need to include the state field anymore to be state aware bzr revid: christophe@tinyerp.com-20081202183821-iodzmaanf3ib0asb --- bin/osv/orm.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index c0c44e608b7..0803a7ace38 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -847,6 +847,10 @@ class orm_template(object): if childs: for f in node.childNodes: fields.update(self.__view_look_dom(cr, user, f, context)) + + if ('state' not in fields) and (('state' in self._columns) or ('state' in self._inherit_fields)): + fields['state'] = {} + return fields def __view_look_dom_arch(self, cr, user, node, context=None): From 086fbc2d4d986e9d22d13c4ad65fd9fade250b44 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Wed, 3 Dec 2008 15:42:26 +0100 Subject: [PATCH 003/137] bugfix bzr revid: fp@tinyerp.com-20081203144226-bm9zfqe4e1olemd2 --- bin/workflow/wkf_expr.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/workflow/wkf_expr.py b/bin/workflow/wkf_expr.py index 60d27b1c395..5c5858ccc3f 100644 --- a/bin/workflow/wkf_expr.py +++ b/bin/workflow/wkf_expr.py @@ -66,6 +66,7 @@ def _eval_expr(cr, ident, workitem, action): ret=False assert action, 'You used a NULL action in a workflow, use dummy node instead.' for line in action.split('\n'): + line = line.replace(chr(13),'') uid=ident[0] model=ident[1] ids=[ident[2]] From 23d5e09e286cf7d5d8f80ac8d6f3313a50bb0ea3 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Thu, 4 Dec 2008 16:36:56 +0100 Subject: [PATCH 004/137] [IMP] move oswalksymlinks to a new module tools.osutil bzr revid: christophe@tinyerp.com-20081204153656-l247acif1eqvyvl0 --- bin/tools/misc.py | 17 ------------ bin/tools/osutil.py | 63 ++++++++++++++++++++++++++++++++++++++++++ bin/tools/translate.py | 2 +- 3 files changed, 64 insertions(+), 18 deletions(-) create mode 100644 bin/tools/osutil.py diff --git a/bin/tools/misc.py b/bin/tools/misc.py index 6d65a425484..6c6efc5438b 100644 --- a/bin/tools/misc.py +++ b/bin/tools/misc.py @@ -252,23 +252,6 @@ def file_open(name, mode="r", subdir='addons', pathinfo=False): raise IOError, 'File not found : '+str(name) -def oswalksymlinks(top, topdown=True, onerror=None): - """ - same as os.walk but follow symlinks - attention: all symlinks are walked before all normals directories - """ - for dirpath, dirnames, filenames in os.walk(top, topdown, onerror): - if topdown: - yield dirpath, dirnames, filenames - - symlinks = filter(lambda dirname: os.path.islink(os.path.join(dirpath, dirname)), dirnames) - for s in symlinks: - for x in oswalksymlinks(os.path.join(dirpath, s), topdown, onerror): - yield x - - if not topdown: - yield dirpath, dirnames, filenames - #---------------------------------------------------------- # iterables #---------------------------------------------------------- diff --git a/bin/tools/osutil.py b/bin/tools/osutil.py new file mode 100644 index 00000000000..ba1d650f4ef --- /dev/null +++ b/bin/tools/osutil.py @@ -0,0 +1,63 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2008 Tiny SPRL (). All Rights Reserved +# $Id$ +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## + +""" +Some functions related to the os and os.path module +""" + +import os +from os.path import join as opj + +def listdir(dir, recursive=False): + """Allow to recursively get the file listing""" + dir = os.path.normpath(dir) + if not recursive: + return os.listdir(dir) + + res = [] + for root, dirs, files in os.walk(dir): + root = root[len(dir)+1:] + res.extend([opj(root, f) for f in files]) + return res + +def walksymlinks(top, topdown=True, onerror=None): + """ + same as os.walk but follow symlinks + attention: all symlinks are walked before all normals directories + """ + for dirpath, dirnames, filenames in os.walk(top, topdown, onerror): + if topdown: + yield dirpath, dirnames, filenames + + symlinks = filter(lambda dirname: os.path.islink(os.path.join(dirpath, dirname)), dirnames) + for s in symlinks: + for x in walksymlinks(os.path.join(dirpath, s), topdown, onerror): + yield x + + if not topdown: + yield dirpath, dirnames, filenames + + + +if __name__ == '__main__': + from pprint import pprint as pp + pp(listdir('../report', True)) diff --git a/bin/tools/translate.py b/bin/tools/translate.py index 5163fa6c7e4..8a20541210f 100644 --- a/bin/tools/translate.py +++ b/bin/tools/translate.py @@ -452,7 +452,7 @@ def trans_generate(lang, modules, dbname=None): installed_modids = modobj.search(cr, uid, [('state', '=', 'installed')]) installed_modules = map(lambda m: m['name'], modobj.read(cr, uid, installed_modids, ['name'])) - for root, dirs, files in tools.oswalksymlinks(tools.config['root_path']): + for root, dirs, files in tools.osutil.walksymlinks(tools.config['root_path']): for fname in fnmatch.filter(files, '*.py'): fabsolutepath = join(root, fname) frelativepath = fabsolutepath[len(tools.config['root_path'])+1:] From c6d7af80f310503fdcb32d12bfe79286b5572372 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Thu, 4 Dec 2008 17:11:41 +0100 Subject: [PATCH 005/137] [IMP] Implement the migration by module bzr revid: christophe@tinyerp.com-20081204161141-d1yjjos76ajodqt0 --- bin/addons/__init__.py | 270 ++++++++++++++++++++++++++++++++++------- 1 file changed, 226 insertions(+), 44 deletions(-) diff --git a/bin/addons/__init__.py b/bin/addons/__init__.py index afd92ee26f8..4eeed2e23c6 100644 --- a/bin/addons/__init__.py +++ b/bin/addons/__init__.py @@ -21,11 +21,13 @@ ############################################################################## import os, sys, imp +from os.path import join as opj import itertools from sets import Set import osv import tools +import tools.osutil import pooler @@ -33,11 +35,10 @@ import netsvc from osv import fields import zipfile +import release logger = netsvc.Logger() -opj = os.path.join - _ad = os.path.abspath(opj(tools.config['root_path'], 'addons')) # default addons path (base) ad = os.path.abspath(tools.config['addons_path']) # alternate addons path @@ -137,10 +138,41 @@ def get_module_path(module): if os.path.exists(opj(_ad, module)) or os.path.exists(opj(_ad, '%s.zip' % module)): return opj(_ad, module) - logger.notifyChannel('init', netsvc.LOG_WARNING, 'addon:%s:module not found' % (module,)) + logger.notifyChannel('init', netsvc.LOG_WARNING, 'addon %s: module not found' % (module,)) return False raise IOError, 'Module not found : %s' % module + +def get_module_filetree(module, dir='.'): + path = get_module_path(module) + if not path: + return False + + dir = os.path.normpath(dir) + if dir == '.': dir = '' + if dir.startswith('..') or dir[0] == '/': + raise Exception('Cannot access file outside the module') + + if not os.path.isdir(path): + # zipmodule + zip = zipfile.ZipFile(path + ".zip") + files = ['/'.join(f.split('/')[1:]) for f in zip.namelist()] + else: + files = tools.osutil.listdir(path, True) + + tree = {} + for f in files: + if not f.startswith(dir): + continue + f = f[len(dir)+int(not dir.endswith('/')):] + lst = f.split(os.sep) + current = tree + while len(lst) != 1: + current = current.setdefault(lst.pop(0), {}) + current[lst.pop(0)] = None + + return tree + def get_module_resource(module, *args): """Return the full path of a resource of the given module. @@ -184,7 +216,7 @@ def create_graph(module_list, force=None): try: info = eval(tools.file_open(terp_file).read()) except: - logger.notifyChannel('init', netsvc.LOG_ERROR, 'addon:%s:eval file %s' % (module, terp_file)) + logger.notifyChannel('init', netsvc.LOG_ERROR, 'addon %s: eval file %s' % (module, terp_file)) raise if info.get('installable', True): packages.append((module, info.get('depends', []), info)) @@ -192,7 +224,7 @@ def create_graph(module_list, force=None): dependencies = dict([(p, deps) for p, deps, data in packages]) current, later = Set([p for p, dep, data in packages]), Set() while packages and current > later: - package, deps, datas = packages[0] + package, deps, data = packages[0] # if all dependencies of 'package' are already in the graph, add 'package' in the graph if reduce(lambda x,y: x and y in graph, deps, True): @@ -203,24 +235,24 @@ def create_graph(module_list, force=None): current.remove(package) graph.addNode(package, deps) node = Node(package, graph) - node.datas = datas + node.data = data for kind in ('init', 'demo', 'update'): if package in tools.config[kind] or 'all' in tools.config[kind] or kind in force: setattr(node, kind, True) else: later.add(package) - packages.append((package, deps, datas)) + packages.append((package, deps, data)) packages.pop(0) for package in later: unmet_deps = filter(lambda p: p not in graph, dependencies[package]) - logger.notifyChannel('init', netsvc.LOG_ERROR, 'addon:%s:Unmet dependencies: %s' % (package, ', '.join(unmet_deps))) + logger.notifyChannel('init', netsvc.LOG_ERROR, 'addon %s: Unmet dependencies: %s' % (package, ', '.join(unmet_deps))) return graph def init_module_objects(cr, module_name, obj_list): pool = pooler.get_pool(cr.dbname) - logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:creating or updating database tables' % module_name) + logger.notifyChannel('init', netsvc.LOG_INFO, 'addon %s: creating or updating database tables' % module_name) for obj in obj_list: if hasattr(obj, 'init'): obj.init(cr) @@ -234,12 +266,11 @@ def register_class(m): global loaded if m in loaded: return - logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:registering classes' % m) - sys.stdout.flush() + logger.notifyChannel('init', netsvc.LOG_INFO, 'addon %s: registering classes' % m) loaded.append(m) mod_path = get_module_path(m) if not os.path.isfile(mod_path+'.zip'): - imp.load_module(m, *imp.find_module(m)) + imp.load_module(m, *imp.find_module(m, [ad, _ad])) else: import zipimport try: @@ -248,14 +279,140 @@ def register_class(m): except zipimport.ZipImportError: logger.notifyChannel('init', netsvc.LOG_ERROR, 'Couldn\'t find module %s' % m) -def register_classes(): - return - module_list = get_modules() - for package in create_graph(module_list): - m = package.name - register_class(m) - logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:registering classes' % m) - sys.stdout.flush() + +class MigrationManager(object): + """ + This class manage the migration of modules + Migrations files must be python files containing a "migrate(cr, installed_version)" function. + Theses files must respect a directory tree structure: A 'migrations' folder which containt a + folder by version. Version can be 'module' version or 'server.module' version (in this case, + the files will only be processed by this version of the server). Python file names must start + by 'pre' or 'post' and will be executed, respectively, before and after the module initialisation + Example: + + + `-- migrations + |-- 1.0 + | |-- pre-update_table_x.py + | |-- pre-update_table_y.py + | |-- post-clean-data.py + | `-- README.txt # not processed + |-- 5.0.1.1 # files in this folder will be executed only on a 5.0 server + | |-- pre-delete_table_z.py + | `-- post-clean-data.py + `-- foo.py # not processed + + This similar structure is generated by the maintenance module with the migrations files get by + the maintenance contract + + """ + def __init__(self, cr, graph): + self.cr = cr + self.graph = graph + self.migrations = {} + self._get_files() + + def _get_files(self): + + """ + import addons.base.maintenance.utils as maintenance_utils + maintenance_utils.update_migrations_files(self.cr) + #""" + + for pkg in self.graph: + self.migrations[pkg.name] = {} + if not (hasattr(pkg, 'update') or pkg.state == 'to upgrade'): + continue + + self.migrations[pkg.name]['module'] = get_module_filetree(pkg.name, 'migrations') or {} + self.migrations[pkg.name]['maintenance'] = get_module_filetree('base', 'maintenance/migrations/' + pkg.name) or {} + + + def migrate_module(self, pkg, stage): + assert stage in ('pre', 'post') + stageformat = {'pre': '[>%s]', + 'post': '[%s>]', + } + + if not (hasattr(pkg, 'update') or pkg.state == 'to upgrade'): + return + + def convert_version(version): + if version.startswith(release.major_version) and version != release.major_version: + return version # the version number already containt the server version + return "%s.%s" % (release.major_version, version) + + def _get_migration_versions(pkg): + def __get_dir(tree): + return [d for d in tree if tree[d] is not None] + + versions = list(set( + __get_dir(self.migrations[pkg.name]['module']) + + __get_dir(self.migrations[pkg.name]['maintenance']) + )) + versions.sort(key=lambda k: parse_version(convert_version(k))) + return versions + + def _get_migration_files(pkg, version, stage): + """ return a list of tuple (module, file) + """ + m = self.migrations[pkg.name] + lst = [] + + mapping = {'module': {'module': pkg.name, 'rootdir': opj('migrations')}, + 'maintenance': {'module': 'base', 'rootdir': opj('maintenance', 'migrations', pkg.name)}, + } + + for x in mapping.keys(): + if version in m[x]: + for f in m[x][version]: + if m[x][version][f] is not None: + continue + if not f.startswith(stage + '-'): + continue + lst.append((mapping[x]['module'], opj(mapping[x]['rootdir'], version, f))) + return lst + + def mergedict(a,b): + a = a.copy() + a.update(b) + return a + + from tools.parse_version import parse_version + + parsed_installed_version = parse_version(pkg.latest_version) + current_version = parse_version(convert_version(pkg.data.get('version', '0'))) + + versions = _get_migration_versions(pkg) + + for version in versions: + if parsed_installed_version < parse_version(convert_version(version)) <= current_version: + + strfmt = {'addon': pkg.name, + 'stage': stage, + 'version': stageformat[stage] % version, + } + + for modulename, pyfile in _get_migration_files(pkg, version, stage): + name, ext = os.path.splitext(os.path.basename(pyfile)) + if ext.lower() != '.py': + continue + fp = tools.file_open(opj(modulename, pyfile)) + mod = None + try: + mod = imp.load_source(name, pyfile, fp) + logger.notifyChannel('migration', netsvc.LOG_INFO, 'addon %(addon)s: Running migration %(version)s %(name)s"' % mergedict({'name': mod.__name__},strfmt)) + mod.migrate(self.cr, pkg.latest_version) + except ImportError: + logger.notifyChannel('migration', netsvc.LOG_ERROR, 'addon %(addon)s: Unable to load %(stage)-migration file %(file)s' % mergedict({'file': opj(modulename,pyfile)}, strfmt)) + raise + except AttributeError: + logger.notifyChannel('migration', netsvc.LOG_ERROR, 'addon %(addon)s: Each %(stage)-migration file must have a "migrate(cr, installed_version)" function' % strfmt) + except: + raise + fp.close() + del mod + def load_module_graph(cr, graph, status=None, **kwargs): # **kwargs is passed directly to convert_xml_import @@ -265,54 +422,75 @@ def load_module_graph(cr, graph, status=None, **kwargs): status = status.copy() package_todo = [] statusi = 0 + pool = pooler.get_pool(cr.dbname) + + # update the graph with values from the database (if exist) + ## First, we set the default values for each package in graph + additional_data = dict.fromkeys([p.name for p in graph], {'id': 0, 'state': 'uninstalled', 'dbdemo': False, 'latest_version': None}) + ## Then we get the values from the database + cr.execute('SELECT name, id, state, demo AS dbdemo, latest_version' + ' FROM ir_module_module' + ' WHERE name in (%s)' % (','.join(['%s'] * len(graph))), + additional_data.keys() + ) + ## and we update the default values with values from the database + additional_data.update(dict([(x.pop('name'), x) for x in cr.dictfetchall()])) + + for package in graph: + for k, v in additional_data[package.name].items(): + setattr(package, k, v) + + migrations = MigrationManager(cr, graph) + for package in graph: status['progress'] = (float(statusi)+0.1)/len(graph) m = package.name + mid = package.id + + migrations.migrate_module(package, 'pre') + register_class(m) - logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s' % m) - sys.stdout.flush() - pool = pooler.get_pool(cr.dbname) + logger.notifyChannel('init', netsvc.LOG_INFO, 'addon %s' % m) modules = pool.instanciate(m, cr) - cr.execute('select id from ir_module_module where name=%s', (m,)) - mid = int(cr.rowcount and cr.fetchone()[0] or 0) - - cr.execute('select state, demo from ir_module_module where id=%d', (mid,)) - (package_state, package_demo) = (cr.rowcount and cr.fetchone()) or ('uninstalled', False) idref = {} status['progress'] = (float(statusi)+0.4)/len(graph) - if hasattr(package, 'init') or hasattr(package, 'update') or package_state in ('to install', 'to upgrade'): + if hasattr(package, 'init') or hasattr(package, 'update') or package.state in ('to install', 'to upgrade'): init_module_objects(cr, m, modules) for kind in ('init', 'update'): - for filename in package.datas.get('%s_xml' % kind, []): + for filename in package.data.get('%s_xml' % kind, []): mode = 'update' - if hasattr(package, 'init') or package_state=='to install': + if hasattr(package, 'init') or package.state=='to install': mode = 'init' - logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:loading %s' % (m, filename)) + logger.notifyChannel('init', netsvc.LOG_INFO, 'addon %s: loading %s' % (m, filename)) name, ext = os.path.splitext(filename) + fp = tools.file_open(opj(m, filename)) if ext == '.csv': - tools.convert_csv_import(cr, m, os.path.basename(filename), tools.file_open(opj(m, filename)).read(), idref, mode=mode) + tools.convert_csv_import(cr, m, os.path.basename(filename), fp.read(), idref, mode=mode) elif ext == '.sql': - queries = tools.file_open(opj(m, filename)).read().split(';') + queries = fp.read().split(';') for query in queries: new_query = ' '.join(query.split()) if new_query: cr.execute(new_query) else: - tools.convert_xml_import(cr, m, tools.file_open(opj(m, filename)), idref, mode=mode, **kwargs) - if hasattr(package, 'demo') or (package_demo and package_state != 'installed'): + tools.convert_xml_import(cr, m, fp, idref, mode=mode, **kwargs) + fp.close() + if hasattr(package, 'demo') or (package.dbdemo and package.state != 'installed'): status['progress'] = (float(statusi)+0.75)/len(graph) - for xml in package.datas.get('demo_xml', []): + for xml in package.data.get('demo_xml', []): name, ext = os.path.splitext(xml) - logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:loading %s' % (m, xml)) + logger.notifyChannel('init', netsvc.LOG_INFO, 'addon %s: loading %s' % (m, xml)) + fp = tools.file_open(opj(m, xml)) if ext == '.csv': - tools.convert_csv_import(cr, m, os.path.basename(xml), tools.file_open(opj(m, xml)).read(), idref, noupdate=True) + tools.convert_csv_import(cr, m, os.path.basename(xml), fp.read(), idref, noupdate=True) else: - tools.convert_xml_import(cr, m, tools.file_open(opj(m, xml)), idref, noupdate=True, **kwargs) + tools.convert_xml_import(cr, m, fp, idref, noupdate=True, **kwargs) + fp.close() cr.execute('update ir_module_module set demo=%s where id=%d', (True, mid)) package_todo.append(package.name) - cr.execute("update ir_module_module set state='installed' where state in ('to upgrade', 'to install') and id=%d", (mid,)) - + ver = release.major_version + '.' + package.data.get('version', '1.0') + cr.execute("update ir_module_module set state='installed', latest_version=%s where id=%d", (ver, mid,)) cr.commit() # Update translations for all installed languages @@ -320,12 +498,15 @@ def load_module_graph(cr, graph, status=None, **kwargs): if modobj: modobj.update_translations(cr, 1, [mid], None) cr.commit() + + + migrations.migrate_module(package, 'post') statusi+=1 cr.execute("""select model,name from ir_model where id not in (select model_id from ir_model_access)""") for (model,name) in cr.fetchall(): - logger.notifyChannel('init', netsvc.LOG_WARNING, 'addon:object %s (%s) has no access rules!' % (model,name)) + logger.notifyChannel('init', netsvc.LOG_WARNING, 'addon object %s (%s) has no access rules!' % (model,name)) pool = pooler.get_pool(cr.dbname) cr.execute('select * from ir_model where state=%s', ('manual',)) @@ -344,6 +525,7 @@ def load_modules(db, force_demo=False, status=None, update_module=False): force.append('demo') if update_module: for module in tools.config['init']: + # FIXME lp:304807 cr.execute('update ir_module_module set state=%s where state=%s and name=%s', ('to install', 'uninstalled', module)) cr.commit() cr.execute("select name from ir_module_module where state in ('installed', 'to install', 'to upgrade','to remove')") @@ -354,7 +536,7 @@ def load_modules(db, force_demo=False, status=None, update_module=False): report = tools.assertion_report() load_module_graph(cr, graph, status, report=report) if report.get_report(): - logger.notifyChannel('init', netsvc.LOG_INFO, 'assert:%s' % report) + logger.notifyChannel('init', netsvc.LOG_INFO, 'assert: %s' % report) for kind in ('init', 'demo', 'update'): tools.config[kind]={} From 99580094e338d05d91b1b5c13eeb18eb10c959ee Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Thu, 4 Dec 2008 21:28:32 +0100 Subject: [PATCH 006/137] improved_security bzr revid: fp@tinyerp.com-20081204202832-4cyln2cynhgkk1b6 --- bin/addons/base/security/ir.model.access.csv | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/addons/base/security/ir.model.access.csv b/bin/addons/base/security/ir.model.access.csv index d5481114af8..d70a91201b9 100644 --- a/bin/addons/base/security/ir.model.access.csv +++ b/bin/addons/base/security/ir.model.access.csv @@ -22,6 +22,7 @@ "access_ir_module_module_dependency_group_system","ir_module_module_dependency group_system","model_ir_module_module_dependency","group_system",1,1,1,1 "access_ir_module_repository_group_system","ir_module_repository group_system","model_ir_module_repository","group_system",1,1,1,1 "access_ir_property_group_user","ir_property group_user","model_ir_property",,1,0,0,0 +"access_ir_property_group_user_manager","ir_property group_manager","model_ir_property",base.group_partner_manager,1,1,1,1 "access_ir_report_custom_group_system","ir_report_custom group_system","model_ir_report_custom",,1,0,0,0 "access_ir_report_custom_fields_group_system","ir_report_custom_fields group_system","model_ir_report_custom_fields",,1,0,0,0 "access_ir_rule_group_user","ir_rule group_user","model_ir_rule",,1,0,0,0 From 6f24369ba291cbe01de325e508b11cb50aa4a421 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Fri, 5 Dec 2008 00:58:43 +0100 Subject: [PATCH 007/137] improved_view bzr revid: fp@tinyerp.com-20081204235843-uwp1poxk0rinjsbu --- bin/addons/base/ir/ir.xml | 14 +++++++++----- bin/addons/base/ir/ir_actions.py | 9 +++++++-- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/bin/addons/base/ir/ir.xml b/bin/addons/base/ir/ir.xml index 1ab2ad0aa79..0e195d3980a 100644 --- a/bin/addons/base/ir/ir.xml +++ b/bin/addons/base/ir/ir.xml @@ -1154,19 +1154,23 @@ - + + + + + - - + + - + - + diff --git a/bin/addons/base/ir/ir_actions.py b/bin/addons/base/ir/ir_actions.py index 2e2da804b24..41ebe76ba51 100644 --- a/bin/addons/base/ir/ir_actions.py +++ b/bin/addons/base/ir/ir_actions.py @@ -371,6 +371,7 @@ class actions_server(osv.osv): _columns = { 'name': fields.char('Action Name', required=True, size=64), 'state': fields.selection([ + ('client_action','Client Action'), ('python','Python Code'), ('dummy','Dummy'), ('trigger','Trigger'), @@ -378,12 +379,12 @@ class actions_server(osv.osv): ('sms','SMS'), ('object_create','Create Object'), ('object_write','Write Object'), - ('client_action','Client Action'), ('other','Others Actions'), - ], 'Action State', required=True, size=32, change_default=True), + ], 'Action State', required=True, size=32), 'code': fields.text('Python Code'), 'sequence': fields.integer('Sequence'), 'model_id': fields.many2one('ir.model', 'Object', required=True), + 'action_id': fields.many2one('ir.actions.actions', 'Client Action'), 'trigger_name': fields.char('Trigger Name', size=128), 'trigger_obj_id': fields.reference('Trigger On', selection=model_get, size=128), 'message': fields.text('Message', translate=True), @@ -457,6 +458,10 @@ class actions_server(osv.osv): def run(self, cr, uid, ids, context={}): logger = netsvc.Logger() for action in self.browse(cr, uid, ids, context): + if action.state=='client_action': + if not action.action_id: + raise osv.except_osv(_('Error'), _("Please specify an action to launch !")) + return self.pool.get(action.action_id.type).read(cr, uid, action.action_id.id, context=context) if action.state=='python': localdict = { 'self': self.pool.get(action.model_id.model), From 17d926706f6e112965890aa4d065bfa157b6f0e1 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Fri, 5 Dec 2008 11:05:08 +0100 Subject: [PATCH 008/137] improve bzr revid: fp@tinyerp.com-20081205100508-dn5fh7gow0udnyjw --- bin/addons/base/security/ir.model.access.csv | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/addons/base/security/ir.model.access.csv b/bin/addons/base/security/ir.model.access.csv index d70a91201b9..41710001246 100644 --- a/bin/addons/base/security/ir.model.access.csv +++ b/bin/addons/base/security/ir.model.access.csv @@ -39,7 +39,8 @@ "access_ir_ui_view_custom_group_user","ir_ui_view_custom_group_user","model_ir_ui_view_custom",,1,0,0,0 "access_ir_ui_view_custom_group_system","ir_ui_view_custom_group_system","model_ir_ui_view_custom","group_system",1,1,1,1 "access_ir_ui_view_sc_group_user","ir_ui_view_sc group_user","model_ir_ui_view_sc",,1,1,1,1 -"access_ir_values_group_erp_manager","ir_values group_erp_manager","model_ir_values",,1,1,1,1 +"access_ir_values_group_erp_manager","ir_values group_erp_manager","model_ir_values",group_erp_manager,1,1,1,1 +"access_ir_values_group_all","ir_values group_all","model_ir_values",,1,0,0,0 "access_wizard_ir_model_menu_create_group_system","wizard_ir_model_menu_create group_system","model_wizard_ir_model_menu_create","group_system",1,1,1,1 "access_wizard_ir_model_menu_create_line_group_system","wizard_ir_model_menu_create_line group_system","model_wizard_ir_model_menu_create_line","group_system",1,1,1,1 "access_wizard_module_lang_export_group_system","wizard_module_lang_export group_system","model_wizard_module_lang_export","group_system",1,1,1,1 From 3332f26cc2244aaeabde71dce2d8a9e96a1d75bb Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Fri, 5 Dec 2008 12:54:09 +0100 Subject: [PATCH 009/137] [FIX] fix the access rights verification in attachments bzr revid: christophe@tinyerp.com-20081205115409-rlk3mq4fw89f1hue --- bin/addons/base/ir/ir_attachment.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/bin/addons/base/ir/ir_attachment.py b/bin/addons/base/ir/ir_attachment.py index e71b227fcff..e1a04a5f85a 100644 --- a/bin/addons/base/ir/ir_attachment.py +++ b/bin/addons/base/ir/ir_attachment.py @@ -52,12 +52,11 @@ class ir_attachment(osv.osv): cache = {} ima = self.pool.get('ir.model.access') for m in models: - if m['res_model'] in cache: - if not cache[m['res_model']]: - ids.remove(m['id']) - continue - cache[m['res_model']] = ima.check(cr, uid, m['res_model'], 'read', - raise_exception=False) + if m['res_model'] not in cache: + cache[m['res_model']] = ima.check(cr, uid, m['res_model'], 'read', + raise_exception=False) + if not cache[m['res_model']]: + ids.remove(m['id']) if count: return len(ids) From b9a785f88660eabf316d59bb07fadc5a053d75e5 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Fri, 5 Dec 2008 13:11:57 +0100 Subject: [PATCH 010/137] [IMP] make bank.type name and bank.type.field name translatable (patch from Activity Solutions) bzr revid: christophe@tinyerp.com-20081205121157-ose6felchwrkyxqs --- bin/addons/base/res/partner/partner.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/addons/base/res/partner/partner.py b/bin/addons/base/res/partner/partner.py index e7dfbb08605..12a82d2b6cd 100644 --- a/bin/addons/base/res/partner/partner.py +++ b/bin/addons/base/res/partner/partner.py @@ -334,7 +334,7 @@ class res_partner_bank_type(osv.osv): _description='Bank Account Type' _name = 'res.partner.bank.type' _columns = { - 'name': fields.char('Name', size=64, required=True), + 'name': fields.char('Name', size=64, required=True, translate=True), 'code': fields.char('Code', size=64, required=True), 'field_ids': fields.one2many('res.partner.bank.type.field', 'bank_type_id', 'Type fields'), } @@ -344,7 +344,7 @@ class res_partner_bank_type_fields(osv.osv): _description='Bank type fields' _name = 'res.partner.bank.type.field' _columns = { - 'name': fields.char('Field name', size=64, required=True), + 'name': fields.char('Field name', size=64, required=True, translate=True), 'bank_type_id': fields.many2one('res.partner.bank.type', 'Bank type', required=True, ondelete='cascade'), 'required': fields.boolean('Required'), 'readonly': fields.boolean('Readonly'), From eb0880955379c1d033ae57871211dcdcffa585a9 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Fri, 5 Dec 2008 13:41:58 +0100 Subject: [PATCH 011/137] [FIX] orm: searching an inexisting id (as integer) return False (patch from Activity Solutions) bzr revid: christophe@tinyerp.com-20081205124158-hjmig1c8gyp9qme3 --- bin/osv/orm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index 0803a7ace38..8a883729e79 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -1801,7 +1801,7 @@ class orm(orm_template): if v == None: r[key] = False if isinstance(ids, (int, long)): - return result[0] + return result and result[0] or False return result def _read_flat(self, cr, user, ids, fields_to_read, context=None, load='_classic_read'): From f770e5e65f84d3680834c0c059523cbb525ed33a Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Fri, 5 Dec 2008 13:56:41 +0100 Subject: [PATCH 012/137] [FIX] report/print_xml.py: use the record when evaluate the expression (patch from Activity Solutions) bzr revid: christophe@tinyerp.com-20081205125641-pmdcma8mlsny7fei --- bin/report/print_xml.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/report/print_xml.py b/bin/report/print_xml.py index e161109d4d6..f5b66d8a88d 100644 --- a/bin/report/print_xml.py +++ b/bin/report/print_xml.py @@ -121,7 +121,7 @@ class document(object): #Pinky: Why not this ? eval(expr, browser) ? # name = browser.name # data_dict = browser._data[self.get_value(browser, 'id')] - return eval(expr) + return eval(expr, {}, {'obj': record}) def parse_node(self, node, parent, browser, datas=None): # node is the node of the xml template to be parsed From 49916d38fd95ee7cd163f5221306f8a84019ca72 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Fri, 5 Dec 2008 14:10:29 +0100 Subject: [PATCH 013/137] [IMP] amount_to_text: add a function allowing to register a convertion function (patch from Activity Solutions) bzr revid: christophe@tinyerp.com-20081205131029-s05x7qtisskcekzw --- bin/tools/amount_to_text.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bin/tools/amount_to_text.py b/bin/tools/amount_to_text.py index 301efcbcccf..9e080bebfc7 100644 --- a/bin/tools/amount_to_text.py +++ b/bin/tools/amount_to_text.py @@ -171,6 +171,9 @@ def amount_to_text_nl(number, currency): #------------------------------------------------------------- _translate_funcs = {'fr' : amount_to_text_fr, 'nl' : amount_to_text_nl} + +def add_amount_to_text_function(lang, func): + _translate_funcs[lang] = func #TODO: we should use the country AND language (ex: septante VS soixante dix) #TODO: we should use en by default, but the translation func is yet to be implemented From bcca622a6e8056336e41363fc1b19e266b1d0e33 Mon Sep 17 00:00:00 2001 From: Husen Daudi Date: Fri, 5 Dec 2008 19:06:12 +0530 Subject: [PATCH 014/137] added states data bzr revid: hda@tinyerp.com-20081205133612-tula3gt59dzic23m --- bin/addons/base/base_data.xml | 1386 +++++++++++++++++++++++++++++++++ 1 file changed, 1386 insertions(+) diff --git a/bin/addons/base/base_data.xml b/bin/addons/base/base_data.xml index 30b3464eb9a..e41fccfe682 100644 --- a/bin/addons/base/base_data.xml +++ b/bin/addons/base/base_data.xml @@ -1255,7 +1255,1393 @@ wy + + + + Al Baḩr al Aḩmar + aba + + + + + Al Buhayrat + bu + + + + + Al Jazirah + aj + + + + + Al Khartum + ak + + + + + Al Qadarif + aq + + + + + Al Wahdah + aw + + + + + An Nil + an + + + + + An Nil al Abyad + ana + + + + + An Nil al Azraq + ana + + + + + Ash Shamaliyah + as + + + + + A ali an Nil + aan + + + + + Baḩr al Jabal + baj + + + + + Gharb al Istiwaiyah + gai + + + + + Gharb Bahr al Ghazal + gbg + + + + + Gharb Darfur + gd + + + + + Janub Darfur + jd + + + + + Janub Kurdufan + jk + + + + + Junqali + ju + + + + + Kassala + kas + + + + + Shamal Bahr al Ghazal + sbg + + + + + Shamal Darfur + sd + + + + + Shamal Kurdufan + sk + + + + + Sharq al Istiwaiyah + si + + + + + Sinnar + sn + + + + + Warab + war + + + + + Aimeliik + aim + + + + + Airai + air + + + + + Angaur + ang + + + + + Hatobohei + hat + + + + + Kayangel + kay + + + + + Koror + kor + + + + + Melekeok + mel + + + + + Ngaraard + ng + + + + + Ngarchelong + ngr + + + + + Ngardmau + ngr + + + + + Ngatpang + ngt + + + + + Ngchesar + ngc + + + + + Ngeremlengui + ngr + + + + + Ngiwal + ngi + + + + + Peleliu + pel + + + + + Sonsorol + son + + + + + Abia + ab + + + + + Adamawa + ad + + + + + Akwa Ibom + AK + + + + + Anambra + AN + + + + + Bauchi + BA + + + + + Bayelsa + BY + + + + + Benue + BE + + + + + Borno + BO + + + + + Cross River + CR + + + + + Delta + DE + + + + + Ebonyi + EB + + + + + Edo + ED + + + + + Ekiti + EK + + + + + Enugu + EN + + + + + Gombe + GO + + + + + Imo + IM + + + + + Jigawa + JI + + + + + Kaduna + KD + + + + + Kano + KN + + + + + Katsina + KT + + + + + Kebbi + KE + + + + + Kogi + KO + + + + + Kwara + KW + + + + + Lagos + LA + + + + + Nassarawa + NA + + + + + Niger + NI + + + + + Ogun + OG + + + + + Ondo + ON + + + + + Osun + OS + + + + + Oyo + OY + + + + + Plateau + PL + + + + + Rivers + RI + + + + + Sokoto + SO + + + + + Taraba + TA + + + + + Yobe + YO + + + + + Zamfara + ZA + + + + + Johor + jo + + + + + Kedah + ke + + + + + Kelantan + kel + + + + + Melaka + mel + + + + + Negeri Sembilan + ns + + + + + Pahang + pah + + + + + Perak + per + + + + + Perlis + per + + + + + Pulau Pinang + pp + + + + + Sabah + sab + + + + + Sarawak + sar + + + + + Selangor + sel + + + + + Terengganu + ter + + + + + Aguascalientes + AGU + + + + + Baja California + BCN + + + + + Baja California Sur + BCS + + + + + Campeche + CAM + + + + + Coahuila + COA + + + + + Colima + COL + + + + + Chiapas + CHP + + + + + Chihuahua + CHH + + + + + Durango + DUR + + + + + Guanajuato + GUA + + + + + Guerrero + GRO + + + + + Hidalgo + HID + + + + + Jalisco + JAL + + + + + México + MEX + + + + + Michoacán + MIC + + + + + Morelos + MOR + + + + + Nayarit + NAY + + + + + Nuevo León + NLE + + + + + Oaxaca + OAX + + + + + Puebla + PUE + + + + + Querétaro + QUE + + + + + Quintana Roo + ROO + + + + + San Luis Potosí + SLP + + + + + Sinaloa + SIN + + + + + Sonora + SON + + + + + Tabasco + TAB + + + + + Tamaulipas + TAM + + + + + Tlaxcala + TLA + + + + + Veracruz + VER + + + + + Yucatán + YUC + + + + + Zacatecas + ZAC + + + + + + + Chin + ch + + + + + Kachin + kc + + + + + Kayah + kh + + + + + Kayin + ky + + + + + Mon + mon + + + + + Rakhine + rk + + + + + Shan + sh + + + + + + Saint Kitts + SK + + + + + Nevis + NE + + + + + + Andhra Pradesh + AP + + + + + Arunachal Pradesh + AR + + + + + Assam + AS + + + + + Bihar + BR + + + + + Chhattasgarh + CT + + + + + Goa + GA + + + + + Gujarat + GJ + + + + + Haryana + HR + + + + + Himachal Pradesh + HP + + + + + Jammu and Kashmir + JK + + + + + Jharkhand + JH + + + + + Karnataka + KA + + + + + Kerala + KL + + + + + Madhya Pradesh + MP + + + + + Maharashtra + MH + + + + + Manipur + MN + + + + + Meghalaya + ML + + + + + Mizoram + MZ + + + + + Nagaland + NL + + + + + Orissa + OR + + + + + Punjab + PB + + + + + Rajasthan + RJ + + + + + Sikkim + SK + + + + + Tamilnadu + TN + + + + + Tripura + TR + + + + + Uttaranchal + UL + + + + + Uttar Pradesh + UP + + + + + West Bengal + WB + + + + + + + Chuuk + TRK + + + + + Kosrae + KSA + + + + + Pohnpei + PNI + + + + + Yap + YAP + + + + + + Āfar + AF + + + + + Āmara + AM + + + + + Bīnshangul Gumuz + BE + + + + + Gambēla Hizboch + GA + + + + + Hārerī Hizb + HA + + + + + Oromīya + OR + + + + + Sumalē + SO + + + + + Tigray + TI + + + + + YeDebub Bihēroch Bihēreseboch na Hizboch + SN + + + + + + Baden-Württemberg + BW + + + + + Bayern + BY + + + + + Bremen + HB + + + + + Hamburg + HH + + + + + Hessen + HE + + + + + Niedersachsen + NI + + + + + Nordrhein-Westfalen + NW + + + + + Rheinland-Pfalz + RP + + + + + Saarland + SL + + + + + Schleswig-Holstein + SH + + + + + Berlin + BE + + + + + Brandenburg + BB + + + + + Mecklenburg-Vorpommern + MV + + + + + Sachsen + SN + + + + + Sachsen-Anhalt + ST + + + + + Thüringen + TH + + + + + + Acre + AC + + + + + Alagoas + AL + + + + + Amazonas + AM + + + + + Amapá + AP + + + + + Bahia + BA + + + + + Ceará + CE + + + + + Espírito Santo + ES + + + + + Fernando de Noronha + FN + + + + + Goiás + GO + + + + + Maranhão + MA + + + + + Minas Gerais + MG + + + + + Mato Grosso do Sul + MS + + + + + Mato Grosso + MT + + + + + Pará + PA + + + + + Paraíba + PB + + + + + Pernambuco + PE + + + + + Piauí + PI + + + + + Paraná + PR + + + + + Rio de Janeiro + RJ + + + + + Rio Grande do Norte + RN + + + + + Rondonia + RO + + + + + Roraima + RR + + + + + Rio Grande do Sul + RS + + + + + Santa Catarina + SC + + + + + Sergipe + SE + + + + + Sao Paulo + SP + + + + + Tocantins + TO + + + + Burgenland + bl + + + + + Karnten + ka + + + + + Niederosterreich + ni + + + + + Oberosterreich + ob + + + + + Salzburg + sa + + + + + Steiermark + st + + + + + Tirol + ti + + + + + Vorarlberg + vb + + + + + Wien + wi + + + + + New South Wales + NSW + + + + + Queensland + QLD + + + + + South Australia + SA + + + + + Tasmania + TAS + + + + + Victoria + VIC + + + + + Western Australia + WA + + + + + Tiny sprl From 75a195153fc2db09fc7e60249f939a565fd6f72e Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Fri, 5 Dec 2008 14:43:32 +0100 Subject: [PATCH 015/137] [FIX] allow selections in (old style) wizards to be translated (idea from Activity Solutions) bzr revid: christophe@tinyerp.com-20081205134332-hkwjiy5fulyh5o2i --- bin/tools/translate.py | 8 ++++++-- bin/wizard/__init__.py | 5 +++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/bin/tools/translate.py b/bin/tools/translate.py index 8a20541210f..3c13c351023 100644 --- a/bin/tools/translate.py +++ b/bin/tools/translate.py @@ -360,10 +360,14 @@ def trans_generate(lang, modules, dbname=None): # export fields for field_name, field_def in result['fields'].iteritems(): + res_name = name + ',' + field_name if 'string' in field_def: source = field_def['string'] - res_name = name + ',' + field_name - push_translation(module, 'wizard_field', res_name, 0, source) + push_translation(module, 'wizard_field', res_name, 0, source.encode('utf8')) + + if 'selection' in field_def: + for key, val in field_def['selection']: + push_translation(module, 'selection', res_name, 0, val.encode('utf8')) # export arch arch = result['arch'] diff --git a/bin/wizard/__init__.py b/bin/wizard/__init__.py index 44f895f352b..72be97b3958 100644 --- a/bin/wizard/__init__.py +++ b/bin/wizard/__init__.py @@ -116,6 +116,11 @@ class interface(netsvc.Service): trans = translate(cr, self.wiz_name+','+state+','+field, 'wizard_field', lang) if trans: fields[field]['string'] = trans + + if 'selection' in fields[field]: + trans = lambda x: translate(cr, self.wiz_name+','+state+','+field, 'selection', lang, x) or x + for idx, (key, val) in enumerate(fields[field]['selection']): + fields[field]['selection'][idx] = (key, trans(val)) # translate arch if not isinstance(arch, UpdateableStr): From dfbcd29e8ee691013339a23e602ea035541b596f Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Sun, 7 Dec 2008 03:16:54 +0100 Subject: [PATCH 016/137] Speed Improvement ORM Better Store={...} bzr revid: fp@tinyerp.com-20081207021654-wfgrjy7tj3ukgopv --- bin/osv/fields.py | 3 + bin/osv/orm.py | 151 ++++++++++++++++++---------------------------- 2 files changed, 63 insertions(+), 91 deletions(-) diff --git a/bin/osv/fields.py b/bin/osv/fields.py index 51112a10048..e8c0c3b1ede 100644 --- a/bin/osv/fields.py +++ b/bin/osv/fields.py @@ -597,6 +597,9 @@ class function(_column): self._type = type self._fnct_search = fnct_search self.store = store + if store: + self._classic_read = True + self._classic_write = True if type == 'float': self._symbol_c = '%f' self._symbol_f = lambda x: __builtin__.float(x or 0.0) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index 0803a7ace38..a4417552669 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -1627,29 +1627,33 @@ class orm(orm_template): def __init__(self, cr): super(orm, self).__init__(cr) self._columns = self._columns.copy() - f = filter(lambda a: isinstance(self._columns[a], fields.function) and self._columns[a].store, self._columns) - if f: - list_store = [] - tuple_store = () - tuple_fn = () - for store_field in f: - if not self._columns[store_field].store == True: - dict_store = self._columns[store_field].store - key = dict_store.keys() - list_data = [] - for i in key: - tuple_store = self._name, store_field, self._columns[store_field]._fnct.__name__, tuple(dict_store[i][0]), dict_store[i][1], i - list_data.append(tuple_store) - #tuple_store=self._name,store_field,self._columns[store_field]._fnct.__name__,tuple(dict_store[key[0]][0]),dict_store[key[0]][1] - for l in list_data: - list_store = [] - if l[5] in self.pool._store_function.keys(): - self.pool._store_function[l[5]].append(l) - temp_list = list(set(self.pool._store_function[l[5]])) - self.pool._store_function[l[5]] = temp_list - else: - list_store.append(l) - self.pool._store_function[l[5]] = list_store + for store_field in self._columns: + f = self._columns[store_field] + if not isinstance(f, fields.function): + continue + if not f.store: + continue + if self._columns[store_field].store is True: + sm = {self._name:(lambda self,cr, uid, ids, c={}: ids, None)} + else: + sm = self._columns[store_field].store + for object, aa in sm.items(): + if len(aa)==2: + (fnct,fields2)=aa + order = 1 + elif len(aa)==3: + (fnct,fields2,order)=aa + else: + raise except_orm(_('Error'), + _('Invalid function definition %s in object %s !' % (store_field, self._name))) + self.pool._store_function.setdefault(object, []) + ok = True + for x,y,z,e,f in self.pool._store_function[object]: + if (x==self._name) and (y==store_field) and (e==fields2): + ok = False + if ok: + self.pool._store_function[object].append( (self._name, store_field, fnct, fields2, order)) + self.pool._store_function[object].sort(lambda x,y: cmp(x[4],y[4])) for (key, _, msg) in self._sql_constraints: self.pool._sql_error[self._table+'_'+key] = msg @@ -1978,15 +1982,8 @@ class orm(orm_template): ids = [ids] fn_list = [] - if self._name in self.pool._store_function.keys(): - list_store = self.pool._store_function[self._name] - fn_data = () - id_change = [] - for tuple_fn in list_store: - for id in ids: - id_change.append(self._store_get_ids(cr, uid, id, tuple_fn, context)[0]) - fn_data = id_change, tuple_fn - fn_list.append(fn_data) + for fnct in self.pool._store_function.get(self._name, []): + fn_list.append( (fnct[0], fnct[1], fnct[2](self,cr, uid, ids, context)) ) delta = context.get('read_delta', False) if delta and self._log_access: @@ -2033,10 +2030,9 @@ class orm(orm_template): else: cr.execute('delete from "'+self._table+'" ' \ 'where id in ('+str_d+')', sub_ids) - if fn_list: - for ids, tuple_fn in fn_list: - self._store_set_values(cr, uid, ids, tuple_fn, id_change, context) + for object,field,ids in fn_list: + self.pool.get(object)._store_set_values(cr, uid, ids, field, context) return True # @@ -2247,22 +2243,15 @@ class orm(orm_template): wf_service = netsvc.LocalService("workflow") for id in ids: wf_service.trg_write(user, self._name, id, cr) - self._update_function_stored(cr, user, ids, context=context) - - if self._name in self.pool._store_function.keys(): - list_store = self.pool._store_function[self._name] - for tuple_fn in list_store: - flag = False - if not tuple_fn[3]: - flag = True - for field in tuple_fn[3]: - if field in vals.keys(): - flag = True - break - if flag: - id_change = self._store_get_ids(cr, user, ids[0], tuple_fn, context) - self._store_set_values(cr, user, ids[0], tuple_fn, id_change, context) + for fnct in self.pool._store_function.get(self._name, []): + ok = False + for key in vals.keys(): + if (not fnct[3]) or (key in fnct[3]): + ok = True + if ok: + ids2 = fnct[2](self,cr, user, ids, context) + self.pool.get(fnct[0])._store_set_values(cr, user, ids2, fnct[1], context) return True # @@ -2369,54 +2358,34 @@ class orm(orm_template): wf_service = netsvc.LocalService("workflow") wf_service.trg_create(user, self._name, id_new, cr) - self._update_function_stored(cr, user, [id_new], context=context) - if self._name in self.pool._store_function.keys(): - list_store = self.pool._store_function[self._name] - for tuple_fn in list_store: - id_change = self._store_get_ids(cr, user, id_new, tuple_fn, context) - self._store_set_values(cr, user, id_new, tuple_fn, id_change, context) + for fnct in self.pool._store_function.get(self._name, []): + ids2 = fnct[2](self,cr, user, [id_new], context) + self.pool.get(fnct[0])._store_set_values(cr, user, ids2, fnct[1], context) return id_new def _store_get_ids(self, cr, uid, ids, tuple_fn, context): - parent_id = getattr(self.pool.get(tuple_fn[0]), tuple_fn[4].func_name)(cr, uid, [ids]) + parent_id = getattr(self.pool.get(tuple_fn[0]), tuple_fn[4].func_name)(cr, uid, ids, context) return parent_id - def _store_set_values(self, cr, uid, ids, tuple_fn, parent_id, context): - name = tuple_fn[1] - table = tuple_fn[0] + def _store_set_values(self, cr, uid, ids, field, context): args = {} - vals_tot = getattr(self.pool.get(table), tuple_fn[2])(cr, uid, parent_id, name, args, context) - write_dict = {} - for id in vals_tot.keys(): - write_dict[name] = vals_tot[id] - self.pool.get(table).write(cr, uid, [id], write_dict) - return True - - def _update_function_stored(self, cr, user, ids, context=None): - if not context: - context = {} - f = filter(lambda a: isinstance(self._columns[a], fields.function) \ - and self._columns[a].store, self._columns) - if f: - result = self.read(cr, user, ids, fields=f, context=context) - for res in result: - upd0 = [] - upd1 = [] - for field in res: - if field not in f: - continue - value = res[field] - if self._columns[field]._type in ('many2one', 'one2one'): - try: - value = res[field][0] - except: - value = res[field] - upd0.append('"'+field+'"='+self._columns[field]._symbol_set[0]) - upd1.append(self._columns[field]._symbol_set[1](value)) - upd1.append(res['id']) - cr.execute('update "' + self._table + '" set ' + \ - string.join(upd0, ',') + ' where id = %d', upd1) + result = self._columns[field].get(cr, self, ids, field, uid, context=context) + for id,value in result.items(): + upd0 = [] + upd1 = [] + if self._columns[field]._multi: + value = value[field] + if self._columns[field]._type in ('many2one', 'one2one'): + try: + value = value[0] + except: + pass + upd0.append('"'+field+'"='+self._columns[field]._symbol_set[0]) + upd1.append(self._columns[field]._symbol_set[1](value)) + upd1.append(id) + cr.execute('update "' + self._table + '" set ' + \ + string.join(upd0, ',') + ' where id = %d', upd1) return True # From 6e55b73d266c78195e143ede26f05890fd957f34 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Sun, 7 Dec 2008 13:45:02 +0100 Subject: [PATCH 017/137] bugfixes bzr revid: fp@tinyerp.com-20081207124502-guf3osjkrd7tunwj --- bin/osv/orm.py | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index a4417552669..72e9276a0c9 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -1433,6 +1433,7 @@ class orm(orm_template): cr.execute("ALTER TABLE \"%s\" ALTER COLUMN \"%s\" DROP NOT NULL" % (self._table, column['attname'])) # iterate on the "object columns" + todo_update_store = [] for k in self._columns: if k in ('id', 'write_uid', 'write_date', 'create_uid', 'create_date'): continue @@ -1474,20 +1475,9 @@ class orm(orm_template): cr.execute("UPDATE \"%s\" SET \"%s\"=NULL" % (self._table, k)) else: cr.execute("UPDATE \"%s\" SET \"%s\"='%s'" % (self._table, k, default)) + if isinstance(f, fields.function): - cr.execute('select id from '+self._table) - ids_lst = map(lambda x: x[0], cr.fetchall()) - while ids_lst: - iids = ids_lst[:40] - ids_lst = ids_lst[40:] - res = f.get(cr, self, iids, k, 1, {}) - for key,val in res.items(): - if f._multi: - val = val[k] - if (val<>False) or (type(val)<>bool): - cr.execute("UPDATE \"%s\" SET \"%s\"='%s' where id=%d"% (self._table, k, val, key)) - #else: - # cr.execute("UPDATE \"%s\" SET \"%s\"=NULL where id=%d"% (self._table, k, key)) + todo_update_store.append((f,k)) # and add constraints if needed if isinstance(f, fields.many2one): @@ -1601,6 +1591,21 @@ class orm(orm_template): cr.commit() else: print "ERROR" + for f,k in todo_update_store: + cr.execute('select id from '+self._table) + ids_lst = map(lambda x: x[0], cr.fetchall()) + while ids_lst: + iids = ids_lst[:40] + ids_lst = ids_lst[40:] + res = f.get(cr, self, iids, k, 1, {}) + for key,val in res.items(): + if f._multi: + val = val[k] + if (val<>False) or (type(val)<>bool): + cr.execute("UPDATE \"%s\" SET \"%s\"='%s' where id=%d"% (self._table, k, val, key)) + #else: + # cr.execute("UPDATE \"%s\" SET \"%s\"=NULL where id=%d"% (self._table, k, key)) + else: cr.execute("SELECT relname FROM pg_class WHERE relkind in ('r','v') AND relname='%s'" % self._table) create = not bool(cr.fetchone()) From f8f691f6edf9caaf85a7799e5a0dd79cc2f12713 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Mon, 8 Dec 2008 08:47:38 +0100 Subject: [PATCH 018/137] bugfixes_store bzr revid: fp@tinyerp.com-20081208074738-qspr61l0lnobpb1h --- bin/osv/orm.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index 72e9276a0c9..3b3b9c3b1d2 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -1988,7 +1988,9 @@ class orm(orm_template): fn_list = [] for fnct in self.pool._store_function.get(self._name, []): - fn_list.append( (fnct[0], fnct[1], fnct[2](self,cr, uid, ids, context)) ) + ids2 = filter(None, fnct[2](self,cr, uid, ids, context)) + if ids2: + fn_list.append( (fnct[0], fnct[1], ids2) ) delta = context.get('read_delta', False) if delta and self._log_access: @@ -2037,7 +2039,9 @@ class orm(orm_template): 'where id in ('+str_d+')', sub_ids) for object,field,ids in fn_list: - self.pool.get(object)._store_set_values(cr, uid, ids, field, context) + ids = self.pool.get(object).search(cr, uid, [('id','in', ids)], context=context) + if ids: + self.pool.get(object)._store_set_values(cr, uid, ids, field, context) return True # @@ -2256,7 +2260,9 @@ class orm(orm_template): ok = True if ok: ids2 = fnct[2](self,cr, user, ids, context) - self.pool.get(fnct[0])._store_set_values(cr, user, ids2, fnct[1], context) + ids2 = filter(None, ids2) + if ids2: + self.pool.get(fnct[0])._store_set_values(cr, user, ids2, fnct[1], context) return True # @@ -2366,13 +2372,11 @@ class orm(orm_template): for fnct in self.pool._store_function.get(self._name, []): ids2 = fnct[2](self,cr, user, [id_new], context) - self.pool.get(fnct[0])._store_set_values(cr, user, ids2, fnct[1], context) + ids2 = filter(None, ids2) + if ids2: + self.pool.get(fnct[0])._store_set_values(cr, user, ids2, fnct[1], context) return id_new - def _store_get_ids(self, cr, uid, ids, tuple_fn, context): - parent_id = getattr(self.pool.get(tuple_fn[0]), tuple_fn[4].func_name)(cr, uid, ids, context) - return parent_id - def _store_set_values(self, cr, uid, ids, field, context): args = {} result = self._columns[field].get(cr, self, ids, field, uid, context=context) From 04b6432165f0f4153bd203749e5c8a1955aec574 Mon Sep 17 00:00:00 2001 From: Olivier Laurent Date: Mon, 8 Dec 2008 08:48:25 +0100 Subject: [PATCH 019/137] typo in translation bzr revid: olt@tinyerp.com-20081208074825-xb33eq6shm74vk6q --- bin/addons/base/i18n/fr_FR.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/addons/base/i18n/fr_FR.po b/bin/addons/base/i18n/fr_FR.po index 9c901466073..16e0647c81c 100644 --- a/bin/addons/base/i18n/fr_FR.po +++ b/bin/addons/base/i18n/fr_FR.po @@ -137,7 +137,7 @@ msgstr "Vous ne pouvez pas créer ce type de document! (%s)" #. module: base #: wizard_field:module.lang.import,init,code:0 msgid "Code (eg:en__US)" -msgstr "Code (ex:fr_FR)" +msgstr "Code (ex:fr__FR)" #. module: base #: field:res.roles,parent_id:0 From b08432d3568cc19b2f9ec33d7beb33312728ab5d Mon Sep 17 00:00:00 2001 From: Olivier Laurent Date: Mon, 8 Dec 2008 08:51:31 +0100 Subject: [PATCH 020/137] level=50 is too low for some projects bzr revid: olt@tinyerp.com-20081208075131-qnxld3nfeap0sg7j --- bin/addons/base/module/module.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/addons/base/module/module.py b/bin/addons/base/module/module.py index 32519086e77..a6767cd6c52 100644 --- a/bin/addons/base/module/module.py +++ b/bin/addons/base/module/module.py @@ -37,6 +37,7 @@ import netsvc from tools.parse_version import parse_version + class module_repository(osv.osv): _name = "ir.module.repository" _description = "Module Repository" @@ -208,7 +209,7 @@ class module(osv.osv): _('You try to remove a module that is installed or will be installed')) return super(module, self).unlink(cr, uid, ids, context=context) - def state_update(self, cr, uid, ids, newstate, states_to_update, context={}, level=50): + def state_update(self, cr, uid, ids, newstate, states_to_update, context={}, level=100): if level<1: raise orm.except_orm(_('Error'), _('Recursion error in modules dependencies !')) demo = False From 8cbf75d09031c06c28342384fc06e583aea9dde6 Mon Sep 17 00:00:00 2001 From: Olivier Laurent Date: Mon, 8 Dec 2008 08:55:58 +0100 Subject: [PATCH 021/137] Sometimes a database could not be created because of the connection to 'template1' This fix should correct the problem (tested with 1 second but reduced to 0.2 second) bzr revid: olt@tinyerp.com-20081208075558-1kfm6rf25nrinwfv --- bin/service/web_services.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/service/web_services.py b/bin/service/web_services.py index e99a7aa8ec3..69d8015f241 100644 --- a/bin/service/web_services.py +++ b/bin/service/web_services.py @@ -67,6 +67,7 @@ class db(netsvc.Service): db = sql_db.db_connect('template1', serialize=1) db.truedb.autocommit() cr = db.cursor() + time.sleep(0.2) cr.execute('CREATE DATABASE ' + db_name + ' ENCODING \'unicode\'') cr.close() class DBInitialize(object): From 299627a14408ce297277d2adfce2e4bdffa1fcbc Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Mon, 8 Dec 2008 15:03:42 +0100 Subject: [PATCH 022/137] [IMP] use psycopg2 instead of psycopg1 bzr revid: christophe@tinyerp.com-20081208140342-qstsqxm0xr5rppzz --- bin/netsvc.py | 1 + bin/openerp-server.py | 27 +------- bin/osv/fields.py | 4 +- bin/osv/osv.py | 4 +- bin/pooler.py | 54 ++++----------- bin/sql_db.py | 149 ++++++++++++++++++++++++------------------ bin/tools/misc.py | 3 - 7 files changed, 101 insertions(+), 141 deletions(-) diff --git a/bin/netsvc.py b/bin/netsvc.py index daa29788e07..31832004067 100644 --- a/bin/netsvc.py +++ b/bin/netsvc.py @@ -206,6 +206,7 @@ class Logger(object): log = logging.getLogger(name) getattr(log, level)(msg) +init_logger() class Agent(object): _timers = [] diff --git a/bin/openerp-server.py b/bin/openerp-server.py index 11a5b32705c..f353dc236b9 100755 --- a/bin/openerp-server.py +++ b/bin/openerp-server.py @@ -53,9 +53,6 @@ __version__ = release.version # get logger #---------------------------------------------------------- import netsvc - -netsvc.init_logger() - logger = netsvc.Logger() #----------------------------------------------------------------------- @@ -81,35 +78,13 @@ dispatcher.monitor(signal.SIGINT) #--------------------------------------------------------------- # connect to the database and initialize it with base if needed #--------------------------------------------------------------- -import psycopg import pooler -db_name = tools.config["db_name"] - -# test whether it is needed to initialize the db (the db is empty) -#try: -# cr = pooler.get_db_only(db_name).cursor() -#except psycopg.OperationalError: -# logger.notifyChannel("init", netsvc.LOG_INFO, "could not connect to database '%s'!" % db_name,) -# cr = None -#if cr: -# cr.execute("SELECT relname FROM pg_class WHERE relkind='r' AND relname='ir_ui_menu'") -# if len(cr.fetchall())==0: -##if False: -# logger.notifyChannel("init", netsvc.LOG_INFO, "init db") -# tools.init_db(cr) -# # in that case, force --init=all -# tools.config["init"]["all"] = 1 -# tools.config['update']['all'] = 1 -# if not tools.config['without_demo']: -# tools.config["demo"]['all'] = 1 -# cr.close() - #---------------------------------------------------------- # launch modules install/upgrade/removes if needed #---------------------------------------------------------- if tools.config['upgrade']: - print 'Upgrading new modules...' + logger.notifyChannel('init', netsvc.LOG_INFO, 'Upgrading new modules...') import tools.upgrade (toinit, toupdate) = tools.upgrade.upgrade() for m in toinit: diff --git a/bin/osv/fields.py b/bin/osv/fields.py index e8c0c3b1ede..097697cb3e1 100644 --- a/bin/osv/fields.py +++ b/bin/osv/fields.py @@ -35,7 +35,7 @@ import string import netsvc -import psycopg +from psycopg2 import Binary import warnings import tools @@ -195,7 +195,7 @@ class time(_column): class binary(_column): _type = 'binary' _symbol_c = '%s' - _symbol_f = lambda symb: symb and psycopg.Binary(symb) or None + _symbol_f = lambda symb: symb and Binary(symb) or None _symbol_set = (_symbol_c, _symbol_f) _classic_read = False diff --git a/bin/osv/osv.py b/bin/osv/osv.py index 2efc3a41a3c..9e6d4171c37 100644 --- a/bin/osv/osv.py +++ b/bin/osv/osv.py @@ -30,7 +30,7 @@ import pooler import copy import sys -import psycopg +from psycopg2 import IntegrityError from netsvc import Logger, LOG_ERROR from tools.misc import UpdateableDict @@ -87,7 +87,7 @@ class osv_pool(netsvc.Service): self.abortResponse(1, inst.name, 'warning', inst.value) except except_osv, inst: self.abortResponse(1, inst.name, inst.exc_type, inst.value) - except psycopg.IntegrityError, inst: + except IntegrityError, inst: for key in self._sql_error.keys(): if key in inst[0]: self.abortResponse(1, 'Constraint Error', 'warning', self._sql_error[key]) diff --git a/bin/pooler.py b/bin/pooler.py index c838641f01d..132e99b5089 100644 --- a/bin/pooler.py +++ b/bin/pooler.py @@ -20,30 +20,19 @@ # ############################################################################## -import sql_db -import osv.osv -import tools -import addons -import netsvc - -db_dic = {} pool_dic = {} - def get_db_and_pool(db_name, force_demo=False, status=None, update_module=False): if not status: status={} - if db_name in db_dic: - db = db_dic[db_name] - else: - logger = netsvc.Logger() - logger.notifyChannel('pooler', netsvc.LOG_INFO, 'Connecting to %s' % (db_name.lower())) - db = sql_db.db_connect(db_name) - db_dic[db_name] = db + + db = get_db_only(db_name) if db_name in pool_dic: pool = pool_dic[db_name] else: + import addons + import osv.osv pool = osv.osv.osv_pool() pool_dic[db_name] = pool addons.load_modules(db, force_demo, status, update_module) @@ -60,49 +49,28 @@ def get_db_and_pool(db_name, force_demo=False, status=None, update_module=False) def restart_pool(db_name, force_demo=False, update_module=False): -# del db_dic[db_name] del pool_dic[db_name] return get_db_and_pool(db_name, force_demo, update_module=update_module) -def close_db(db_name): - if db_name in db_dic: - db_dic[db_name].truedb.close() - del db_dic[db_name] - if db_name in pool_dic: - del pool_dic[db_name] - - def get_db_only(db_name): - if db_name in db_dic: - db = db_dic[db_name] - else: - db = sql_db.db_connect(db_name) - db_dic[db_name] = db + # ATTENTION: + # do not put this import outside this function + # sql_db must not be loaded before the logger is initialized. + # sql_db import psycopg2.tool which create a default logger if there is not. + # this resulting of having the logs outputed twice... + import sql_db + db = sql_db.db_connect(db_name) return db def get_db(db_name): -# print "get_db", db_name return get_db_and_pool(db_name)[0] def get_pool(db_name, force_demo=False, status=None, update_module=False): -# print "get_pool", db_name pool = get_db_and_pool(db_name, force_demo, status, update_module)[1] -# addons.load_modules(db_name, False) -# if not pool.obj_list(): -# pool.instanciate() -# print "pool", pool return pool -# return get_db_and_pool(db_name)[1] - - -def init(): - global db -# db = get_db_only(tools.config['db_name']) - sql_db.init() - # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/bin/sql_db.py b/bin/sql_db.py index c43fed6d2e7..e52b94d89fa 100644 --- a/bin/sql_db.py +++ b/bin/sql_db.py @@ -20,38 +20,40 @@ # ############################################################################## -import psycopg +import netsvc +from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT, ISOLATION_LEVEL_SERIALIZABLE +from psycopg2.pool import ThreadedConnectionPool +from psycopg2.psycopg1 import cursor as psycopg1cursor + +import psycopg2.extensions +psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) + import tools -import sys,os - -#try: -# import decimal -#except ImportError: -# from tools import decimal - - import re from mx import DateTime as mdt re_from = re.compile('.* from "?([a-zA-Z_0-9]+)"? .*$'); re_into = re.compile('.* into "?([a-zA-Z_0-9]+)"? .*$'); -class fake_cursor: +def log(msg, lvl=netsvc.LOG_DEBUG): + logger = netsvc.Logger() + logger.notifyChannel('sql', lvl, msg) + +class Cursor(object): IN_MAX = 1000 - nbr = 0 - _tables = {} sql_from_log = {} sql_into_log = {} sql_log = False count = 0 - def __init__(self, db, con, dbname): - self.db = db - self.obj = db.cursor() - self.con = con - self.dbname = dbname + def __init__(self, pool): + self._pool = pool + self._cnx = pool.getconn() + self.autocommit(False) + self._obj = self._cnx.cursor(cursor_factory=psycopg1cursor) + self.dbname = pool.dbname - def execute(self, sql, params=None): + def execute(self, query, params=None): if not params: params=() def base_string(s): @@ -59,24 +61,28 @@ class fake_cursor: return s.encode('utf-8') return s p=map(base_string, params) - if isinstance(sql, unicode): - sql = sql.encode('utf-8') + query = base_string(query) + + if '%d' in query or '%f' in query: + log(queyr, netsvc.LOG_WARNING) + log("SQL queries mustn't containt %d or %f anymore. Use only %s", netsvc.LOG_WARNING) + query = query.replace('%d', '%s').replace('%f', '%s') + if self.sql_log: now = mdt.now() - print "SQL LOG query:", sql - print "SQL LOG params:", repr(p) - if p: - res = self.obj.execute(sql, p) - else: - res = self.obj.execute(sql) + log("SQL LOG query: %s" % (query,)) + log("SQL LOG params: %r" % (p,)) + + res = self._obj.execute(query, p) + if self.sql_log: self.count+=1 - res_from = re_from.match(sql.lower()) + res_from = re_from.match(query.lower()) if res_from: self.sql_from_log.setdefault(res_from.group(1), [0, 0]) self.sql_from_log[res_from.group(1)][0] += 1 self.sql_from_log[res_from.group(1)][1] += mdt.now() - now - res_into = re_into.match(sql.lower()) + res_into = re_into.match(query.lower()) if res_into: self.sql_into_log.setdefault(res_into.group(1), [0, 0]) self.sql_into_log[res_into.group(1)][0] += 1 @@ -84,7 +90,7 @@ class fake_cursor: return res def print_log(self, type='from'): - print "SQL LOG %s:" % (type,) + log("SQL LOG %s:" % (type,)) if type == 'from': logs = self.sql_from_log.items() else: @@ -92,63 +98,76 @@ class fake_cursor: logs.sort(lambda x, y: cmp(x[1][1], y[1][1])) sum=0 for r in logs: - print "table:", r[0], ":", str(r[1][1]), "/", r[1][0] + log("table: %s: %s/%s" %(r[0], str(r[1][1]), r[1][0])) sum+= r[1][1] - print "SUM:%s/%d"% (sum, self.count) + log("SUM:%s/%d" % (sum, self.count)) def close(self): if self.sql_log: self.print_log('from') self.print_log('into') - self.obj.close() + self._obj.close() # This force the cursor to be freed, and thus, available again. It is # important because otherwise we can overload the server very easily # because of a cursor shortage (because cursors are not garbage # collected as fast as they should). The problem is probably due in # part because browse records keep a reference to the cursor. - del self.obj + del self._obj + self._pool.putconn(self._cnx) + + def autocommit(self, on): + self._cnx.set_isolation_level([ISOLATION_LEVEL_SERIALIZABLE, ISOLATION_LEVEL_AUTOCOMMIT][bool(on)]) + + def commit(self): + return self._cnx.commit() + + def rollback(self): + return self._cnx.rollback() def __getattr__(self, name): - return getattr(self.obj, name) + return getattr(self._obj, name) -class fakedb: - def __init__(self, truedb, dbname): - self.truedb = truedb +class ConnectionPool(object): + def __init__(self, pool, dbname): self.dbname = dbname + self._pool = pool def cursor(self): - return fake_cursor(self.truedb, {}, self.dbname) + return Cursor(self) -def decimalize(symb): - if symb is None: return None - if isinstance(symb, float): - return decimal.Decimal('%f' % symb) - return decimal.Decimal(symb) + def __getattr__(self, name): + return getattr(self._pool, name) + +class PoolManager(object): + _pools = {} + _dsn = None + maxconn = int(tools.config['db_maxconn']) or 64 + + def dsn(db_name): + if PoolManager._dsn is None: + PoolManager._dsn = '' + for p in ('host', 'port', 'user', 'password'): + cfg = tools.config['db_' + p] + if cfg: + PoolManager._dsn += '%s=%s ' % (p, cfg) + return '%s dbname=%s' % (PoolManager._dsn, db_name) + dsn = staticmethod(dsn) + + def get(db_name): + if db_name not in PoolManager._pools: + logger = netsvc.Logger() + try: + logger.notifyChannel('dbpool', netsvc.LOG_INFO, 'Connecting to %s' % (db_name.lower())) + PoolManager._pools[db_name] = ConnectionPool(ThreadedConnectionPool(0, PoolManager.maxconn, PoolManager.dsn(db_name)), db_name) + except Exception, e: + logger.notifyChannel('dbpool', netsvc.LOG_CRITICAL, 'Unable to connect to %s: %r' % (db_name, e)) + raise + return PoolManager._pools[db_name] + get = staticmethod(get) def db_connect(db_name, serialize=0): - host = tools.config['db_host'] and "host=%s" % tools.config['db_host'] or '' - port = tools.config['db_port'] and "port=%s" % tools.config['db_port'] or '' - name = "dbname=%s" % db_name - user = tools.config['db_user'] and "user=%s" % tools.config['db_user'] or '' - password = tools.config['db_password'] and "password=%s" % tools.config['db_password'] or '' - maxconn = int(tools.config['db_maxconn']) or 64 - tdb = psycopg.connect('%s %s %s %s %s' % (host, port, name, user, password), - serialize=serialize, maxconn=maxconn) - fdb = fakedb(tdb, db_name) - return fdb - -def init(): - #define DATEOID 1082, define TIMESTAMPOID 1114 see pgtypes.h - psycopg.register_type(psycopg.new_type((1082,), "date", lambda x:x)) - psycopg.register_type(psycopg.new_type((1083,), "time", lambda x:x)) - psycopg.register_type(psycopg.new_type((1114,), "datetime", lambda x:x)) - #psycopg.register_type(psycopg.new_type((700, 701, 1700), 'decimal', decimalize)) - -psycopg.register_type(psycopg.new_type((1082,), "date", lambda x:x)) -psycopg.register_type(psycopg.new_type((1083,), "time", lambda x:x)) -psycopg.register_type(psycopg.new_type((1114,), "datetime", lambda x:x)) - + return PoolManager.get(db_name) # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/bin/tools/misc.py b/bin/tools/misc.py index 6c6efc5438b..212501a8703 100644 --- a/bin/tools/misc.py +++ b/bin/tools/misc.py @@ -27,10 +27,7 @@ Miscelleanous tools used by OpenERP. import os, time, sys import inspect -import psycopg -#import netsvc from config import config -#import tools import zipfile import release From 3b8e9cae1ea9949d0053bd02a0e90b5af6340176 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Mon, 8 Dec 2008 15:04:45 +0100 Subject: [PATCH 023/137] [FIX] change setup.py to load psycopg2 bzr revid: christophe@tinyerp.com-20081208140445-fcey0uzjpwtzkfzx --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 17c2b9447c6..c0459d0864f 100755 --- a/setup.py +++ b/setup.py @@ -54,7 +54,7 @@ execfile(opj('bin', 'release.py')) py_short_version = '%s.%s' % sys.version_info[:2] required_modules = [ - ('psycopg', 'PostgreSQL module'), + ('psycopg2', 'PostgreSQL module'), ('xml', 'XML Tools for python'), ('libxml2', 'libxml2 python bindings'), ('libxslt', 'libxslt python bindings'), From d02ffad04f6e5c133872f98e789730268a4c2895 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Tue, 9 Dec 2008 09:03:55 +0100 Subject: [PATCH 024/137] improved_related bzr revid: fp@tinyerp.com-20081209080355-b3n01hbm3asej3mp --- bin/osv/expression.py | 3 +- bin/osv/fields.py | 94 ++++++++++++++++--------------------------- 2 files changed, 36 insertions(+), 61 deletions(-) diff --git a/bin/osv/expression.py b/bin/osv/expression.py index 93d3a0bc07b..37a2ad65ac1 100644 --- a/bin/osv/expression.py +++ b/bin/osv/expression.py @@ -22,6 +22,7 @@ ############################################################################## from tools import flatten, reverse_enumerate +import fields class expression(object): @@ -190,7 +191,7 @@ class expression(object): dom = _rec_get(ids2, working_table, left) self.__exp = self.__exp[:i] + dom + self.__exp[i+1:] else: - if isinstance(right, basestring): + if isinstance(right, basestring): # and not isinstance(field, fields.related): res_ids = field_obj.name_search(cr, uid, right, [], operator, limit=None) right = map(lambda x: x[0], res_ids) self.__exp[i] = (left, 'in', right) diff --git a/bin/osv/fields.py b/bin/osv/fields.py index e8c0c3b1ede..d7de7d013fd 100644 --- a/bin/osv/fields.py +++ b/bin/osv/fields.py @@ -639,60 +639,27 @@ class function(_column): class related(function): - def _fnct_search(self, tobj, cr, uid, obj=None, name=None, context=None): - where_flag = 0 - where = " where" - query = "select %s.id from %s" % (obj._table, obj._table) - relation_child = obj._name - relation = obj._name - for i in range(len(self._arg)): - field_detail = self._field_get(cr, uid, obj, relation, self._arg[i]) - relation = field_detail[0] - if field_detail[1] in ('one2many', 'many2many'): - obj_child = obj.pool.get(field_detail[2][self._arg[i]]['relation']) - field_detail_child = obj_child.fields_get(cr, uid,) - - fields_filter = dict(filter(lambda x: x[1].get('relation', False) - and x[1].get('relation') == relation_child - and x[1].get('type')=='many2one', field_detail_child.items())) - query += " inner join %s on %s.id = %s.%s" % (obj_child._table, obj._table, obj_child._table, fields_filter.keys()[0]) - relation_child = relation - elif field_detail[1] in ('many2one'): - obj_child = obj.pool.get(field_detail[2][self._arg[i]]['relation']) - obj_child2 = obj.pool.get(relation_child) - if obj_child._name == obj_child2._name: -# select res_partner.id from res_partner where res_partner.parent_id in(select id from res_partner where res_partner.date >= '2008-10-01'); -# where +=" %s.id = %s.%s in (select id from %s where %s.%s %s %s"%(obj_child._table,obj_child2._table,self._arg[i]) - pass - else: - query += " inner join %s on %s.id = %s.%s" % (obj_child._table, obj_child._table, obj_child2._table, self._arg[i]) - relation_child = field_detail[0] - if i == (len(self._arg)-1): - if obj_child._inherits: - obj_child_inherits = obj.pool.get(obj_child._inherits.keys()[0]) - query += " inner join %s on %s.id = %s.%s" % (obj_child_inherits._table, obj_child_inherits._table, obj_child._table, obj_child._inherits.values()[0]) - obj_child = obj_child_inherits - where += " %s.%s %s '%%%s%%' and" % (obj_child._table, obj_child._rec_name, context[0][1], context[0][2]) + def _fnct_search(self, tobj, cr, uid, obj=None, name=None, domain=None, context={}): + self._field_get2(cr, uid, obj, context) + i = len(self._arg)-1 + sarg = name + while i>0: + if type(sarg) in [type([]), type( (1,) )]: + where = [(self._arg[i], 'in', sarg)] else: - obj_child = obj.pool.get(relation_child) - if field_detail[1] in ('char'): - where += " %s.%s %s '%%%s%%' and" % (obj_child._table, self._arg[i], context[0][1], context[0][2]) - if field_detail[1] in ('date'): - where += " %s.%s %s '%s' and" % (obj_child._table, self._arg[i], context[0][1], context[0][2]) - if field_detail[1] in ['integer', 'long', 'float','integer_big']: - where += " %s.%s %s '%d' and" % (obj_child._table, self._arg[i], context[0][1], context[0][2]) - if len(where)>10: - query += where.rstrip('and') - cr.execute(query) - ids = [] - for id in cr.fetchall(): - ids.append(id[0]) - return [('id', 'in', ids)] + where = [(self._arg[i], '=', sarg)] + if domain: + where = map(lambda x: (self._arg[i],x[1], x[2]), domain) + domain = [] + sarg = obj.pool.get(self._relations[i]['object']).search(cr, uid, where, context=context) + i -= 1 + return [(self._arg[0], 'in', sarg)] -# def _fnct_write(self,obj,cr, uid, ids,values, field_name, args, context=None): -# raise 'Not Implemented Yet' + def _fnct_write(self,obj,cr, uid, ids,values, field_name, args, context=None): + raise 'Not Implemented Yet' def _fnct_read(self, obj, cr, uid, ids, field_name, args, context=None): + self._field_get2(cr, uid, obj, context) if not ids: return {} relation = obj._name res = {} @@ -701,12 +668,12 @@ class related(function): t_data = data relation = obj._name for i in range(len(self.arg)): - field_detail = self._field_get(cr, uid, obj, relation, self.arg[i]) - relation = field_detail[0] + field_detail = self._relations[i] + relation = field_detail['object'] if not t_data[self.arg[i]]: t_data = False break - if field_detail[1] in ('one2many', 'many2many'): + if field_detail['type'] in ('one2many', 'many2many'): t_data = t_data[self.arg[i]][0] else: t_data = t_data[self.arg[i]] @@ -718,16 +685,23 @@ class related(function): def __init__(self, *arg, **args): self.arg = arg + self._relations = [] super(related, self).__init__(self._fnct_read, arg, fnct_inv_arg=arg, method=True, fnct_search=self._fnct_search, **args) - # TODO: call field_get on the object, not in the DB - def _field_get(self, cr, uid, obj, model_name, prop): - fields = obj.pool.get(model_name).fields_get(cr, uid,[prop]) - if fields.get(prop, False): - return(fields[prop].get('relation', False), fields[prop].get('type', False), fields) - else: - raise 'Field %s not exist in %s' % (prop, model_name) + def _field_get2(self, cr, uid, obj, context={}): + if self._relations: + return + obj_name = obj._name + for i in range(len(self._arg)): + f = obj.pool.get(obj_name).fields_get(cr, uid, [self._arg[i]], context=context)[self._arg[i]] + self._relations.append({ + 'object': obj_name, + 'type': f['type'] + }) + if f.get('relation',False): + obj_name = f['relation'] + self._relations[-1]['relation'] = f['relation'] # --------------------------------------------------------- # Serialized fields From b2f82b8bd636a3be14315729c8d2f08f67875553 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Tue, 9 Dec 2008 13:23:45 +0100 Subject: [PATCH 025/137] [FIX] psycopg2 return strings in unicode. bzr revid: christophe@tinyerp.com-20081209122345-mqi0yy55yh0zswnm --- bin/addons/base/ir/ir_values.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/addons/base/ir/ir_values.py b/bin/addons/base/ir/ir_values.py index 2beff6c22fb..bd9a5ba2c69 100644 --- a/bin/addons/base/ir/ir_values.py +++ b/bin/addons/base/ir/ir_values.py @@ -211,7 +211,7 @@ class ir_values(osv.osv): #ir_del(cr, uid, x[0]) return False else: - datas = pickle.loads(x[2]) + datas = pickle.loads(str(x[2])) if meta: meta2 = pickle.loads(x[4]) return (x[0],x[1],datas,meta2) From c2cc3a304996fd1a7208b8e0570eef435682e75f Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Tue, 9 Dec 2008 13:37:22 +0100 Subject: [PATCH 026/137] [FIX] psycopg2: in queries we must now use %s everywhere (no more %d or %f) bzr revid: christophe@tinyerp.com-20081209123722-4kmv4pecjwiw3tm3 --- bin/addons/__init__.py | 4 +- bin/addons/base/ir/ir_cron.py | 2 +- bin/addons/base/ir/ir_model.py | 18 ++++---- bin/addons/base/ir/ir_rule.py | 2 +- bin/addons/base/ir/ir_sequence.py | 4 +- bin/addons/base/ir/ir_ui_menu.py | 2 +- bin/addons/base/ir/ir_ui_view.py | 2 +- bin/addons/base/ir/workflow/print_instance.py | 16 +++---- bin/addons/base/module/module.py | 12 +++--- bin/addons/base/res/partner/partner.py | 2 +- bin/addons/base/res/res_currency.py | 4 +- bin/addons/base/res/res_request.py | 10 ++--- bin/addons/base/res/res_user.py | 2 +- bin/osv/expression.py | 4 +- bin/service/security.py | 2 +- bin/tools/upgrade.py | 6 +-- bin/workflow/instance.py | 22 +++++----- bin/workflow/wkf_logs.py | 2 +- bin/workflow/wkf_service.py | 16 +++---- bin/workflow/workitem.py | 42 +++++++++---------- 20 files changed, 87 insertions(+), 87 deletions(-) diff --git a/bin/addons/__init__.py b/bin/addons/__init__.py index 4eeed2e23c6..f61b5f16ba0 100644 --- a/bin/addons/__init__.py +++ b/bin/addons/__init__.py @@ -487,10 +487,10 @@ def load_module_graph(cr, graph, status=None, **kwargs): else: tools.convert_xml_import(cr, m, fp, idref, noupdate=True, **kwargs) fp.close() - cr.execute('update ir_module_module set demo=%s where id=%d', (True, mid)) + cr.execute('update ir_module_module set demo=%s where id=%s', (True, mid)) package_todo.append(package.name) ver = release.major_version + '.' + package.data.get('version', '1.0') - cr.execute("update ir_module_module set state='installed', latest_version=%s where id=%d", (ver, mid,)) + cr.execute("update ir_module_module set state='installed', latest_version=%s where id=%s", (ver, mid,)) cr.commit() # Update translations for all installed languages diff --git a/bin/addons/base/ir/ir_cron.py b/bin/addons/base/ir/ir_cron.py index 31ad86612ad..f20381fc6e3 100644 --- a/bin/addons/base/ir/ir_cron.py +++ b/bin/addons/base/ir/ir_cron.py @@ -101,7 +101,7 @@ class ir_cron(osv.osv, netsvc.Agent): addsql='' if not numbercall: addsql = ', active=False' - cr.execute("update ir_cron set nextcall=%s, numbercall=%d"+addsql+" where id=%d", (nextcall.strftime('%Y-%m-%d %H:%M:%S'), numbercall, job['id'])) + cr.execute("update ir_cron set nextcall=%s, numbercall=%s"+addsql+" where id=%s", (nextcall.strftime('%Y-%m-%d %H:%M:%S'), numbercall, job['id'])) cr.commit() finally: cr.close() diff --git a/bin/addons/base/ir/ir_model.py b/bin/addons/base/ir/ir_model.py index 91360668243..4d8e2175d9d 100644 --- a/bin/addons/base/ir/ir_model.py +++ b/bin/addons/base/ir/ir_model.py @@ -266,7 +266,7 @@ class ir_model_access(osv.osv): if not grouparr: return False - cr.execute("select 1 from res_groups_users_rel where uid=%d and gid in(select res_id from ir_model_data where module=%s and name=%s)", (uid, grouparr[0], grouparr[1],)) + cr.execute("select 1 from res_groups_users_rel where uid=%s and gid in(select res_id from ir_model_data where module=%s and name=%s)", (uid, grouparr[0], grouparr[1],)) return bool(cr.fetchone()) def check_group(self, cr, uid, model, mode, group_ids): @@ -285,7 +285,7 @@ class ir_model_access(osv.osv): cr.execute("SELECT perm_" + mode + " " " FROM ir_model_access a " " JOIN ir_model m ON (m.id = a.model_id) " - " WHERE m.model = %s AND a.group_id = %d", (model_name, group_id) + " WHERE m.model = %s AND a.group_id = %s", (model_name, group_id) ) r = cr.fetchone() if r is None: @@ -442,10 +442,10 @@ class ir_model_data(osv.osv): cr.execute('select id,res_id from ir_model_data where module=%s and name=%s', (module,xml_id)) results = cr.fetchall() for action_id2,res_id2 in results: - cr.execute('select id from '+self.pool.get(model)._table+' where id=%d', (res_id2,)) + cr.execute('select id from '+self.pool.get(model)._table+' where id=%s', (res_id2,)) result3 = cr.fetchone() if not result3: - cr.execute('delete from ir_model_data where id=%d', (action_id2,)) + cr.execute('delete from ir_model_data where id=%s', (action_id2,)) else: res_id,action_id = res_id2,action_id2 @@ -513,7 +513,7 @@ class ir_model_data(osv.osv): #self.pool.get(model).unlink(cr, uid, ids) for id in ids: self.unlink_mark[(model, id)]=False - cr.execute('delete from ir_model_data where res_id=%d and model=\'%s\'', (id,model)) + cr.execute('delete from ir_model_data where res_id=%s and model=\'%s\'', (id,model)) return True def ir_set(self, cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=None, xml_id=False): @@ -525,7 +525,7 @@ class ir_model_data(osv.osv): model = models[0] if res_id: - where = ' and res_id=%d' % (res_id,) + where = ' and res_id=%s' % (res_id,) else: where = ' and (res_id is null)' @@ -552,10 +552,10 @@ class ir_model_data(osv.osv): if (module,name) not in self.loads: self.unlink_mark[(model,res_id)] = id if model=='workflow.activity': - cr.execute('select res_type,res_id from wkf_instance where id in (select inst_id from wkf_workitem where act_id=%d)', (res_id,)) + cr.execute('select res_type,res_id from wkf_instance where id in (select inst_id from wkf_workitem where act_id=%s)', (res_id,)) wkf_todo.extend(cr.fetchall()) - cr.execute("update wkf_transition set condition='True', role_id=NULL, signal=NULL,act_to=act_from,act_from=%d where act_to=%d", (res_id,res_id)) - cr.execute("delete from wkf_transition where act_to=%d", (res_id,)) + cr.execute("update wkf_transition set condition='True', role_id=NULL, signal=NULL,act_to=act_from,act_from=%s where act_to=%s", (res_id,res_id)) + cr.execute("delete from wkf_transition where act_to=%s", (res_id,)) for model,id in wkf_todo: wf_service = netsvc.LocalService("workflow") diff --git a/bin/addons/base/ir/ir_rule.py b/bin/addons/base/ir/ir_rule.py index ef9e90c6b64..3db6218e442 100644 --- a/bin/addons/base/ir/ir_rule.py +++ b/bin/addons/base/ir/ir_rule.py @@ -148,7 +148,7 @@ class ir_rule(osv.osv): WHERE m.model = %s AND (g.id IN (SELECT rule_group_id FROM group_rule_group_rel g_rel JOIN res_groups_users_rel u_rel ON (g_rel.group_id = u_rel.gid) - WHERE u_rel.uid = %d) OR g.global)""", (model_name, uid)) + WHERE u_rel.uid = %s) OR g.global)""", (model_name, uid)) ids = map(lambda x:x[0], cr.fetchall()) if not ids: return '', [] diff --git a/bin/addons/base/ir/ir_sequence.py b/bin/addons/base/ir/ir_sequence.py index 7c160fe98da..23e4ee90c93 100644 --- a/bin/addons/base/ir/ir_sequence.py +++ b/bin/addons/base/ir/ir_sequence.py @@ -69,11 +69,11 @@ class ir_sequence(osv.osv): 'sec': time.strftime('%S'), } - def get_id(self, cr, uid, sequence_id, test='id=%d'): + def get_id(self, cr, uid, sequence_id, test='id=%s'): cr.execute('select id,number_next,number_increment,prefix,suffix,padding from ir_sequence where '+test+' and active=True FOR UPDATE', (sequence_id,)) res = cr.dictfetchone() if res: - cr.execute('update ir_sequence set number_next=number_next+number_increment where id=%d and active=True', (res['id'],)) + cr.execute('update ir_sequence set number_next=number_next+number_increment where id=%s and active=True', (res['id'],)) if res['number_next']: return self._process(res['prefix']) + '%%0%sd' % res['padding'] % res['number_next'] + self._process(res['suffix']) else: diff --git a/bin/addons/base/ir/ir_ui_menu.py b/bin/addons/base/ir/ir_ui_menu.py index e44c5f6b65c..0a0b0442652 100644 --- a/bin/addons/base/ir/ir_ui_menu.py +++ b/bin/addons/base/ir/ir_ui_menu.py @@ -41,7 +41,7 @@ class many2many_unique(fields.many2many): for act in values: if act[0]==4: cr.execute('SELECT * FROM '+self._rel+' \ - WHERE '+self._id1+'=%d AND '+self._id2+'=%d', (id, act[1])) + WHERE '+self._id1+'=%s AND '+self._id2+'=%s', (id, act[1])) if cr.fetchall(): val.remove(act) return super(many2many_unique, self).set(cr, obj, id, name, val, user=user, diff --git a/bin/addons/base/ir/ir_ui_view.py b/bin/addons/base/ir/ir_ui_view.py index 7e7fc29459f..74badb96846 100644 --- a/bin/addons/base/ir/ir_ui_view.py +++ b/bin/addons/base/ir/ir_ui_view.py @@ -99,7 +99,7 @@ class view(osv.osv): for rs in result: if rs.get('model') == 'board.board': - cr.execute("select id,arch,ref_id from ir_ui_view_custom where user_id=%d and ref_id=%d", (uid, rs['id'])) + cr.execute("select id,arch,ref_id from ir_ui_view_custom where user_id=%s and ref_id=%s", (uid, rs['id'])) oview = cr.dictfetchall() if oview: rs['arch'] = oview[0]['arch'] diff --git a/bin/addons/base/ir/workflow/print_instance.py b/bin/addons/base/ir/workflow/print_instance.py index 48a958c5945..2f225c44209 100644 --- a/bin/addons/base/ir/workflow/print_instance.py +++ b/bin/addons/base/ir/workflow/print_instance.py @@ -28,7 +28,7 @@ import report,pooler,tools def graph_get(cr, graph, wkf_id, nested=False, workitem={}): import pydot - cr.execute('select * from wkf_activity where wkf_id=%d', (wkf_id,)) + cr.execute('select * from wkf_activity where wkf_id=%s', (wkf_id,)) nodes = cr.dictfetchall() activities = {} actfrom = {} @@ -36,7 +36,7 @@ def graph_get(cr, graph, wkf_id, nested=False, workitem={}): for n in nodes: activities[n['id']] = n if n['subflow_id'] and nested: - cr.execute('select * from wkf where id=%d', (n['subflow_id'],)) + cr.execute('select * from wkf where id=%s', (n['subflow_id'],)) wkfinfo = cr.dictfetchone() graph2 = pydot.Cluster('subflow'+str(n['subflow_id']), fontsize='12', label = """\"Subflow: %s\\nOSV: %s\"""" % ( n['name'], wkfinfo['osv']) ) (s1,s2) = graph_get(cr, graph2, n['subflow_id'], nested,workitem) @@ -78,9 +78,9 @@ def graph_get(cr, graph, wkf_id, nested=False, workitem={}): activity_to = actto[t['act_to']][1].get(t['signal'], actto[t['act_to']][0]) graph.add_edge(pydot.Edge( str(activity_from) ,str(activity_to), fontsize='10', **args)) nodes = cr.dictfetchall() - cr.execute('select id from wkf_activity where flow_start=True and wkf_id=%d limit 1', (wkf_id,)) + cr.execute('select id from wkf_activity where flow_start=True and wkf_id=%s limit 1', (wkf_id,)) start = cr.fetchone()[0] - cr.execute("select 'subflow.'||name,id from wkf_activity where flow_stop=True and wkf_id=%d", (wkf_id,)) + cr.execute("select 'subflow.'||name,id from wkf_activity where flow_stop=True and wkf_id=%s", (wkf_id,)) stop = cr.fetchall() stop = (stop[0][1], dict(stop)) return ((start,{}),stop) @@ -88,14 +88,14 @@ def graph_get(cr, graph, wkf_id, nested=False, workitem={}): def graph_instance_get(cr, graph, inst_id, nested=False): workitems = {} - cr.execute('select * from wkf_instance where id=%d', (inst_id,)) + cr.execute('select * from wkf_instance where id=%s', (inst_id,)) inst = cr.dictfetchone() def workitem_get(instance): - cr.execute('select act_id,count(*) from wkf_workitem where inst_id=%d group by act_id', (instance,)) + cr.execute('select act_id,count(*) from wkf_workitem where inst_id=%s group by act_id', (instance,)) workitems = dict(cr.fetchall()) - cr.execute('select subflow_id from wkf_workitem where inst_id=%d', (instance,)) + cr.execute('select subflow_id from wkf_workitem where inst_id=%s', (instance,)) for (subflow_id,) in cr.fetchall(): workitems.update(workitem_get(subflow_id)) return workitems @@ -130,7 +130,7 @@ class report_graph_instance(object): showpage''' else: cr.execute('SELECT id FROM wkf_instance \ - WHERE res_id=%d AND wkf_id=%d \ + WHERE res_id=%s AND wkf_id=%s \ ORDER BY state LIMIT 1', (data['id'], wkfinfo['id'])) inst_id = cr.fetchone() diff --git a/bin/addons/base/module/module.py b/bin/addons/base/module/module.py index a6767cd6c52..de2544df472 100644 --- a/bin/addons/base/module/module.py +++ b/bin/addons/base/module/module.py @@ -68,7 +68,7 @@ class module_category(osv.osv): cr.execute('select category_id,count(*) from ir_module_module where category_id in ('+','.join(map(str,ids))+') or category_id in (select id from ir_module_category where parent_id in ('+','.join(map(str,ids))+')) group by category_id') result = dict(cr.fetchall()) for id in ids: - cr.execute('select id from ir_module_category where parent_id=%d', (id,)) + cr.execute('select id from ir_module_category where parent_id=%s', (id,)) childs = [c for c, in cr.fetchall()] result[id] = reduce(lambda x,y:x+y, [result.get(c, 0) for c in childs], result.get(id, 0)) return result @@ -312,7 +312,7 @@ class module(osv.osv): 'license': terp.get('license', 'GPL-2'), }) cr.execute('DELETE FROM ir_module_module_dependency\ - WHERE module_id = %d', (id,)) + WHERE module_id = %s', (id,)) self._update_dependencies(cr, uid, ids[0], terp.get('depends', [])) self._update_category(cr, uid, ids[0], terp.get('category', @@ -433,7 +433,7 @@ class module(osv.osv): 'license': terp.get('license', 'GPL-2'), }) cr.execute('DELETE FROM ir_module_module_dependency ' \ - 'WHERE module_id = %d', (mod.id,)) + 'WHERE module_id = %s', (mod.id,)) self._update_dependencies(cr, uid, mod.id, terp.get('depends', [])) self._update_category(cr, uid, mod.id, terp.get('category', @@ -445,21 +445,21 @@ class module(osv.osv): def _update_dependencies(self, cr, uid, id, depends=[]): for d in depends: - cr.execute('INSERT INTO ir_module_module_dependency (module_id, name) values (%d, %s)', (id, d)) + cr.execute('INSERT INTO ir_module_module_dependency (module_id, name) values (%s, %s)', (id, d)) def _update_category(self, cr, uid, id, category='Uncategorized'): categs = category.split('/') p_id = None while categs: if p_id is not None: - cr.execute('select id from ir_module_category where name=%s and parent_id=%d', (categs[0], p_id)) + cr.execute('select id from ir_module_category where name=%s and parent_id=%s', (categs[0], p_id)) else: cr.execute('select id from ir_module_category where name=%s and parent_id is NULL', (categs[0],)) c_id = cr.fetchone() if not c_id: cr.execute('select nextval(\'ir_module_category_id_seq\')') c_id = cr.fetchone()[0] - cr.execute('insert into ir_module_category (id, name, parent_id) values (%d, %s, %d)', (c_id, categs[0], p_id)) + cr.execute('insert into ir_module_category (id, name, parent_id) values (%s, %s, %s)', (c_id, categs[0], p_id)) else: c_id = c_id[0] p_id = c_id diff --git a/bin/addons/base/res/partner/partner.py b/bin/addons/base/res/partner/partner.py index 12a82d2b6cd..8aef2eb46fd 100644 --- a/bin/addons/base/res/partner/partner.py +++ b/bin/addons/base/res/partner/partner.py @@ -259,7 +259,7 @@ class res_partner(osv.osv): raise osv.except_osv(_('Warning'), _("Couldn't generate the next id because some partners have an alphabetic id !")) # update the current partner - cr.execute("update res_partner set ref=%d where id=%d", (nextref, ids[0])) + cr.execute("update res_partner set ref=%s where id=%s", (nextref, ids[0])) return True def view_header_get(self, cr, uid, view_id, view_type, context): diff --git a/bin/addons/base/res/res_currency.py b/bin/addons/base/res/res_currency.py index b3849c0e352..8b752e4af5e 100644 --- a/bin/addons/base/res/res_currency.py +++ b/bin/addons/base/res/res_currency.py @@ -39,7 +39,7 @@ class res_currency(osv.osv): date=time.strftime('%Y-%m-%d') date= date or time.strftime('%Y-%m-%d') for id in ids: - cr.execute("SELECT currency_id, rate FROM res_currency_rate WHERE currency_id = %d 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' ORDER BY name desc LIMIT 1" % (id, date)) if cr.rowcount: id, rate=cr.fetchall()[0] res[id]=rate @@ -91,7 +91,7 @@ class res_currency(osv.osv): if account and (account.currency_mode=='average') and account.currency_id: q = self.pool.get('account.move.line')._query_get(cr, uid, context=context) cr.execute('select sum(debit-credit),sum(amount_currency) from account_move_line l ' \ - 'where l.currency_id=%d and l.account_id=%d and '+q, (account.currency_id.id,account.id,)) + 'where l.currency_id=%s and l.account_id=%s and '+q, (account.currency_id.id,account.id,)) tot1,tot2 = cr.fetchone() if tot2 and not account_invert: rate = float(tot1)/float(tot2) diff --git a/bin/addons/base/res/res_request.py b/bin/addons/base/res/res_request.py index 2dd6f1ad4ce..94f4217211f 100644 --- a/bin/addons/base/res/res_request.py +++ b/bin/addons/base/res/res_request.py @@ -34,8 +34,8 @@ class res_request(osv.osv): def request_send(self, cr, uid, ids, *args): for id in ids: - cr.execute('update res_request set state=%s,date_sent=%s where id=%d', ('waiting', time.strftime('%Y-%m-%d %H:%M:%S'), id)) - cr.execute('select act_from,act_to,body,date_sent from res_request where id=%d', (id,)) + cr.execute('update res_request set state=%s,date_sent=%s where id=%s', ('waiting', time.strftime('%Y-%m-%d %H:%M:%S'), id)) + cr.execute('select act_from,act_to,body,date_sent from res_request where id=%s', (id,)) values = cr.dictfetchone() if values['body'] and (len(values['body']) > 128): values['name'] = values['body'][:125] + '...' @@ -47,7 +47,7 @@ class res_request(osv.osv): def request_reply(self, cr, uid, ids, *args): for id in ids: - cr.execute("update res_request set state='active', act_from=%d, act_to=act_from, trigger_date=NULL, body='' where id=%d", (uid,id)) + cr.execute("update res_request set state='active', act_from=%s, act_to=act_from, trigger_date=NULL, body='' where id=%s", (uid,id)) return True def request_close(self, cr, uid, ids, *args): @@ -55,9 +55,9 @@ class res_request(osv.osv): return True def request_get(self, cr, uid): - cr.execute('select id from res_request where act_to=%d and (trigger_date<=%s or trigger_date is null) and active=True', (uid,time.strftime('%Y-%m-%d'))) + cr.execute('select id from res_request where act_to=%s and (trigger_date<=%s or trigger_date is null) and active=True', (uid,time.strftime('%Y-%m-%d'))) ids = map(lambda x:x[0], cr.fetchall()) - cr.execute('select id from res_request where act_from=%d and (act_to<>%d) and (trigger_date<=%s or trigger_date is null) and active=True', (uid,uid,time.strftime('%Y-%m-%d'))) + cr.execute('select id from res_request where act_from=%s and (act_to<>%s) and (trigger_date<=%s or trigger_date is null) and active=True', (uid,uid,time.strftime('%Y-%m-%d'))) ids2 = map(lambda x:x[0], cr.fetchall()) return (ids, ids2) diff --git a/bin/addons/base/res/res_user.py b/bin/addons/base/res/res_user.py index 24c31cf30c3..518acf57944 100644 --- a/bin/addons/base/res/res_user.py +++ b/bin/addons/base/res/res_user.py @@ -74,7 +74,7 @@ class roles(osv.osv): def check(self, cr, uid, ids, role_id): if role_id in ids: return True - cr.execute('select parent_id from res_roles where id=%d', (role_id,)) + cr.execute('select parent_id from res_roles where id=%s', (role_id,)) roles = cr.fetchone()[0] if roles: return self.check(cr, uid, ids, roles) diff --git a/bin/osv/expression.py b/bin/osv/expression.py index 93d3a0bc07b..0ec1e74765b 100644 --- a/bin/osv/expression.py +++ b/bin/osv/expression.py @@ -50,7 +50,7 @@ class expression(object): subids = ids[i:i+cr.IN_MAX] cr.execute('SELECT "%s"' \ ' FROM "%s"' \ - ' WHERE "%s" in (%s)' % (s, f, w, ','.join(['%d']*len(subids))), + ' WHERE "%s" in (%s)' % (s, f, w, ','.join(['%s']*len(subids))), subids) res.extend([r[0] for r in cr.fetchall()]) return res @@ -243,7 +243,7 @@ class expression(object): if len_after: if left == 'id': - instr = ','.join(['%d'] * len_after) + instr = ','.join(['%s'] * len_after) else: instr = ','.join([table._columns[left]._symbol_set[0]] * len_after) query = '(%s.%s %s (%s))' % (table._table, left, operator, instr) diff --git a/bin/service/security.py b/bin/service/security.py index 28f66812c25..81c6ef99744 100644 --- a/bin/service/security.py +++ b/bin/service/security.py @@ -46,7 +46,7 @@ def check(db, uid, passwd): return True cr = pooler.get_db(db).cursor() - cr.execute('select count(*) from res_users where id=%d and password=%s', (int(uid), passwd)) + cr.execute('select count(*) from res_users where id=%s and password=%s', (int(uid), passwd)) res = cr.fetchone()[0] cr.close() if not bool(res): diff --git a/bin/tools/upgrade.py b/bin/tools/upgrade.py index 80a3771f454..8392dbd9e93 100644 --- a/bin/tools/upgrade.py +++ b/bin/tools/upgrade.py @@ -59,7 +59,7 @@ def upgrade(): for module_id,name,url in cr.fetchall(): print '\tremoving module %s' % name remove(name) - cr.execute('update ir_module_module set state=%s where id=%d', ('uninstalled', module_id)) + cr.execute('update ir_module_module set state=%s where id=%s', ('uninstalled', module_id)) cr.commit() print 'Check for modules to upgrade...' @@ -68,7 +68,7 @@ def upgrade(): print '\tupgrading module %s' % name remove(name) install(name, url) - cr.execute('update ir_module_module set state=%s where id=%d', ('installed', module_id)) + cr.execute('update ir_module_module set state=%s where id=%s', ('installed', module_id)) cr.commit() toupdate.append(name) @@ -77,7 +77,7 @@ def upgrade(): for module_id,name,url in cr.fetchall(): print '\tinstalling module %s' % name install(name, url) - cr.execute('update ir_module_module set state=%s where id=%d', ('installed', module_id)) + cr.execute('update ir_module_module set state=%s where id=%s', ('installed', module_id)) cr.commit() toinit.append(name) diff --git a/bin/workflow/instance.py b/bin/workflow/instance.py index 9521135a0e8..ce9dfdd0c6a 100644 --- a/bin/workflow/instance.py +++ b/bin/workflow/instance.py @@ -30,8 +30,8 @@ def create(cr, ident, wkf_id): (uid,res_type,res_id) = ident cr.execute("select nextval('wkf_instance_id_seq')") id_new = cr.fetchone()[0] - cr.execute('insert into wkf_instance (id,res_type,res_id,uid,wkf_id) values (%d,%s,%s,%s,%s)', (id_new,res_type,res_id,uid,wkf_id)) - cr.execute('select * from wkf_activity where flow_start=True and wkf_id=%d', (wkf_id,)) + cr.execute('insert into wkf_instance (id,res_type,res_id,uid,wkf_id) values (%s,%s,%s,%s,%s)', (id_new,res_type,res_id,uid,wkf_id)) + cr.execute('select * from wkf_activity where flow_start=True and wkf_id=%s', (wkf_id,)) res = cr.dictfetchall() stack = [] workitem.create(cr, res, id_new, ident, stack=stack) @@ -40,10 +40,10 @@ def create(cr, ident, wkf_id): def delete(cr, ident): (uid,res_type,res_id) = ident - cr.execute('delete from wkf_instance where res_id=%d and res_type=%s', (res_id,res_type)) + cr.execute('delete from wkf_instance where res_id=%s and res_type=%s', (res_id,res_type)) def validate(cr, inst_id, ident, signal, force_running=False): - cr.execute("select * from wkf_workitem where inst_id=%d", (inst_id,)) + cr.execute("select * from wkf_workitem where inst_id=%s", (inst_id,)) for witem in cr.dictfetchall(): stack = [] workitem.process(cr, witem, ident, signal, force_running, stack=stack) @@ -52,27 +52,27 @@ def validate(cr, inst_id, ident, signal, force_running=False): return stack and stack[0] or False def update(cr, inst_id, ident): - cr.execute("select * from wkf_workitem where inst_id=%d", (inst_id,)) + cr.execute("select * from wkf_workitem where inst_id=%s", (inst_id,)) for witem in cr.dictfetchall(): stack = [] workitem.process(cr, witem, ident, stack=stack) return _update_end(cr, inst_id, ident) def _update_end(cr, inst_id, ident): - cr.execute('select wkf_id from wkf_instance where id=%d', (inst_id,)) + cr.execute('select wkf_id from wkf_instance where id=%s', (inst_id,)) wkf_id = cr.fetchone()[0] - cr.execute('select state,flow_stop from wkf_workitem w left join wkf_activity a on (a.id=w.act_id) where w.inst_id=%d', (inst_id,)) + cr.execute('select state,flow_stop from wkf_workitem w left join wkf_activity a on (a.id=w.act_id) where w.inst_id=%s', (inst_id,)) ok=True for r in cr.fetchall(): if (r[0]<>'complete') or not r[1]: ok=False break if ok: - cr.execute('select distinct a.name from wkf_activity a left join wkf_workitem w on (a.id=w.act_id) where w.inst_id=%d', (inst_id,)) + cr.execute('select distinct a.name from wkf_activity a left join wkf_workitem w on (a.id=w.act_id) where w.inst_id=%s', (inst_id,)) act_names = cr.fetchall() - cr.execute("update wkf_instance set state='complete' where id=%d", (inst_id,)) - cr.execute("update wkf_workitem set state='complete' where subflow_id=%d", (inst_id,)) - cr.execute("select i.id,w.osv,i.res_id from wkf_instance i left join wkf w on (i.wkf_id=w.id) where i.id in (select inst_id from wkf_workitem where subflow_id=%d)", (inst_id,)) + cr.execute("update wkf_instance set state='complete' where id=%s", (inst_id,)) + cr.execute("update wkf_workitem set state='complete' where subflow_id=%s", (inst_id,)) + cr.execute("select i.id,w.osv,i.res_id from wkf_instance i left join wkf w on (i.wkf_id=w.id) where i.id in (select inst_id from wkf_workitem where subflow_id=%s)", (inst_id,)) for i in cr.fetchall(): for act_name in act_names: validate(cr, i[0], (ident[0],i[1],i[2]), 'subflow.'+act_name[0]) diff --git a/bin/workflow/wkf_logs.py b/bin/workflow/wkf_logs.py index 6dbf0ef48ef..17e3bfb1471 100644 --- a/bin/workflow/wkf_logs.py +++ b/bin/workflow/wkf_logs.py @@ -26,7 +26,7 @@ def log(cr,ident,act_id,info=''): pass - #cr.execute('insert into wkf_logs (res_type, res_id, uid, act_id, time, info) values (%s,%d,%d,%d,current_time,%s)', (ident[1],int(ident[2]),int(ident[0]),int(act_id),info)) + #cr.execute('insert into wkf_logs (res_type, res_id, uid, act_id, time, info) values (%s,%s,%s,%s,current_time,%s)', (ident[1],int(ident[2]),int(ident[0]),int(act_id),info)) # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/bin/workflow/wkf_service.py b/bin/workflow/wkf_service.py index 1ac88015d0b..598bf8ac9cf 100644 --- a/bin/workflow/wkf_service.py +++ b/bin/workflow/wkf_service.py @@ -44,15 +44,15 @@ class workflow_service(netsvc.Service): def trg_write(self, uid, res_type, res_id, cr): ident = (uid,res_type,res_id) - cr.execute('select id from wkf_instance where res_id=%d and res_type=%s and state=%s', (res_id,res_type, 'active')) + cr.execute('select id from wkf_instance where res_id=%s and res_type=%s and state=%s', (res_id,res_type, 'active')) for (id,) in cr.fetchall(): instance.update(cr, id, ident) def trg_trigger(self, uid, res_type, res_id, cr): - cr.execute('select instance_id from wkf_triggers where res_id=%d and model=%s', (res_id,res_type)) + cr.execute('select instance_id from wkf_triggers where res_id=%s and model=%s', (res_id,res_type)) res = cr.fetchall() for (instance_id,) in res: - cr.execute('select uid,res_type,res_id from wkf_instance where id=%d', (instance_id,)) + cr.execute('select uid,res_type,res_id from wkf_instance where id=%s', (instance_id,)) ident = cr.fetchone() instance.update(cr, instance_id, ident) @@ -76,7 +76,7 @@ class workflow_service(netsvc.Service): result = False ident = (uid,res_type,res_id) # ids of all active workflow instances for a corresponding resource (id, model_nam) - cr.execute('select id from wkf_instance where res_id=%d and res_type=%s and state=%s', (res_id, res_type, 'active')) + cr.execute('select id from wkf_instance where res_id=%s and res_type=%s and state=%s', (res_id, res_type, 'active')) for (id,) in cr.fetchall(): res2 = instance.validate(cr, id, ident, signal) result = result or res2 @@ -88,21 +88,21 @@ class workflow_service(netsvc.Service): def trg_redirect(self, uid, res_type, res_id, new_rid, cr): # get ids of wkf instances for the old resource (res_id) #CHECKME: shouldn't we get only active instances? - cr.execute('select id, wkf_id from wkf_instance where res_id=%d and res_type=%s', (res_id, res_type)) + cr.execute('select id, wkf_id from wkf_instance where res_id=%s and res_type=%s', (res_id, res_type)) for old_inst_id, wkf_id in cr.fetchall(): # first active instance for new resource (new_rid), using same wkf cr.execute( 'SELECT id '\ 'FROM wkf_instance '\ - 'WHERE res_id=%d AND res_type=%s AND wkf_id=%d AND state=%s', + 'WHERE res_id=%s AND res_type=%s AND wkf_id=%s AND state=%s', (new_rid, res_type, wkf_id, 'active')) new_id = cr.fetchone() if new_id: # select all workitems which "wait" for the old instance - cr.execute('select id from wkf_workitem where subflow_id=%d', (old_inst_id,)) + cr.execute('select id from wkf_workitem where subflow_id=%s', (old_inst_id,)) for (item_id,) in cr.fetchall(): # redirect all those workitems to the wkf instance of the new resource - cr.execute('update wkf_workitem set subflow_id=%d where id=%d', (new_id[0], item_id)) + cr.execute('update wkf_workitem set subflow_id=%s where id=%s', (new_id[0], item_id)) workflow_service() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/bin/workflow/workitem.py b/bin/workflow/workitem.py index 8757fd9024c..6f41bc9602c 100644 --- a/bin/workflow/workitem.py +++ b/bin/workflow/workitem.py @@ -22,7 +22,7 @@ # # TODO: -# cr.execute('delete from wkf_triggers where model=%s and res_id=%d', (res_type,res_id)) +# cr.execute('delete from wkf_triggers where model=%s and res_id=%s', (res_type,res_id)) # import netsvc @@ -35,8 +35,8 @@ def create(cr, act_datas, inst_id, ident, stack): for act in act_datas: cr.execute("select nextval('wkf_workitem_id_seq')") id_new = cr.fetchone()[0] - cr.execute("insert into wkf_workitem (id,act_id,inst_id,state) values (%d,%s,%s,'active')", (id_new, act['id'], inst_id)) - cr.execute('select * from wkf_workitem where id=%d',(id_new,)) + cr.execute("insert into wkf_workitem (id,act_id,inst_id,state) values (%s,%s,%s,'active')", (id_new, act['id'], inst_id)) + cr.execute('select * from wkf_workitem where id=%s',(id_new,)) res = cr.dictfetchone() wkf_logs.log(cr,ident,act['id'],'active') process(cr, res, ident, stack=stack) @@ -45,7 +45,7 @@ def process(cr, workitem, ident, signal=None, force_running=False, stack=None): if stack is None: raise 'Error !!!' result = True - cr.execute('select * from wkf_activity where id=%d', (workitem['act_id'],)) + cr.execute('select * from wkf_activity where id=%s', (workitem['act_id'],)) activity = cr.dictfetchone() triggers = False @@ -63,7 +63,7 @@ def process(cr, workitem, ident, signal=None, force_running=False, stack=None): triggers = triggers and not ok if triggers: - cr.execute('select * from wkf_transition where act_from=%d', (workitem['act_id'],)) + cr.execute('select * from wkf_transition where act_from=%s', (workitem['act_id'],)) alltrans = cr.dictfetchall() for trans in alltrans: if trans['trigger_model']: @@ -71,7 +71,7 @@ def process(cr, workitem, ident, signal=None, force_running=False, stack=None): for res_id in ids: cr.execute('select nextval(\'wkf_triggers_id_seq\')') id =cr.fetchone()[0] - cr.execute('insert into wkf_triggers (model,res_id,instance_id,workitem_id,id) values (%s,%d,%d,%d,%d)', (trans['trigger_model'],res_id,workitem['inst_id'], workitem['id'], id)) + cr.execute('insert into wkf_triggers (model,res_id,instance_id,workitem_id,id) values (%s,%s,%s,%s,%s)', (trans['trigger_model'],res_id,workitem['inst_id'], workitem['id'], id)) return result @@ -79,7 +79,7 @@ def process(cr, workitem, ident, signal=None, force_running=False, stack=None): # ---------------------- PRIVATE FUNCS -------------------------------- def _state_set(cr, workitem, activity, state, ident): - cr.execute('update wkf_workitem set state=%s where id=%d', (state,workitem['id'])) + cr.execute('update wkf_workitem set state=%s where id=%s', (state,workitem['id'])) workitem['state'] = state wkf_logs.log(cr,ident,activity['id'],state) @@ -89,7 +89,7 @@ def _execute(cr, workitem, activity, ident, stack): # send a signal to parent workflow (signal: subflow.signal_name) # if (workitem['state']=='active') and activity['signal_send']: - cr.execute("select i.id,w.osv,i.res_id from wkf_instance i left join wkf w on (i.wkf_id=w.id) where i.id in (select inst_id from wkf_workitem where subflow_id=%d)", (workitem['inst_id'],)) + cr.execute("select i.id,w.osv,i.res_id from wkf_instance i left join wkf w on (i.wkf_id=w.id) where i.id in (select inst_id from wkf_workitem where subflow_id=%s)", (workitem['inst_id'],)) for i in cr.fetchall(): instance.validate(cr, i[0], (ident[0],i[1],i[2]), activity['signal_send'], force_running=True) @@ -116,7 +116,7 @@ def _execute(cr, workitem, activity, ident, stack): elif activity['kind']=='stopall': if workitem['state']=='active': _state_set(cr, workitem, activity, 'running', ident) - cr.execute('delete from wkf_workitem where inst_id=%d and id<>%d', (workitem['inst_id'], workitem['id'])) + cr.execute('delete from wkf_workitem where inst_id=%s and id<>%s', (workitem['inst_id'], workitem['id'])) if activity['action']: wkf_expr.execute(cr, ident, workitem, activity) _state_set(cr, workitem, activity, 'complete', ident) @@ -129,14 +129,14 @@ def _execute(cr, workitem, activity, ident, stack): cr.execute('delete from wkf_workitem where id=%s', (workitem['id'],)) return False assert type(id_new)==type(1) or type(id_new)==type(1L), 'Wrong return value: '+str(id_new)+' '+str(type(id_new)) - cr.execute('select id from wkf_instance where res_id=%d and wkf_id=%d', (id_new,activity['subflow_id'])) + cr.execute('select id from wkf_instance where res_id=%s and wkf_id=%s', (id_new,activity['subflow_id'])) id_new = cr.fetchone()[0] else: id_new = instance.create(cr, ident, activity['subflow_id']) - cr.execute('update wkf_workitem set subflow_id=%d where id=%s', (id_new, workitem['id'])) + cr.execute('update wkf_workitem set subflow_id=%s where id=%s', (id_new, workitem['id'])) workitem['subflow_id'] = id_new if workitem['state']=='running': - cr.execute("select state from wkf_instance where id=%d", (workitem['subflow_id'],)) + cr.execute("select state from wkf_instance where id=%s", (workitem['subflow_id'],)) state= cr.fetchone()[0] if state=='complete': _state_set(cr, workitem, activity, 'complete', ident) @@ -145,7 +145,7 @@ def _execute(cr, workitem, activity, ident, stack): def _split_test(cr, workitem, split_mode, ident, signal=None, stack=None): if stack is None: raise 'Error !!!' - cr.execute('select * from wkf_transition where act_from=%d', (workitem['act_id'],)) + cr.execute('select * from wkf_transition where act_from=%s', (workitem['act_id'],)) test = False transitions = [] alltrans = cr.dictfetchall() @@ -162,36 +162,36 @@ def _split_test(cr, workitem, split_mode, ident, signal=None, stack=None): if not wkf_expr.check(cr, workitem, ident, transition,signal): test = False break - cr.execute('select count(*) from wkf_witm_trans where trans_id=%d and inst_id=%d', (transition['id'], workitem['inst_id'])) + cr.execute('select count(*) from wkf_witm_trans where trans_id=%s and inst_id=%s', (transition['id'], workitem['inst_id'])) if not cr.fetchone()[0]: transitions.append((transition['id'], workitem['inst_id'])) if test and len(transitions): - cr.executemany('insert into wkf_witm_trans (trans_id,inst_id) values (%d,%d)', transitions) - cr.execute('delete from wkf_workitem where id=%d', (workitem['id'],)) + cr.executemany('insert into wkf_witm_trans (trans_id,inst_id) values (%s,%s)', transitions) + cr.execute('delete from wkf_workitem where id=%s', (workitem['id'],)) for t in transitions: _join_test(cr, t[0], t[1], ident, stack) return True return False def _join_test(cr, trans_id, inst_id, ident, stack): - cr.execute('select * from wkf_activity where id=(select act_to from wkf_transition where id=%d)', (trans_id,)) + cr.execute('select * from wkf_activity where id=(select act_to from wkf_transition where id=%s)', (trans_id,)) activity = cr.dictfetchone() if activity['join_mode']=='XOR': create(cr,[activity], inst_id, ident, stack) - cr.execute('delete from wkf_witm_trans where inst_id=%d and trans_id=%d', (inst_id,trans_id)) + cr.execute('delete from wkf_witm_trans where inst_id=%s and trans_id=%s', (inst_id,trans_id)) else: - cr.execute('select id from wkf_transition where act_to=%d', (activity['id'],)) + cr.execute('select id from wkf_transition where act_to=%s', (activity['id'],)) trans_ids = cr.fetchall() ok = True for (id,) in trans_ids: - cr.execute('select count(*) from wkf_witm_trans where trans_id=%d and inst_id=%d', (id,inst_id)) + cr.execute('select count(*) from wkf_witm_trans where trans_id=%s and inst_id=%s', (id,inst_id)) res = cr.fetchone()[0] if not res: ok = False break if ok: for (id,) in trans_ids: - cr.execute('delete from wkf_witm_trans where trans_id=%d and inst_id=%d', (id,inst_id)) + cr.execute('delete from wkf_witm_trans where trans_id=%s and inst_id=%s', (id,inst_id)) create(cr, [activity], inst_id, ident, stack) # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From 822da77ee66b6d7e36ab100fa30ee8ee397c15bc Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Tue, 9 Dec 2008 14:31:32 +0100 Subject: [PATCH 027/137] [FIX] psycopg2: convert types & update web_services bzr revid: christophe@tinyerp.com-20081209133132-wn7v8d2qyo3cv6x5 --- bin/service/web_services.py | 10 ++++------ bin/sql_db.py | 35 +++++++++++++++++++++++++++++++---- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/bin/service/web_services.py b/bin/service/web_services.py index 69d8015f241..55ecdf91f04 100644 --- a/bin/service/web_services.py +++ b/bin/service/web_services.py @@ -65,8 +65,8 @@ class db(netsvc.Service): self.actions[id] = {'clean': False} db = sql_db.db_connect('template1', serialize=1) - db.truedb.autocommit() cr = db.cursor() + cr.autocommit(True) time.sleep(0.2) cr.execute('CREATE DATABASE ' + db_name + ' ENCODING \'unicode\'') cr.close() @@ -140,12 +140,12 @@ class db(netsvc.Service): def drop(self, password, db_name): security.check_super(password) - pooler.close_db(db_name) + sql_db.close_db(db_name) logger = netsvc.Logger() db = sql_db.db_connect('template1', serialize=1) - db.truedb.autocommit() cr = db.cursor() + cr.autocommit(True) try: try: cr.execute('DROP DATABASE ' + db_name) @@ -195,8 +195,8 @@ class db(netsvc.Service): raise Exception, "Database already exists" db = sql_db.db_connect('template1', serialize=1) - db.truedb.autocommit() cr = db.cursor() + cr.autocommit(True) cr.execute('CREATE DATABASE ' + db_name + ' ENCODING \'unicode\'') cr.close() @@ -231,7 +231,6 @@ class db(netsvc.Service): def db_exist(self, db_name): try: db = sql_db.db_connect(db_name) - db.truedb.close() return True except: return False @@ -256,7 +255,6 @@ class db(netsvc.Service): cr.close() except: res = [] - db.truedb.close() res.sort() return res diff --git a/bin/sql_db.py b/bin/sql_db.py index e52b94d89fa..ccf57d0c718 100644 --- a/bin/sql_db.py +++ b/bin/sql_db.py @@ -28,6 +28,21 @@ from psycopg2.psycopg1 import cursor as psycopg1cursor import psycopg2.extensions psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) +types_mapping = { + 'date': (1082,), + 'time': (1083,), + 'datetime': (1114,), +} + +def undecimalize(symb, cr): + if symb is None: return None + return float(symb) + +for name, typeoid in types_mapping.items(): + psycopg2.extensions.register_type(psycopg2.extensions.new_type(typeoid, name, lambda x, cr: x)) +psycopg2.extensions.register_type(psycopg2.extensions.new_type((700, 701, 1700,), 'float', undecimalize)) + + import tools import re @@ -64,16 +79,19 @@ class Cursor(object): query = base_string(query) if '%d' in query or '%f' in query: - log(queyr, netsvc.LOG_WARNING) + #import traceback + #traceback.print_stack() + log(query, netsvc.LOG_WARNING) log("SQL queries mustn't containt %d or %f anymore. Use only %s", netsvc.LOG_WARNING) - query = query.replace('%d', '%s').replace('%f', '%s') + if p: + query = query.replace('%d', '%s').replace('%f', '%s') if self.sql_log: now = mdt.now() log("SQL LOG query: %s" % (query,)) log("SQL LOG params: %r" % (p,)) - res = self._obj.execute(query, p) + res = self._obj.execute(query, p or None) if self.sql_log: self.count+=1 @@ -103,7 +121,7 @@ class Cursor(object): log("SUM:%s/%d" % (sum, self.count)) def close(self): - if self.sql_log: + if self.sql_from_log or self.sql_into_log: self.print_log('from') self.print_log('into') self._obj.close() @@ -166,8 +184,17 @@ class PoolManager(object): return PoolManager._pools[db_name] get = staticmethod(get) + def close(db_name): + if db_name is PoolManager._pools: + PoolManager._pools[db_name].closeall() + del PoolManager._pools[db_name] + close = staticmethod(close) + def db_connect(db_name, serialize=0): return PoolManager.get(db_name) +def close_db(db_name): + return PoolManager.close(db_name) + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From e09455ccd8ef2af53ce8eaf17b2cde305a8fd1c0 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Tue, 9 Dec 2008 14:35:40 +0100 Subject: [PATCH 028/137] [FIX] psycopg2: %d -> %s [IMP] orm: use _symbol_f when updating database at initialization [IMP] misc.ustr: function returning the unicode string representation of a object bzr revid: christophe@tinyerp.com-20081209133540-zlb6wxs97cxa99nx --- bin/osv/fields.py | 59 ++++++++-------- bin/osv/orm.py | 165 ++++++++++++++++++++++--------------------- bin/tools/convert.py | 12 ++-- bin/tools/misc.py | 30 ++++++-- 4 files changed, 145 insertions(+), 121 deletions(-) diff --git a/bin/osv/fields.py b/bin/osv/fields.py index 097697cb3e1..617399478f1 100644 --- a/bin/osv/fields.py +++ b/bin/osv/fields.py @@ -86,7 +86,7 @@ class _column(object): pass def set(self, cr, obj, id, name, value, user=None, context=None): - cr.execute('update '+obj._table+' set '+name+'='+self._symbol_set[0]+' where id=%d', (self._symbol_set[1](value), id)) + cr.execute('update '+obj._table+' set '+name+'='+self._symbol_set[0]+' where id=%s', (self._symbol_set[1](value), id)) def set_memory(self, cr, obj, id, name, value, user=None, context=None): raise Exception(_('Not implemented set_memory method !')) @@ -118,13 +118,13 @@ class boolean(_column): class integer_big(_column): _type = 'integer_big' - _symbol_c = '%d' + _symbol_c = '%s' _symbol_f = lambda x: int(x or 0) _symbol_set = (_symbol_c, _symbol_f) class integer(_column): _type = 'integer' - _symbol_c = '%d' + _symbol_c = '%s' _symbol_f = lambda x: int(x or 0) _symbol_set = (_symbol_c, _symbol_f) @@ -168,10 +168,9 @@ class text(_column): import __builtin__ - class float(_column): _type = 'float' - _symbol_c = '%f' + _symbol_c = '%s' _symbol_f = lambda x: __builtin__.float(x or 0.0) _symbol_set = (_symbol_c, _symbol_f) @@ -263,9 +262,9 @@ class one2one(_column): self._table = obj_src.pool.get(self._obj)._table if act[0] == 0: id_new = obj.create(cr, user, act[1]) - cr.execute('update '+obj_src._table+' set '+field+'=%d where id=%d', (id_new, id)) + cr.execute('update '+obj_src._table+' set '+field+'=%s where id=%s', (id_new, id)) else: - cr.execute('select '+field+' from '+obj_src._table+' where id=%d', (act[0],)) + cr.execute('select '+field+' from '+obj_src._table+' where id=%s', (act[0],)) id = cr.fetchone()[0] obj.write(cr, user, [id], act[1], context=context) @@ -331,20 +330,20 @@ class many2one(_column): for act in values: if act[0] == 0: id_new = obj.create(cr, act[2]) - cr.execute('update '+obj_src._table+' set '+field+'=%d where id=%d', (id_new, id)) + cr.execute('update '+obj_src._table+' set '+field+'=%s where id=%s', (id_new, id)) elif act[0] == 1: obj.write(cr, [act[1]], act[2], context=context) elif act[0] == 2: - cr.execute('delete from '+self._table+' where id=%d', (act[1],)) + cr.execute('delete from '+self._table+' where id=%s', (act[1],)) elif act[0] == 3 or act[0] == 5: - cr.execute('update '+obj_src._table+' set '+field+'=null where id=%d', (id,)) + cr.execute('update '+obj_src._table+' set '+field+'=null where id=%s', (id,)) elif act[0] == 4: - cr.execute('update '+obj_src._table+' set '+field+'=%d where id=%d', (act[1], id)) + cr.execute('update '+obj_src._table+' set '+field+'=%s where id=%s', (act[1], id)) else: if values: - cr.execute('update '+obj_src._table+' set '+field+'=%d where id=%d', (values, id)) + cr.execute('update '+obj_src._table+' set '+field+'=%s where id=%s', (values, id)) else: - cr.execute('update '+obj_src._table+' set '+field+'=null where id=%d', (id,)) + cr.execute('update '+obj_src._table+' set '+field+'=null where id=%s', (id,)) def search(self, cr, obj, args, name, value, offset=0, limit=None, uid=None): return obj.pool.get(self._obj).search(cr, uid, args+self._domain+[('name', 'like', value)], offset, limit) @@ -435,19 +434,19 @@ class one2many(_column): elif act[0] == 2: obj.unlink(cr, user, [act[1]], context=context) elif act[0] == 3: - cr.execute('update '+_table+' set '+self._fields_id+'=null where id=%d', (act[1],)) + cr.execute('update '+_table+' set '+self._fields_id+'=null where id=%s', (act[1],)) elif act[0] == 4: - cr.execute('update '+_table+' set '+self._fields_id+'=%d where id=%d', (id, act[1])) + cr.execute('update '+_table+' set '+self._fields_id+'=%s where id=%s', (id, act[1])) elif act[0] == 5: - cr.execute('update '+_table+' set '+self._fields_id+'=null where '+self._fields_id+'=%d', (id,)) + cr.execute('update '+_table+' set '+self._fields_id+'=null where '+self._fields_id+'=%s', (id,)) elif act[0] == 6: if not act[2]: ids2 = [0] else: ids2 = act[2] - cr.execute('update '+_table+' set '+self._fields_id+'=NULL where '+self._fields_id+'=%d and id not in ('+','.join(map(str, ids2))+')', (id,)) + cr.execute('update '+_table+' set '+self._fields_id+'=NULL where '+self._fields_id+'=%s and id not in ('+','.join(map(str, ids2))+')', (id,)) if act[2]: - cr.execute('update '+_table+' set '+self._fields_id+'=%d where id in ('+','.join(map(str, act[2]))+')', (id,)) + cr.execute('update '+_table+' set '+self._fields_id+'=%s where id in ('+','.join(map(str, act[2]))+')', (id,)) def search(self, cr, obj, args, name, value, offset=0, limit=None, uid=None, operator='like'): return obj.pool.get(self._obj).name_search(cr, uid, value, self._domain, offset, limit) @@ -500,7 +499,7 @@ class many2many(_column): FROM '+self._rel+' , '+obj._table+' \ WHERE '+self._rel+'.'+self._id1+' in ('+ids_s+') \ AND '+self._rel+'.'+self._id2+' = '+obj._table+'.id '+d1 - +limit_str+' order by '+obj._table+'.'+obj._order+' offset %d', + +limit_str+' order by '+obj._table+'.'+obj._order+' offset %s', d2+[offset]) for r in cr.fetchall(): res[r[1]].append(r[0]) @@ -515,26 +514,26 @@ class many2many(_column): for act in values: if act[0] == 0: idnew = obj.create(cr, user, act[2]) - cr.execute('insert into '+self._rel+' ('+self._id1+','+self._id2+') values (%d,%d)', (id, idnew)) + cr.execute('insert into '+self._rel+' ('+self._id1+','+self._id2+') values (%s,%s)', (id, idnew)) elif act[0] == 1: obj.write(cr, user, [act[1]], act[2], context=context) elif act[0] == 2: obj.unlink(cr, user, [act[1]], context=context) elif act[0] == 3: - cr.execute('delete from '+self._rel+' where ' + self._id1 + '=%d and '+ self._id2 + '=%d', (id, act[1])) + cr.execute('delete from '+self._rel+' where ' + self._id1 + '=%s and '+ self._id2 + '=%s', (id, act[1])) elif act[0] == 4: - cr.execute('insert into '+self._rel+' ('+self._id1+','+self._id2+') values (%d,%d)', (id, act[1])) + cr.execute('insert into '+self._rel+' ('+self._id1+','+self._id2+') values (%s,%s)', (id, act[1])) elif act[0] == 5: - cr.execute('update '+self._rel+' set '+self._id2+'=null where '+self._id2+'=%d', (id,)) + cr.execute('update '+self._rel+' set '+self._id2+'=null where '+self._id2+'=%s', (id,)) elif act[0] == 6: d1, d2 = obj.pool.get('ir.rule').domain_get(cr, user, obj._name) if d1: d1 = ' and ' + d1 - cr.execute('delete from '+self._rel+' where '+self._id1+'=%d AND '+self._id2+' IN (SELECT '+self._rel+'.'+self._id2+' FROM '+self._rel+', '+obj._table+' WHERE '+self._rel+'.'+self._id1+'=%d AND '+self._rel+'.'+self._id2+' = '+obj._table+'.id '+ d1 +')', [id, id]+d2) + cr.execute('delete from '+self._rel+' where '+self._id1+'=%s AND '+self._id2+' IN (SELECT '+self._rel+'.'+self._id2+' FROM '+self._rel+', '+obj._table+' WHERE '+self._rel+'.'+self._id1+'=%s AND '+self._rel+'.'+self._id2+' = '+obj._table+'.id '+ d1 +')', [id, id]+d2) for act_nbr in act[2]: - cr.execute('insert into '+self._rel+' ('+self._id1+','+self._id2+') values (%d, %d)', (id, act_nbr)) + cr.execute('insert into '+self._rel+' ('+self._id1+','+self._id2+') values (%s, %s)', (id, act_nbr)) # # TODO: use a name_search @@ -601,9 +600,9 @@ class function(_column): self._classic_read = True self._classic_write = True if type == 'float': - self._symbol_c = '%f' - self._symbol_f = lambda x: __builtin__.float(x or 0.0) - self._symbol_set = (self._symbol_c, self._symbol_f) + self._symbol_c = float._symbol_c + self._symbol_f = float._symbol_f + self._symbol_set = float._symbol_set def search(self, cr, uid, obj, name, args): if not self._fnct_search: @@ -680,7 +679,7 @@ class related(function): if field_detail[1] in ('date'): where += " %s.%s %s '%s' and" % (obj_child._table, self._arg[i], context[0][1], context[0][2]) if field_detail[1] in ['integer', 'long', 'float','integer_big']: - where += " %s.%s %s '%d' and" % (obj_child._table, self._arg[i], context[0][1], context[0][2]) + where += " %s.%s %s '%s' and" % (obj_child._table, self._arg[i], context[0][1], context[0][2]) if len(where)>10: query += where.rstrip('and') cr.execute(query) @@ -754,7 +753,7 @@ class property(function): nid = property.search(cr, uid, [('fields_id', '=', definition_id), ('res_id', '=', obj._name+','+str(id))]) while len(nid): - cr.execute('DELETE FROM ir_property WHERE id=%d', (nid.pop(),)) + cr.execute('DELETE FROM ir_property WHERE id=%s', (nid.pop(),)) nid = property.search(cr, uid, [('fields_id', '=', definition_id), ('res_id', '=', False)]) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index c9c813da720..5a2c8aaf34b 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -342,7 +342,7 @@ class orm_template(object): id, model_id, model, name, field_description, ttype, relation,view_load,state,select_level ) VALUES ( - %d,%s,%s,%s,%s,%s,%s,%s,%s,%s + %s,%s,%s,%s,%s,%s,%s,%s,%s,%s )""", ( id, vals['model_id'], vals['model'], vals['name'], vals['field_description'], vals['ttype'], vals['relation'], bool(vals['view_load']), 'base', @@ -995,7 +995,7 @@ class orm_template(object): while ok: if view_id: where = (model and (" and model='%s'" % (self._name,))) or '' - cr.execute('SELECT arch,name,field_parent,id,type,inherit_id FROM ir_ui_view WHERE id=%d'+where, (view_id,)) + cr.execute('SELECT arch,name,field_parent,id,type,inherit_id FROM ir_ui_view WHERE id=%s'+where, (view_id,)) else: cr.execute('''SELECT arch,name,field_parent,id,type,inherit_id @@ -1021,7 +1021,7 @@ class orm_template(object): def _inherit_apply_rec(result, inherit_id): # get all views which inherit from (ie modify) this view - cr.execute('select arch,id from ir_ui_view where inherit_id=%d and model=%s order by priority', (inherit_id, self._name)) + cr.execute('select arch,id from ir_ui_view where inherit_id=%s and model=%s order by priority', (inherit_id, self._name)) sql_inherit = cr.fetchall() for (inherit, id) in sql_inherit: result = _inherit_apply(result, inherit) @@ -1368,7 +1368,7 @@ class orm(orm_template): childs = cr.fetchall() for id in childs: pos2 = browse_rec(id[0], pos2) - cr.execute('update '+self._table+' set parent_left=%d, parent_right=%d where id=%d', (pos,pos2,root)) + cr.execute('update '+self._table+' set parent_left=%s, parent_right=%s where id=%s', (pos,pos2,root)) return pos2+1 browse_rec(None) return True @@ -1396,8 +1396,8 @@ class orm(orm_template): logger.notifyChannel('init', netsvc.LOG_ERROR, 'create a column parent_right on object %s: fields.integer(\'Right Parent\', select=1)' % (self._table, )) if self._columns[self._parent_name].ondelete<>'cascade': logger.notifyChannel('init', netsvc.LOG_ERROR, "the columns %s on object must be set as ondelete='cascasde'" % (self._name, self._parent_name)) - cr.execute("ALTER TABLE \"%s\" ADD COLUMN \"%s\" INTEGER" % (self._table, 'parent_left')) - cr.execute("ALTER TABLE \"%s\" ADD COLUMN \"%s\" INTEGER" % (self._table, 'parent_right')) + cr.execute('ALTER TABLE "%s" ADD COLUMN "parent_left" INTEGER' % (self._table,)) + cr.execute('ALTER TABLE "%s" ADD COLUMN "parent_right" INTEGER' % (self._table,)) cr.commit() store_compute = True @@ -1409,15 +1409,13 @@ class orm(orm_template): 'write_date': 'TIMESTAMP' } for k in logs: - cr.execute( - """ + cr.execute(""" SELECT c.relname - FROM pg_class c, pg_attribute a - WHERE c.relname='%s' AND a.attname='%s' AND c.oid=a.attrelid - """ % (self._table, k)) + FROM pg_class c, pg_attribute a + WHERE c.relname=%s AND a.attname=%s AND c.oid=a.attrelid + """, (self._table, k)) if not cr.rowcount: - cr.execute("ALTER TABLE \"%s\" ADD COLUMN \"%s\" %s" % - (self._table, k, logs[k])) + cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (self._table, k, logs[k])) cr.commit() # iterate on the database columns to drop the NOT NULL constraints @@ -1425,12 +1423,12 @@ class orm(orm_template): cr.execute( "SELECT a.attname, a.attnotnull "\ "FROM pg_class c, pg_attribute a "\ - "WHERE c.oid=a.attrelid AND c.relname='%s'" % self._table) + "WHERE c.oid=a.attrelid AND c.relname=%s", (self._table,)) db_columns = cr.dictfetchall() for column in db_columns: if column['attname'] not in ('id', 'oid', 'tableoid', 'ctid', 'xmin', 'xmax', 'cmin', 'cmax'): if column['attnotnull'] and column['attname'] not in self._columns: - cr.execute("ALTER TABLE \"%s\" ALTER COLUMN \"%s\" DROP NOT NULL" % (self._table, column['attname'])) + cr.execute('ALTER TABLE "%s" ALTER COLUMN "%s" DROP NOT NULL' % (self._table, column['attname'])) # iterate on the "object columns" todo_update_store = [] @@ -1443,10 +1441,10 @@ class orm(orm_template): if isinstance(f, fields.one2many): cr.execute("SELECT relname FROM pg_class WHERE relkind='r' AND relname=%s", (f._obj,)) if cr.fetchone(): - cr.execute("SELECT count(*) as c FROM pg_class c,pg_attribute a WHERE c.relname=%s AND a.attname=%s AND c.oid=a.attrelid", (f._obj, f._fields_id)) + cr.execute("SELECT count(1) as c FROM pg_class c,pg_attribute a WHERE c.relname=%s AND a.attname=%s AND c.oid=a.attrelid", (f._obj, f._fields_id)) res = cr.fetchone()[0] if not res: - cr.execute("ALTER TABLE \"%s\" ADD FOREIGN KEY (%s) REFERENCES \"%s\" ON DELETE SET NULL" % (self._obj, f._fields_id, f._table)) + cr.execute('ALTER TABLE "%s" ADD FOREIGN KEY (%s) REFERENCES "%s" ON DELETE SET NULL' % (self._obj, f._fields_id, f._table)) elif isinstance(f, fields.many2many): cr.execute("SELECT relname FROM pg_class WHERE relkind in ('r','v') AND relname=%s", (f._rel,)) if not cr.dictfetchall(): @@ -1455,9 +1453,9 @@ class orm(orm_template): ref = self.pool.get(f._obj)._table except AttributeError: ref = f._obj.replace('.', '_') - cr.execute("CREATE TABLE \"%s\" (\"%s\" INTEGER NOT NULL REFERENCES \"%s\" ON DELETE CASCADE, \"%s\" INTEGER NOT NULL REFERENCES \"%s\" ON DELETE CASCADE) WITH OIDS"%(f._rel, f._id1, self._table, f._id2, ref)) - cr.execute("CREATE INDEX \"%s_%s_index\" ON \"%s\" (\"%s\")" % (f._rel, f._id1, f._rel, f._id1)) - cr.execute("CREATE INDEX \"%s_%s_index\" ON \"%s\" (\"%s\")" % (f._rel, f._id2, f._rel, f._id2)) + cr.execute('CREATE TABLE "%s" ("%s" INTEGER NOT NULL REFERENCES "%s" ON DELETE CASCADE, "%s" INTEGER NOT NULL REFERENCES "%s" ON DELETE CASCADE) WITH OIDS' % (f._rel, f._id1, self._table, f._id2, ref)) + cr.execute('CREATE INDEX "%s_%s_index" ON "%s" ("%s")' % (f._rel, f._id1, f._rel, f._id1)) + cr.execute('CREATE INDEX "%s_%s_index" ON "%s" ("%s")' % (f._rel, f._id2, f._rel, f._id2)) cr.commit() else: cr.execute("SELECT c.relname,a.attname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,t.typname,CASE WHEN a.attlen=-1 THEN a.atttypmod-4 ELSE a.attlen END as size FROM pg_class c,pg_attribute a,pg_type t WHERE c.relname=%s AND a.attname=%s AND c.oid=a.attrelid AND a.atttypid=t.oid", (self._table, k)) @@ -1466,15 +1464,14 @@ class orm(orm_template): if not isinstance(f, fields.function) or f.store: # add the missing field - cr.execute("ALTER TABLE \"%s\" ADD COLUMN \"%s\" %s" % (self._table, k, get_pg_type(f)[1])) + cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (self._table, k, get_pg_type(f)[1])) # initialize it if not create and k in self._defaults: default = self._defaults[k](self, cr, 1, {}) - if not default: - cr.execute("UPDATE \"%s\" SET \"%s\"=NULL" % (self._table, k)) - else: - cr.execute("UPDATE \"%s\" SET \"%s\"='%s'" % (self._table, k, default)) + ss = self._columns[k]._symbol_set + query = 'UPDATE "%s" SET "%s"=%s' % (self._table, k, ss[0]) + cr.execute(query, (default is not None and ss[1](default) or None,)) if isinstance(f, fields.function): todo_update_store.append((f,k)) @@ -1488,13 +1485,13 @@ class orm(orm_template): ref = f._obj.replace('.', '_') # ir_actions is inherited so foreign key doesn't work on it if ref != 'ir_actions': - cr.execute("ALTER TABLE \"%s\" ADD FOREIGN KEY (\"%s\") REFERENCES \"%s\" ON DELETE %s" % (self._table, k, ref, f.ondelete)) + cr.execute('ALTER TABLE "%s" ADD FOREIGN KEY ("%s") REFERENCES "%s" ON DELETE %s' % (self._table, k, ref, f.ondelete)) if f.select: - cr.execute("CREATE INDEX \"%s_%s_index\" ON \"%s\" (\"%s\")" % (self._table, k, self._table, k)) + cr.execute('CREATE INDEX "%s_%s_index" ON "%s" ("%s")' % (self._table, k, self._table, k)) if f.required: cr.commit() try: - cr.execute("ALTER TABLE \"%s\" ALTER COLUMN \"%s\" SET NOT NULL" % (self._table, k)) + cr.execute('ALTER TABLE "%s" ALTER COLUMN "%s" SET NOT NULL' % (self._table, k)) except: logger.notifyChannel('init', netsvc.LOG_WARNING, 'WARNING: unable to set column %s of table %s not null !\nTry to re-run: openerp-server.py --update=module\nIf it doesn\'t work, update records and execute manually:\nALTER TABLE %s ALTER COLUMN %s SET NOT NULL' % (k, self._table, self._table, k)) cr.commit() @@ -1521,61 +1518,64 @@ class orm(orm_template): # We update varchar size, otherwise, we keep DB size # to avoid truncated string... if f_pg_size < f.size: - cr.execute("ALTER TABLE \"%s\" RENAME COLUMN \"%s\" TO temp_change_size" % (self._table, k)) - cr.execute("ALTER TABLE \"%s\" ADD COLUMN \"%s\" VARCHAR(%d)" % (self._table, k, f.size)) - cr.execute("UPDATE \"%s\" SET \"%s\"=temp_change_size::VARCHAR(%d)" % (self._table, k, f.size)) - cr.execute("ALTER TABLE \"%s\" DROP COLUMN temp_change_size" % (self._table,)) + cr.execute('ALTER TABLE "%s" RENAME COLUMN "%s" TO temp_change_size' % (self._table, k)) + cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" VARCHAR(%d)' % (self._table, k, f.size)) + cr.execute('UPDATE "%s" SET "%s"=temp_change_size::VARCHAR(%d)' % (self._table, k, f.size)) + cr.execute('ALTER TABLE "%s" DROP COLUMN temp_change_size' % (self._table,)) cr.commit() if f_pg_type == 'date' and f._type == 'datetime': - cr.execute("ALTER TABLE \"%s\" RENAME COLUMN \"%s\" TO temp_change_type" % (self._table, k)) - cr.execute("ALTER TABLE \"%s\" ADD COLUMN \"%s\" TIMESTAMP " % (self._table, k)) - cr.execute("UPDATE \"%s\" SET \"%s\"=temp_change_type::TIMESTAMP" % (self._table, k)) - cr.execute("ALTER TABLE \"%s\" DROP COLUMN temp_change_type" % (self._table,)) + cr.execute('ALTER TABLE "%s" RENAME COLUMN "%s" TO temp_change_type' % (self._table, k)) + cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" TIMESTAMP' % (self._table, k)) + cr.execute('UPDATE "%s" SET "%s"=temp_change_type::TIMESTAMP' % (self._table, k)) + cr.execute('ALTER TABLE "%s" DROP COLUMN temp_change_type' % (self._table,)) cr.commit() # if the field is required and hasn't got a NOT NULL constraint if f.required and f_pg_notnull == 0: # set the field to the default value if any if k in self._defaults: default = self._defaults[k](self, cr, 1, {}) - if not (default is False): - cr.execute("UPDATE \"%s\" SET \"%s\"='%s' WHERE %s is NULL" % (self._table, k, default, k)) + if (default is not None): + ss = self._columns[k]._symbol_set + query = 'UPDATE "%s" SET "%s"=%s WHERE %s is NULL' % (self._table, k, ss[0], k) + cr.execute(query, (ss[1](default),)) cr.commit() # add the NOT NULL constraint try: - cr.execute("ALTER TABLE \"%s\" ALTER COLUMN \"%s\" SET NOT NULL" % (self._table, k)) + cr.execute('ALTER TABLE "%s" ALTER COLUMN "%s" SET NOT NULL' % (self._table, k)) cr.commit() except: logger.notifyChannel('init', netsvc.LOG_WARNING, 'unable to set a NOT NULL constraint on column %s of the %s table !\nIf you want to have it, you should update the records and execute manually:\nALTER TABLE %s ALTER COLUMN %s SET NOT NULL' % (k, self._table, self._table, k)) cr.commit() elif not f.required and f_pg_notnull == 1: - cr.execute("ALTER TABLE \"%s\" ALTER COLUMN \"%s\" DROP NOT NULL" % (self._table, k)) + cr.execute('ALTER TABLE "%s" ALTER COLUMN "%s" DROP NOT NULL' % (self._table, k)) cr.commit() - cr.execute("SELECT indexname FROM pg_indexes WHERE indexname = '%s_%s_index' and tablename = '%s'" % (self._table, k, self._table)) + indexname = '%s_%s_index' % (self._table, k) + cr.execute("SELECT indexname FROM pg_indexes WHERE indexname = %s and tablename = %s", (indexname, self._table)) res = cr.dictfetchall() if not res and f.select: - cr.execute("CREATE INDEX \"%s_%s_index\" ON \"%s\" (\"%s\")" % (self._table, k, self._table, k)) + cr.execute('CREATE INDEX "%s_%s_index" ON "%s" ("%s")' % (self._table, k, self._table, k)) cr.commit() if res and not f.select: - cr.execute("DROP INDEX \"%s_%s_index\"" % (self._table, k)) + cr.execute('DROP INDEX "%s_%s_index"' % (self._table, k)) cr.commit() if isinstance(f, fields.many2one): ref = self.pool.get(f._obj)._table if ref != 'ir_actions': - cr.execute('SELECT confdeltype, conname FROM pg_constraint as con, pg_class as cl1, pg_class as cl2, ' \ - 'pg_attribute as att1, pg_attribute as att2 ' \ - 'WHERE con.conrelid = cl1.oid ' \ - 'AND cl1.relname = %s ' \ - 'AND con.confrelid = cl2.oid ' \ - 'AND cl2.relname = %s ' \ - 'AND array_lower(con.conkey, 1) = 1 ' \ - 'AND con.conkey[1] = att1.attnum ' \ - 'AND att1.attrelid = cl1.oid ' \ - 'AND att1.attname = %s ' \ - 'AND array_lower(con.confkey, 1) = 1 ' \ - 'AND con.confkey[1] = att2.attnum ' \ - 'AND att2.attrelid = cl2.oid ' \ - 'AND att2.attname = %s ' \ - 'AND con.contype = \'f\'', (self._table, ref, k, 'id')) + cr.execute('SELECT confdeltype, conname FROM pg_constraint as con, pg_class as cl1, pg_class as cl2, ' + 'pg_attribute as att1, pg_attribute as att2 ' + 'WHERE con.conrelid = cl1.oid ' + 'AND cl1.relname = %s ' + 'AND con.confrelid = cl2.oid ' + 'AND cl2.relname = %s ' + 'AND array_lower(con.conkey, 1) = 1 ' + 'AND con.conkey[1] = att1.attnum ' + 'AND att1.attrelid = cl1.oid ' + 'AND att1.attname = %s ' + 'AND array_lower(con.confkey, 1) = 1 ' + 'AND con.confkey[1] = att2.attnum ' + 'AND att2.attrelid = cl2.oid ' + 'AND att2.attname = %s ' + "AND con.contype = 'f'", (self._table, ref, k, 'id')) res = cr.dictfetchall() if res: confdeltype = { @@ -1592,6 +1592,8 @@ class orm(orm_template): else: print "ERROR" for f,k in todo_update_store: + ss = self._columns[k]._symbol_set + update_query = 'UPDATE "%s" SET "%s"=%s WHERE id=%%s' % (self._table, k, ss[0]) cr.execute('select id from '+self._table) ids_lst = map(lambda x: x[0], cr.fetchall()) while ids_lst: @@ -1602,19 +1604,21 @@ class orm(orm_template): if f._multi: val = val[k] if (val<>False) or (type(val)<>bool): - cr.execute("UPDATE \"%s\" SET \"%s\"='%s' where id=%d"% (self._table, k, val, key)) + #cr.execute("UPDATE \"%s\" SET \"%s\"='%s' where id=%d"% (self._table, k, val, key)) + cr.execute(update_query, (ss[1](val), key)) #else: # cr.execute("UPDATE \"%s\" SET \"%s\"=NULL where id=%d"% (self._table, k, key)) else: - cr.execute("SELECT relname FROM pg_class WHERE relkind in ('r','v') AND relname='%s'" % self._table) + cr.execute("SELECT relname FROM pg_class WHERE relkind in ('r','v') AND relname=%s", (self._table,)) create = not bool(cr.fetchone()) for (key, con, _) in self._sql_constraints: - cr.execute("SELECT conname FROM pg_constraint where conname='%s_%s'" % (self._table, key)) + conname = '%s_%s' % (self._table, key) + cr.execute("SELECT conname FROM pg_constraint where conname=%s", (conname,)) if not cr.dictfetchall(): try: - cr.execute('alter table \"%s\" add constraint \"%s_%s\" %s' % (self._table, self._table, key, con,)) + cr.execute('alter table "%s" add constraint "%s_%s" %s' % (self._table, self._table, key, con,)) cr.commit() except: logger.notifyChannel('init', netsvc.LOG_WARNING, 'unable to add \'%s\' constraint on table %s !\n If you want to have it, you should update the records and execute manually:\nALTER table %s ADD CONSTRAINT %s_%s %s' % (con, self._table, self._table, self._table, key, con,)) @@ -1836,7 +1840,6 @@ class orm(orm_template): if isinstance(self._columns[f], fields.binary) and context.get('bin_size', False): return "length(%s) as %s" % (f,f) return '"%s"' % (f,) - #fields_pre2 = map(lambda x: (x in ('create_date', 'write_date')) and ('date_trunc(\'second\', '+x+') as '+x) or '"'+x+'"', fields_pre) fields_pre2 = map(convert_field, fields_pre) for i in range(0, len(ids), cr.IN_MAX): sub_ids = ids[i:i+cr.IN_MAX] @@ -1888,7 +1891,7 @@ class orm(orm_template): # to get the _symbol_get in each occurence for r in res: for f in fields_post: - r[f] = self.columns[f]._symbol_get(r[f]) + r[f] = self._columns[f]._symbol_get(r[f]) ids = map(lambda x: x['id'], res) # all non inherited fields for which the attribute whose name is in load is False @@ -2022,7 +2025,7 @@ class orm(orm_template): for i in range(0, len(ids), cr.IN_MAX): sub_ids = ids[i:i+cr.IN_MAX] - str_d = string.join(('%d',)*len(sub_ids), ',') + str_d = string.join(('%s',)*len(sub_ids), ',') if d1: cr.execute('SELECT id FROM "'+self._table+'" ' \ 'WHERE id IN ('+str_d+')'+d1, sub_ids+d2) @@ -2139,7 +2142,7 @@ class orm(orm_template): % (vals[field], field)) if self._log_access: - upd0.append('write_uid=%d') + upd0.append('write_uid=%s') upd0.append('write_date=now()') upd1.append(user) @@ -2205,14 +2208,14 @@ class orm(orm_template): if self.pool._init: self.pool._init_parent[self._name]=True else: - cr.execute('select parent_left,parent_right from '+self._table+' where id=%d', (vals[self._parent_name],)) + cr.execute('select parent_left,parent_right from '+self._table+' where id=%s', (vals[self._parent_name],)) res = cr.fetchone() if res: pleft,pright = res else: cr.execute('select max(parent_right),max(parent_right)+1 from '+self._table) pleft,pright = cr.fetchone() - cr.execute('select parent_left,parent_right,id from '+self._table+' where id in ('+','.join(map(lambda x:'%d',ids))+')', ids) + cr.execute('select parent_left,parent_right,id from '+self._table+' where id in ('+','.join(map(lambda x:'%s',ids))+')', ids) dest = pleft + 1 for cleft,cright,cid in cr.fetchall(): if cleft > pleft: @@ -2232,17 +2235,17 @@ class orm(orm_template): cr.execute('UPDATE '+self._table+''' SET parent_left = CASE - WHEN parent_left BETWEEN %d AND %d THEN parent_left + %d - WHEN parent_left BETWEEN %d AND %d THEN parent_left + %d + WHEN parent_left BETWEEN %s AND %s THEN parent_left + %s + WHEN parent_left BETWEEN %s AND %s THEN parent_left + %s ELSE parent_left END, parent_right = CASE - WHEN parent_right BETWEEN %d AND %d THEN parent_right + %d - WHEN parent_right BETWEEN %d AND %d THEN parent_right + %d + WHEN parent_right BETWEEN %s AND %s THEN parent_right + %s + WHEN parent_right BETWEEN %s AND %s THEN parent_right + %s ELSE parent_right END WHERE - parent_left<%d OR parent_right>%d; + parent_left<%s OR parent_right>%s; ''', (leftbound,rightbound,cwidth,cleft,cright,treeshift,leftbound,rightbound, cwidth,cleft,cright,treeshift,leftrange,rightrange)) @@ -2313,7 +2316,7 @@ class orm(orm_template): for table in tocreate: id = self.pool.get(table).create(cr, user, tocreate[table]) upd0 += ','+self._inherits[table] - upd1 += ',%d' + upd1 += ',%s' upd2.append(id) for field in vals: @@ -2343,7 +2346,7 @@ class orm(orm_template): % (vals[field], field)) if self._log_access: upd0 += ',create_uid,create_date' - upd1 += ',%d,now()' + upd1 += ',%s,now()' upd2.append(user) cr.execute('insert into "'+self._table+'" (id'+upd0+") values ("+str(id_new)+upd1+')', tuple(upd2)) upd_todo.sort(lambda x, y: self._columns[x].priority-self._columns[y].priority) @@ -2358,14 +2361,14 @@ class orm(orm_template): else: parent = vals.get(self._parent_name, False) if parent: - cr.execute('select parent_left from '+self._table+' where id=%d', (parent,)) + cr.execute('select parent_left from '+self._table+' where id=%s', (parent,)) pleft = cr.fetchone()[0] else: cr.execute('select max(parent_right) from '+self._table) pleft = cr.fetchone()[0] or 0 - cr.execute('update '+self._table+' set parent_left=parent_left+2 where parent_left>%d', (pleft,)) - cr.execute('update '+self._table+' set parent_right=parent_right+2 where parent_right>%d', (pleft,)) - cr.execute('update '+self._table+' set parent_left=%d,parent_right=%d where id=%d', (pleft+1,pleft+2,id_new)) + cr.execute('update '+self._table+' set parent_left=parent_left+2 where parent_left>%s', (pleft,)) + cr.execute('update '+self._table+' set parent_right=parent_right+2 where parent_right>%s', (pleft,)) + cr.execute('update '+self._table+' set parent_left=%s,parent_right=%s where id=%s', (pleft+1,pleft+2,id_new)) wf_service = netsvc.LocalService("workflow") wf_service.trg_create(user, self._name, id_new, cr) @@ -2394,7 +2397,7 @@ class orm(orm_template): upd1.append(self._columns[field]._symbol_set[1](value)) upd1.append(id) cr.execute('update "' + self._table + '" set ' + \ - string.join(upd0, ',') + ' where id = %d', upd1) + string.join(upd0, ',') + ' where id = %s', upd1) return True # @@ -2492,7 +2495,7 @@ class orm(orm_template): return [] if isinstance(ids, (int, long)): ids = [ids] - return [(r['id'], str(r[self._rec_name])) for r in self.read(cr, user, ids, + return [(r['id'], tools.ustr(r[self._rec_name])) for r in self.read(cr, user, ids, [self._rec_name], context, load='_classic_write')] def name_search(self, cr, user, name='', args=None, operator='ilike', context=None, limit=None): diff --git a/bin/tools/convert.py b/bin/tools/convert.py index ee7c1c53ee8..b063c9ebabe 100644 --- a/bin/tools/convert.py +++ b/bin/tools/convert.py @@ -474,7 +474,7 @@ form: module.record_id""" % (xml_id,) pid = False for idx, menu_elem in enumerate(m_l): if pid: - cr.execute('select id from ir_ui_menu where parent_id=%d and name=%s', (pid, menu_elem)) + cr.execute('select id from ir_ui_menu where parent_id=%s and name=%s', (pid, menu_elem)) else: cr.execute('select id from ir_ui_menu where parent_id is null and name=%s', (menu_elem,)) res = cr.fetchone() @@ -513,15 +513,15 @@ form: module.record_id""" % (xml_id,) values['icon'] = icons.get(a_type,'STOCK_NEW') if a_type=='act_window': a_id = self.id_get(cr, 'ir.actions.%s'% a_type, a_action) - cr.execute('select view_type,view_mode,name,view_id,target from ir_act_window where id=%d', (int(a_id),)) + cr.execute('select view_type,view_mode,name,view_id,target from ir_act_window where id=%s', (int(a_id),)) rrres = cr.fetchone() assert rrres, "No window action defined for this id %s !\n" \ "Verify that this is a window action or add a type argument." % (a_action,) action_type,action_mode,action_name,view_id,target = rrres if view_id: - cr.execute('SELECT type FROM ir_ui_view WHERE id=%d', (int(view_id),)) + cr.execute('SELECT type FROM ir_ui_view WHERE id=%s', (int(view_id),)) action_mode, = cr.fetchone() - cr.execute('SELECT view_mode FROM ir_act_window_view WHERE act_window_id=%d ORDER BY sequence LIMIT 1', (int(a_id),)) + cr.execute('SELECT view_mode FROM ir_act_window_view WHERE act_window_id=%s ORDER BY sequence LIMIT 1', (int(a_id),)) if cr.rowcount: action_mode, = cr.fetchone() if action_type=='tree': @@ -538,7 +538,7 @@ form: module.record_id""" % (xml_id,) values['name'] = action_name elif a_type=='wizard': a_id = self.id_get(cr, 'ir.actions.%s'% a_type, a_action) - cr.execute('select name from ir_act_wizard where id=%d', (int(a_id),)) + cr.execute('select name from ir_act_wizard where id=%s', (int(a_id),)) resw = cr.fetchone() if (not values.get('name', False)) and resw: values['name'] = resw[0] @@ -819,7 +819,7 @@ def convert_csv_import(cr, module, fname, csvcontent, idref=None, mode='init', if (not line) or not reduce(lambda x,y: x or y, line) : continue try: - datas.append( map(lambda x:x.decode('utf8').encode('utf8'), line)) + datas.append(map(lambda x: misc.ustr(x), line)) except: print "ERROR while importing the line: ", line pool.get(model).import_data(cr, uid, fields, datas,mode, module,noupdate,filename=fname_partial) diff --git a/bin/tools/misc.py b/bin/tools/misc.py index 212501a8703..0466de4ad62 100644 --- a/bin/tools/misc.py +++ b/bin/tools/misc.py @@ -68,7 +68,7 @@ def init_db(cr): if p_id is not None: cr.execute('select id \ from ir_module_category \ - where name=%s and parent_id=%d', (categs[0], p_id)) + where name=%s and parent_id=%s', (categs[0], p_id)) else: cr.execute('select id \ from ir_module_category \ @@ -79,7 +79,7 @@ def init_db(cr): c_id = cr.fetchone()[0] cr.execute('insert into ir_module_category \ (id, name, parent_id) \ - values (%d, %s, %d)', (c_id, categs[0], p_id)) + values (%s, %s, %s)', (c_id, categs[0], p_id)) else: c_id = c_id[0] p_id = c_id @@ -99,7 +99,7 @@ def init_db(cr): cr.execute('insert into ir_module_module \ (id, author, latest_version, website, name, shortdesc, description, \ category_id, state) \ - values (%d, %s, %s, %s, %s, %s, %s, %d, %s)', ( + values (%s, %s, %s, %s, %s, %s, %s, %s, %s)', ( id, info.get('author', ''), release.major_version + '.' + info.get('version', ''), info.get('website', ''), i, info.get('name', False), @@ -580,6 +580,28 @@ class cache(object): def to_xml(s): return s.replace('&','&').replace('<','<').replace('>','>') +def ustr(value): + """This method is similar to the builtin `str` method, except + it will return Unicode string. + + @param value: the value to convert + + @rtype: unicode + @return: unicode string + """ + + if isinstance(value, unicode): + return value + + if hasattr(value, '__unicode__'): + return unicode(value) + + if not isinstance(value, str): + value = str(value) + + return unicode(value, 'utf-8') + + def get_languages(): languages={ 'bg_BG': u'Bulgarian / български', @@ -630,7 +652,7 @@ def get_user_companies(cr, user): res=[x[0] for x in cr.fetchall()] res.extend(_get_company_children(cr, res)) return res - cr.execute('SELECT comp.id FROM res_company AS comp, res_users AS u WHERE u.id = %d AND comp.id = u.company_id' % (user,)) + cr.execute('SELECT comp.id FROM res_company AS comp, res_users AS u WHERE u.id = %s AND comp.id = u.company_id' % (user,)) compids=[cr.fetchone()[0]] compids.extend(_get_company_children(cr, compids)) return compids From a0b7a8f4e6b9da9689a423f3de30e74ea7892ece Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Tue, 9 Dec 2008 15:10:34 +0100 Subject: [PATCH 029/137] modifs bzr revid: fp@tinyerp.com-20081209141034-cj0f9clfgkr1eorz --- bin/osv/orm.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index c9c813da720..165bc86e126 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -308,12 +308,16 @@ class orm_template(object): cr.execute('SELECT nextval(%s)', ('ir_model_id_seq',)) model_id = cr.fetchone()[0] cr.execute("INSERT INTO ir_model (id,model, name, info,state) VALUES (%s, %s, %s, %s,%s)", (model_id, self._name, self._description, self.__doc__, 'base')) - if 'module' in context: - cr.execute("INSERT INTO ir_model_data (name,date_init,date_update,module,model,res_id) VALUES (%s, now(), now(), %s, %s, %s)", \ - ('model_'+self._name.replace('.','_'), context['module'], 'ir.model', model_id) - ) else: model_id = cr.fetchone()[0] + if 'module' in context: + name_id = 'model_'+self._name.replace('.','_') + cr.execute('select * from ir_model_data where name=%s and res_id=%s', (name_id,model_id)) + if not cr.rowcount: + cr.execute("INSERT INTO ir_model_data (name,date_init,date_update,module,model,res_id) VALUES (%s, now(), now(), %s, %s, %s)", \ + (name_id, context['module'], 'ir.model', model_id) + ) + cr.commit() cr.execute("SELECT * FROM ir_model_fields WHERE model=%s", (self._name,)) From 887a992d587bce6cf7487a0b22460d55c7bdc3df Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Tue, 9 Dec 2008 15:31:53 +0100 Subject: [PATCH 030/137] improvement bzr revid: fp@tinyerp.com-20081209143153-7t18385iv9bbwasn --- bin/addons/__init__.py | 16 +++++++++++++++- bin/addons/base/module/module.py | 4 ++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/bin/addons/__init__.py b/bin/addons/__init__.py index 4eeed2e23c6..2ac9d6ed513 100644 --- a/bin/addons/__init__.py +++ b/bin/addons/__init__.py @@ -442,6 +442,18 @@ def load_module_graph(cr, graph, status=None, **kwargs): migrations = MigrationManager(cr, graph) + # only if update + register_class('base') + pool.instanciate('base', cr) + modobj = pool.get('ir.module.module') + modobj.update_list(cr, 1) + + mids = modobj.search(cr, 1, [('state','=','installed')]) + for m in modobj.browse(cr, 1, mids): + for dep in m.dependencies_id: + if dep.state=='uninstalled': + modobj.button_install(cr, 1, [m.id]) + for package in graph: status['progress'] = (float(statusi)+0.1)/len(graph) m = package.name @@ -493,8 +505,10 @@ def load_module_graph(cr, graph, status=None, **kwargs): cr.execute("update ir_module_module set state='installed', latest_version=%s where id=%d", (ver, mid,)) cr.commit() - # Update translations for all installed languages + # Set new modules and dependencies modobj = pool.get('ir.module.module') + + # Update translations for all installed languages if modobj: modobj.update_translations(cr, 1, [mid], None) cr.commit() diff --git a/bin/addons/base/module/module.py b/bin/addons/base/module/module.py index a6767cd6c52..7fe32ab6a73 100644 --- a/bin/addons/base/module/module.py +++ b/bin/addons/base/module/module.py @@ -347,8 +347,8 @@ class module(osv.osv): self._update_dependencies(cr, uid, id, terp.get('depends', [])) self._update_category(cr, uid, id, terp.get('category', 'Uncategorized')) - import socket - socket.setdefaulttimeout(10) + #import socket + #socket.setdefaulttimeout(10) for repository in robj.browse(cr, uid, robj.search(cr, uid, [])): try: index_page = urllib.urlopen(repository.url).read() From 549458e0534cf77e53230462a57d21d6cbfc962b Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Tue, 9 Dec 2008 15:34:26 +0100 Subject: [PATCH 031/137] improve bzr revid: fp@tinyerp.com-20081209143426-8hp2khrcdevqcdqs --- bin/addons/base/module/module.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/bin/addons/base/module/module.py b/bin/addons/base/module/module.py index 7fe32ab6a73..0cb090c2bc7 100644 --- a/bin/addons/base/module/module.py +++ b/bin/addons/base/module/module.py @@ -325,14 +325,14 @@ class module(osv.osv): if not terp or not terp.get('installable', True): continue - if not os.path.isfile( mod_path ): - import imp - path = imp.find_module(mod_name, [addons.ad, addons._ad]) - imp.load_module(name, *path) - else: - import zipimport - zimp = zipimport.zipimporter(mod_path) - zimp.load_module(mod_name) + #if not os.path.isfile( mod_path ): + # import imp + # path = imp.find_module(mod_name, [addons.ad, addons._ad]) + # imp.load_module(name, *path) + #else: + # import zipimport + # zimp = zipimport.zipimporter(mod_path) + # zimp.load_module(mod_name) id = self.create(cr, uid, { 'name': mod_name, 'state': 'uninstalled', From 6b47dd274aa70dd07521b3ce848f49699de98428 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Tue, 9 Dec 2008 15:37:20 +0100 Subject: [PATCH 032/137] improve bzr revid: fp@tinyerp.com-20081209143720-crwf3n3esq54400n --- bin/addons/__init__.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/bin/addons/__init__.py b/bin/addons/__init__.py index 2ac9d6ed513..2163e905178 100644 --- a/bin/addons/__init__.py +++ b/bin/addons/__init__.py @@ -424,6 +424,13 @@ def load_module_graph(cr, graph, status=None, **kwargs): statusi = 0 pool = pooler.get_pool(cr.dbname) + # only if update + register_class('base') + pool.instanciate('base', cr) + modobj = pool.get('ir.module.module') + modobj.update_list(cr, 1) + + # update the graph with values from the database (if exist) ## First, we set the default values for each package in graph additional_data = dict.fromkeys([p.name for p in graph], {'id': 0, 'state': 'uninstalled', 'dbdemo': False, 'latest_version': None}) @@ -442,12 +449,6 @@ def load_module_graph(cr, graph, status=None, **kwargs): migrations = MigrationManager(cr, graph) - # only if update - register_class('base') - pool.instanciate('base', cr) - modobj = pool.get('ir.module.module') - modobj.update_list(cr, 1) - mids = modobj.search(cr, 1, [('state','=','installed')]) for m in modobj.browse(cr, 1, mids): for dep in m.dependencies_id: From a357aa85e58859855761eae990f62e8600204010 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Tue, 9 Dec 2008 21:37:54 +0100 Subject: [PATCH 033/137] bugfix bzr revid: fp@tinyerp.com-20081209203754-2xk5qcy0vivsjy4f --- bin/addons/__init__.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/bin/addons/__init__.py b/bin/addons/__init__.py index 2163e905178..7aa8a884f44 100644 --- a/bin/addons/__init__.py +++ b/bin/addons/__init__.py @@ -424,12 +424,6 @@ def load_module_graph(cr, graph, status=None, **kwargs): statusi = 0 pool = pooler.get_pool(cr.dbname) - # only if update - register_class('base') - pool.instanciate('base', cr) - modobj = pool.get('ir.module.module') - modobj.update_list(cr, 1) - # update the graph with values from the database (if exist) ## First, we set the default values for each package in graph @@ -449,12 +443,6 @@ def load_module_graph(cr, graph, status=None, **kwargs): migrations = MigrationManager(cr, graph) - mids = modobj.search(cr, 1, [('state','=','installed')]) - for m in modobj.browse(cr, 1, mids): - for dep in m.dependencies_id: - if dep.state=='uninstalled': - modobj.button_install(cr, 1, [m.id]) - for package in graph: status['progress'] = (float(statusi)+0.1)/len(graph) m = package.name @@ -538,11 +526,23 @@ def load_modules(db, force_demo=False, status=None, update_module=False): force = [] if force_demo: force.append('demo') + pool = pooler.get_pool(cr.dbname) if update_module: for module in tools.config['init']: - # FIXME lp:304807 cr.execute('update ir_module_module set state=%s where state=%s and name=%s', ('to install', 'uninstalled', module)) cr.commit() + + register_class('base') + pool.instanciate('base', cr) + modobj = pool.get('ir.module.module') + modobj.update_list(cr, 1) + + mids = modobj.search(cr, 1, [('state','in',('installed','to install'))]) + for m in modobj.browse(cr, 1, mids): + for dep in m.dependencies_id: + if dep.state=='uninstalled': + modobj.button_install(cr, 1, [m.id]) + cr.execute("select name from ir_module_module where state in ('installed', 'to install', 'to upgrade','to remove')") else: cr.execute("select name from ir_module_module where state in ('installed', 'to upgrade', 'to remove')") From f500ecff15296379a6970e6b1eab6c67c3c21dd3 Mon Sep 17 00:00:00 2001 From: Jay Vora Date: Wed, 10 Dec 2008 19:05:06 +0530 Subject: [PATCH 034/137] Reports: FormatLang() corrected - Reports will behave acc. to Language(res.lang),not locale. bzr revid: jvo@tinyerp.com-20081210133506-w9h48mu7qum7ok2g --- bin/addons/base/res/res_lang.py | 135 +++++++++++++++++++++++++- bin/addons/base/res/res_lang_view.xml | 28 ++++++ bin/report/report_sxw.py | 76 ++++++++++----- 3 files changed, 214 insertions(+), 25 deletions(-) diff --git a/bin/addons/base/res/res_lang.py b/bin/addons/base/res/res_lang.py index bdf8c25d283..c90c02e3b98 100644 --- a/bin/addons/base/res/res_lang.py +++ b/bin/addons/base/res/res_lang.py @@ -1,7 +1,7 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# OpenERP, Open Source Management Solution +# OpenERP, Open Source Management Solution # Copyright (C) 2004-2008 Tiny SPRL (). All Rights Reserved # $Id$ # @@ -21,24 +21,153 @@ ############################################################################## from osv import fields, osv +from locale import localeconv class lang(osv.osv): _name = "res.lang" + _description = "Languages" + + def _get_default_date_format(self,cursor,user,context={}): + return '%Y-%m-%d' + + def _get_default_time_format(self,cursor,user,context={}): + return '%H:%M:%S' + _columns = { 'name': fields.char('Name', size=64, required=True), 'code': fields.char('Code', size=5, required=True), 'translatable': fields.boolean('Translatable'), 'active': fields.boolean('Active'), - 'direction': fields.selection([('ltr', 'Left-to-right'), ('rtl', 'Right-to-left')], 'Direction',resuired=True), + 'direction': fields.selection([('ltr', 'Left-to-Right'), ('rtl', 'Right-to-Left')], 'Direction',required=True), + 'date_format':fields.char('Date Format',size=64,required=True), + 'time_format':fields.char('Time Format',size=64,required=True), + 'grouping':fields.char('Separator Format',size=64,required=True,help="The Separator Format should be like [,n] where 0 < n :starting from Unit digit.-1 will end the separation. e.g. [3,2,-1] will represent 106500 to be 1,06,500;[1,2,-1] will represent it to be 106,50,0;[3] will represent it as 106,500. Provided ',' as the thousand separator in each case."), + 'decimal_point':fields.char('Decimal Separator', size=64,required=True), + 'thousands_sep':fields.char('Thousands Separator',size=64), + 'legend':fields.text('Legends for Date and Time Formats',readonly=True), } _defaults = { 'active': lambda *a: 1, 'translatable': lambda *a: 0, 'direction': lambda *a: 'ltr', + 'date_format':_get_default_date_format, + 'time_format':_get_default_time_format, + 'grouping':lambda *a: '[]', + 'decimal_point':lambda *a: '.', + 'thousands_sep':lambda *a: ',', + 'legend': lambda *a: '%a - Abbreviated weekday name.\ +\n%A - Full weekday name.\ +\n%b - Abbreviated month name.\ +\n%B - Full month name. \ +\n%c - Appropriate date and time representation.\ +\n%d - Day of the month as a decimal number [01,31].\ +\n%H - Hour (24-hour clock) as a decimal number [00,23].\ +\n%I - Hour (12-hour clock) as a decimal number [01,12].\ +\n%j - Day of the year as a decimal number [001,366].\ +\n%m - Month as a decimal number [01,12].\ +\n%M - Minute as a decimal number [00,59].\ +\n%p - Equivalent of either AM or PM.\ +\n%S - Second as a decimal number [00,61].\ +\n%U - Week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Sunday are considered to be in week 0.\ +\n%w - Weekday as a decimal number [0(Sunday),6].\ +\n%W - Week number of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Monday are considered to be in week 0.\ +\n%x - Appropriate date representation.\ +\n%X - Appropriate time representation.\ +\n%y - Year without century as a decimal number [00,99].\ +\n%Y - Year with century as a decimal number.\ +\n ==========================================\ +\n\nExamples:\ +\n1. %c ==> Fri Dec 5 18:25:20 2008\ +\n2. %a ,%A ==> Fri, Friday\ +\n3. %x ,%X ==> 12/05/08, 18:25:20\ +\n4. %b, %B ==> Dec, December\ +\n5. %y, %Y ==> 08, 2008\ +\n6. %d, %m ==> 05, 12\ +\n7. %H:%M:%S ==> 18:25:20\ +\n8. %I:%M:%S %p ==> 06:25:20 PM\ +\n9. %j ==> 340\ +\n10. %S ==> 20\ +\n11. %U or %W ==> 48 (49th week)\ +\n12. %w ==> 5 ( Friday is the 6th day)', } + + def _group(self,cr,uid,ids,s, monetary=False): + conv = localeconv() + + lang_obj=self.browse(cr,uid,ids[0]) + thousands_sep = lang_obj.thousands_sep or conv[monetary and 'mon_thousands_sep' or 'thousands_sep'] + + grouping = eval(lang_obj.grouping) + + if not grouping: + return (s, 0) + result = "" + seps = 0 + spaces = "" + if s[-1] == ' ': + sp = s.find(' ') + spaces = s[sp:] + s = s[:sp] + while s and grouping: + # if grouping is -1, we are done + if grouping[0] == -1: + break + # 0: re-use last group ad infinitum + elif grouping[0] != 0: + #process last group + group = grouping[0] + grouping = grouping[1:] + if result: + result = s[-group:] + thousands_sep + result + seps += 1 + else: + result = s[-group:] + s = s[:-group] + if s and s[-1] not in "0123456789": + # the leading string is only spaces and signs + return s + result + spaces, seps + if not result: + return s + spaces, seps + if s: + result = s + thousands_sep + result + seps += 1 + return result + spaces, seps + + def format(self,cr,uid,ids,percent, value, grouping=False, monetary=False): + """ Format() will return the language-specific output for float values""" + + if percent[0] != '%': + raise ValueError("format() must be given exactly one %char format specifier") + + lang_obj=self.browse(cr,uid,ids[0]) + + formatted = percent % value + # floats and decimal ints need special action! + if percent[-1] in 'eEfFgG': + seps = 0 + parts = formatted.split('.') + + if grouping: + parts[0], seps = self._group(cr,uid,ids,parts[0], monetary=monetary) + + decimal_point=lang_obj.decimal_point + formatted = decimal_point.join(parts) + while seps: + sp = formatted.find(' ') + if sp == -1: break + formatted = formatted[:sp] + formatted[sp+1:] + seps -= 1 + elif percent[-1] in 'diu': + if grouping: + formatted = self._group(cr,uid,ids,formatted, monetary=monetary)[0] + + return formatted + +# import re, operator +# _percent_re = re.compile(r'%(?:\((?P.*?)\))?' +# r'(?P[-#0-9 +*.hlL]*?)[eEfFgGdiouxXcrs%]') lang() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: - diff --git a/bin/addons/base/res/res_lang_view.xml b/bin/addons/base/res/res_lang_view.xml index 3c6f45f0ad4..428edcdad44 100644 --- a/bin/addons/base/res/res_lang_view.xml +++ b/bin/addons/base/res/res_lang_view.xml @@ -15,6 +15,34 @@ + + res.lang.form + res.lang + form + +
+ + + + + + + + + + + + + + + + + + + + +
+ Languages res.lang diff --git a/bin/report/report_sxw.py b/bin/report/report_sxw.py index a776e4ee6c3..ddf0393e910 100644 --- a/bin/report/report_sxw.py +++ b/bin/report/report_sxw.py @@ -36,6 +36,7 @@ import copy import StringIO import zipfile import os +import mx.DateTime DT_FORMAT = '%Y-%m-%d' DHM_FORMAT = '%Y-%m-%d %H:%M:%S' @@ -255,6 +256,7 @@ class rml_parse(object): 'format': self.format, 'formatLang': self.formatLang, 'logo' : user.company_id.logo, + 'lang' : user.company_id.partner_id.lang, } self.localcontext.update(context) self.rml_header = user.company_id.rml_header @@ -333,31 +335,61 @@ class rml_parse(object): else: obj._cache[table][id] = {'id': id} - def formatLang(self, value, digit=2, date=False): + def formatLang(self, value, digits=2, date=False,date_time=False, grouping=True, monetary=False, currency=None): if not value: return '' - lc, encoding = locale.getdefaultlocale() - if not encoding: - encoding = 'UTF-8' - if encoding == 'utf': - encoding = 'UTF-8' - if encoding == 'cp1252': - encoding= '1252' + + pool_lang=self.pool.get('res.lang') lang = self.localcontext.get('lang', 'en_US') or 'en_US' - try: - if os.name == 'nt': - locale.setlocale(locale.LC_ALL, _LOCALE2WIN32.get(lang, lang) + '.' + encoding) + lang_obj = pool_lang.browse(self.cr,self.uid,pool_lang.search(self.cr,self.uid,[('code','=',lang)])[0]) + + if date or date_time: + date_format = lang_obj.date_format + if date_time: + date_format = lang_obj.date_format + " " + lang_obj.time_format + + if not isinstance(value, time.struct_time): + # assume string, parse it + if len(str(value)) == 10: + # length of date like 2001-01-01 is ten + # assume format '%Y-%m-%d' + date = mx.DateTime.strptime(str(value),DT_FORMAT) + else: + # assume format '%Y-%m-%d %H:%M:%S' + value = str(value)[:19] + date = mx.DateTime.strptime(str(value),DHM_FORMAT) else: - locale.setlocale(locale.LC_ALL, lang + '.' + encoding) - except Exception: - netsvc.Logger().notifyChannel('report', netsvc.LOG_WARNING, - 'report %s: unable to set locale "%s"' % (self.name, - self.localcontext.get('lang', 'en_US') or 'en_US')) - if date: - date = time.strptime(value, DT_FORMAT) - return time.strftime(locale.nl_langinfo(locale.D_FMT).replace('%y', '%Y'), - date) - return locale.format('%.' + str(digit) + 'f', value, True) + date = mx.DateTime.DateTime(*(value.timetuple()[:6])) + + return date.strftime(date_format) + + return lang_obj.format('%.' + str(digits) + 'f', value, grouping=grouping, monetary=monetary) + +# def formatLang(self, value, digit=2, date=False): +# if not value: +# return '' +# lc, encoding = locale.getdefaultlocale() +# if not encoding: +# encoding = 'UTF-8' +# if encoding == 'utf': +# encoding = 'UTF-8' +# if encoding == 'cp1252': +# encoding= '1252' +# lang = self.localcontext.get('lang', 'en_US') or 'en_US' +# try: +# if os.name == 'nt': +# locale.setlocale(locale.LC_ALL, _LOCALE2WIN32.get(lang, lang) + '.' + encoding) +# else: +# locale.setlocale(locale.LC_ALL, lang + '.' + encoding) +# except Exception: +# netsvc.Logger().notifyChannel('report', netsvc.LOG_WARNING, +# 'report %s: unable to set locale "%s"' % (self.name, +# self.localcontext.get('lang', 'en_US') or 'en_US')) +# if date: +# date = time.strptime(value, DT_FORMAT) +# return time.strftime(locale.nl_langinfo(locale.D_FMT).replace('%y', '%Y'), +# date) +# return locale.format('%.' + str(digit) + 'f', value, True) def repeatIn(self, lst, name, nodes_parent=False): self._node.data = '' @@ -555,7 +587,7 @@ class report_sxw(report_rml): def getObjects(self, cr, uid, ids, context): table_obj = pooler.get_pool(cr.dbname).get(self.table) - return table_obj.browse(cr, uid, ids, list_class=browse_record_list, context=context, fields_process=_fields_process) + return table_obj.browse(cr, uid, ids, list_class=browse_record_list, context=context) def create(self, cr, uid, ids, data, context=None): logo = None From 02663d978045949ba95de5bed40eea043cd7ee6d Mon Sep 17 00:00:00 2001 From: Najlaa Date: Wed, 10 Dec 2008 15:08:56 +0100 Subject: [PATCH 035/137] [IMP] convert varchar to text in database bzr revid: nel@silver-20081210140856-easnep218it0bnqu --- bin/osv/orm.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index 165bc86e126..06fb00c42ee 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -1530,6 +1530,12 @@ class orm(orm_template): cr.execute("UPDATE \"%s\" SET \"%s\"=temp_change_size::VARCHAR(%d)" % (self._table, k, f.size)) cr.execute("ALTER TABLE \"%s\" DROP COLUMN temp_change_size" % (self._table,)) cr.commit() + if f_pg_type == 'varchar' and f._type == 'text': + cr.execute("ALTER TABLE \"%s\" RENAME COLUMN \"%s\" TO temp_change_type" % (self._table, k)) + cr.execute("ALTER TABLE \"%s\" ADD COLUMN \"%s\" text " % (self._table, k)) + cr.execute("UPDATE \"%s\" SET \"%s\"=temp_change_type" % (self._table, k)) + cr.execute("ALTER TABLE \"%s\" DROP COLUMN temp_change_type" % (self._table,)) + cr.commit() if f_pg_type == 'date' and f._type == 'datetime': cr.execute("ALTER TABLE \"%s\" RENAME COLUMN \"%s\" TO temp_change_type" % (self._table, k)) cr.execute("ALTER TABLE \"%s\" ADD COLUMN \"%s\" TIMESTAMP " % (self._table, k)) From 5a836ab2754fa552b68cc5a70a52c50a2c3633da Mon Sep 17 00:00:00 2001 From: Najlaa Date: Wed, 10 Dec 2008 15:11:28 +0100 Subject: [PATCH 036/137] [FIX] correct graph loading when updating database or installing new module from command line lp bug: https://launchpad.net/bugs/304807 fixed bzr revid: nel@silver-20081210141128-oaknnb0rzj68htio --- bin/addons/__init__.py | 44 +++++++++++++++++++++++--------- bin/addons/base/module/module.py | 4 +++ 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/bin/addons/__init__.py b/bin/addons/__init__.py index 7aa8a884f44..f9f1e0196dd 100644 --- a/bin/addons/__init__.py +++ b/bin/addons/__init__.py @@ -527,28 +527,48 @@ def load_modules(db, force_demo=False, status=None, update_module=False): if force_demo: force.append('demo') pool = pooler.get_pool(cr.dbname) + report = tools.assertion_report() if update_module: - for module in tools.config['init']: + basegraph = create_graph(['base'], force) + load_module_graph(cr, basegraph, status, report=report) + + modobj = pool.get('ir.module.module') + modobj.update_list(cr, 1) + + if tools.config['init']: + ids = modobj.search(cr, 1, ['&', ('state', '=', 'uninstalled'), ('name', 'in', tools.config['init'])]) + if ids: + #modobj.write(cr, ids, {'state': 'to install'}) + modobj.button_install(cr, 1, ids) + + ids = modobj.search(cr, 1, ['&', '!', ('name', '=', 'base'), ('state', 'in', ('installed', 'to upgrade'))]) + if ids: + modobj.button_upgrade(cr, 1, ids) + + """ + for module in modobj.browse(cr, uid, modobj.search(crtools.config['init']: cr.execute('update ir_module_module set state=%s where state=%s and name=%s', ('to install', 'uninstalled', module)) cr.commit() - register_class('base') - pool.instanciate('base', cr) - modobj = pool.get('ir.module.module') - modobj.update_list(cr, 1) - - mids = modobj.search(cr, 1, [('state','in',('installed','to install'))]) - for m in modobj.browse(cr, 1, mids): - for dep in m.dependencies_id: - if dep.state=='uninstalled': - modobj.button_install(cr, 1, [m.id]) +, + mids = modobj.search(cr, 1, [('state','in',('installed','to install'))]) + for m in modobj.browse(cr, 1, mids): + for dep in m.dependencies_id: + if dep.state=='uninstalled': + modobj.button_install(cr, 1, [m.id]) + #""" cr.execute("select name from ir_module_module where state in ('installed', 'to install', 'to upgrade','to remove')") else: cr.execute("select name from ir_module_module where state in ('installed', 'to upgrade', 'to remove')") module_list = [name for (name,) in cr.fetchall()] graph = create_graph(module_list, force) - report = tools.assertion_report() + + base = graph['base'] + for kind in ('init', 'demo', 'update'): + if hasattr(base, kind): + delattr(base, kind) + load_module_graph(cr, graph, status, report=report) if report.get_report(): logger.notifyChannel('init', netsvc.LOG_INFO, 'assert: %s' % report) diff --git a/bin/addons/base/module/module.py b/bin/addons/base/module/module.py index 0cb090c2bc7..0e5b976c97c 100644 --- a/bin/addons/base/module/module.py +++ b/bin/addons/base/module/module.py @@ -261,6 +261,7 @@ class module(osv.osv): def button_upgrade(self, cr, uid, ids, context=None): depobj = self.pool.get('ir.module.module.dependency') todo = self.browse(cr, uid, ids, context=context) + to_install = set() i = 0 while i Date: Wed, 10 Dec 2008 15:43:57 +0100 Subject: [PATCH 037/137] [IMP] remove dead code and add comment bzr revid: christophe@tinyerp.com-20081210144357-d4v17cnsjycabexr --- bin/addons/__init__.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/bin/addons/__init__.py b/bin/addons/__init__.py index 983af9d17e9..5f5063792d1 100644 --- a/bin/addons/__init__.py +++ b/bin/addons/__init__.py @@ -538,32 +538,19 @@ def load_modules(db, force_demo=False, status=None, update_module=False): if tools.config['init']: ids = modobj.search(cr, 1, ['&', ('state', '=', 'uninstalled'), ('name', 'in', tools.config['init'])]) if ids: - #modobj.write(cr, ids, {'state': 'to install'}) modobj.button_install(cr, 1, ids) ids = modobj.search(cr, 1, ['&', '!', ('name', '=', 'base'), ('state', 'in', ('installed', 'to upgrade'))]) if ids: modobj.button_upgrade(cr, 1, ids) - """ - for module in modobj.browse(cr, uid, modobj.search(crtools.config['init']: - cr.execute('update ir_module_module set state=%s where state=%s and name=%s', ('to install', 'uninstalled', module)) - cr.commit() - -, - mids = modobj.search(cr, 1, [('state','in',('installed','to install'))]) - for m in modobj.browse(cr, 1, mids): - for dep in m.dependencies_id: - if dep.state=='uninstalled': - modobj.button_install(cr, 1, [m.id]) - #""" - cr.execute("select name from ir_module_module where state in ('installed', 'to install', 'to upgrade','to remove')") else: cr.execute("select name from ir_module_module where state in ('installed', 'to upgrade', 'to remove')") module_list = [name for (name,) in cr.fetchall()] graph = create_graph(module_list, force) + # the 'base' module has already been updated base = graph['base'] for kind in ('init', 'demo', 'update'): if hasattr(base, kind): From 3b41e1a8431b7156bb1d501046cce4cd68a14cbd Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Wed, 10 Dec 2008 16:06:32 +0100 Subject: [PATCH 038/137] [IMP] avoid false warnings by disabling the check of access rules when loading only 'base' module graph bzr revid: christophe@tinyerp.com-20081210150632-7tji0vj1yc05o7h8 --- bin/addons/__init__.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/bin/addons/__init__.py b/bin/addons/__init__.py index 5f5063792d1..8e9932a2cfc 100644 --- a/bin/addons/__init__.py +++ b/bin/addons/__init__.py @@ -414,7 +414,7 @@ class MigrationManager(object): del mod -def load_module_graph(cr, graph, status=None, **kwargs): +def load_module_graph(cr, graph, status=None, check_access_rules=True, **kwargs): # **kwargs is passed directly to convert_xml_import if not status: status={} @@ -507,12 +507,14 @@ def load_module_graph(cr, graph, status=None, **kwargs): statusi+=1 - cr.execute("""select model,name from ir_model where id not in (select model_id from ir_model_access)""") - for (model,name) in cr.fetchall(): - logger.notifyChannel('init', netsvc.LOG_WARNING, 'addon object %s (%s) has no access rules!' % (model,name)) + if check_access_rules: + cr.execute("""select model,name from ir_model where id not in (select model_id from ir_model_access)""") + for (model,name) in cr.fetchall(): + logger.notifyChannel('init', netsvc.LOG_WARNING, 'addon object %s (%s) has no access rules!' % (model,name)) + pool = pooler.get_pool(cr.dbname) - cr.execute('select * from ir_model where state=%s', ('manual',)) + cr.execute('select model from ir_model where state=%s', ('manual',)) for model in cr.dictfetchall(): pool.get('ir.model').instanciate(cr, 1, model['model'], {}) @@ -530,7 +532,7 @@ def load_modules(db, force_demo=False, status=None, update_module=False): report = tools.assertion_report() if update_module: basegraph = create_graph(['base'], force) - load_module_graph(cr, basegraph, status, report=report) + load_module_graph(cr, basegraph, status, check_access_rules=False, report=report) modobj = pool.get('ir.module.module') modobj.update_list(cr, 1) From 2d4a21f9f27d5d299e9a8d1aaf5afd4647acd4ea Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Wed, 10 Dec 2008 22:23:54 +0100 Subject: [PATCH 039/137] [IMP] Change the presentation of the logger bzr revid: stephane@tinyerp.com-20081210212354-zox0dl3v85yo6754 --- bin/netsvc.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/bin/netsvc.py b/bin/netsvc.py index 31832004067..a972fa84484 100644 --- a/bin/netsvc.py +++ b/bin/netsvc.py @@ -204,7 +204,14 @@ def init_logger(): class Logger(object): def notifyChannel(self, name, level, msg): log = logging.getLogger(name) - getattr(log, level)(msg) + level_method = getattr(log, level) + + result = msg.strip().split('\n') + if len(result)>1: + for idx, s in enumerate(result): + level_method('[%02d]: %s' % (idx+1, s,)) + elif result: + level_method(result[0]) init_logger() From b5b1ab39046141fe507b8e5f39a5d23012164134 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Wed, 10 Dec 2008 22:24:23 +0100 Subject: [PATCH 040/137] [IMP] Update the logging of the error in the osv module bzr revid: stephane@tinyerp.com-20081210212423-20zjyagn6etc3rzn --- bin/osv/osv.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bin/osv/osv.py b/bin/osv/osv.py index 9e6d4171c37..32fdfd17e6f 100644 --- a/bin/osv/osv.py +++ b/bin/osv/osv.py @@ -96,8 +96,7 @@ class osv_pool(netsvc.Service): import traceback tb_s = reduce(lambda x, y: x+y, traceback.format_exception( sys.exc_type, sys.exc_value, sys.exc_traceback)) logger = Logger() - for idx, s in enumerate(tb_s.split('\n')): - logger.notifyChannel("web-services", LOG_ERROR, '[%2d]: %s' % (idx, s,)) + logger.notifyChannel('web-services', LOG_ERROR, tb_s) raise def execute(self, db, uid, obj, method, *args, **kw): From 0d07e64e711430b27a95d47a0680a325c4e581aa Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Wed, 10 Dec 2008 22:25:25 +0100 Subject: [PATCH 041/137] [IMP] Remove the print statements bzr revid: stephane@tinyerp.com-20081210212525-lfastpg2wkepfsbt --- bin/tools/translate.py | 1 - bin/workflow/workitem.py | 1 - 2 files changed, 2 deletions(-) diff --git a/bin/tools/translate.py b/bin/tools/translate.py index 3c13c351023..90980fd806c 100644 --- a/bin/tools/translate.py +++ b/bin/tools/translate.py @@ -543,7 +543,6 @@ def trans_load_data(db_name, fileobj, fileformat, lang, strict=False, lang_name= line += 1 # skip empty rows and rows where the translation field (=last fiefd) is empty if (not row) or (not row[-1]): - #print "translate: skip %s" % repr(row) continue # dictionary which holds values for this line of the csv file diff --git a/bin/workflow/workitem.py b/bin/workflow/workitem.py index 6f41bc9602c..ce54dffa1c0 100644 --- a/bin/workflow/workitem.py +++ b/bin/workflow/workitem.py @@ -97,7 +97,6 @@ def _execute(cr, workitem, activity, ident, stack): if workitem['state']=='active': _state_set(cr, workitem, activity, 'complete', ident) if activity['action_id']: - print 'ICI' res2 = wkf_expr.execute_action(cr, ident, workitem, activity) if res2: stack.append(res2) From c7e627bed96d8086f15ac9fa4517f418f2a32fd6 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Wed, 10 Dec 2008 22:26:45 +0100 Subject: [PATCH 042/137] [IMP] Improve the logging bzr revid: stephane@tinyerp.com-20081210212645-01kbn7iprk88g4wn --- bin/tools/convert.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/bin/tools/convert.py b/bin/tools/convert.py index b063c9ebabe..982d9ccdd88 100644 --- a/bin/tools/convert.py +++ b/bin/tools/convert.py @@ -486,7 +486,7 @@ form: module.record_id""" % (xml_id,) try: npid = self.pool.get('ir.model.data')._update_dummy(cr, self.uid, 'ir.ui.menu', self.module, xml_id, idx==len(m_l)-1) except: - print 'Menu Error', self.module, xml_id, idx==len(m_l)-1 + self.logger.notifyChannel('init', netsvc.LOG_ERROR, "addon: %s xml_id: %s" % (self.module, xml_id)) else: # the menuitem does't exist but we are in branch (not a leaf) self.logger.notifyChannel("init", netsvc.LOG_WARNING, 'Warning no ID for submenu %s of menu %s !' % (menu_elem, str(m_l))) @@ -738,7 +738,7 @@ form: module.record_id""" % (xml_id,) raise Exception( "Mismatch xml format: only terp or openerp as root tag" ) if de.nodeName == 'terp': - self.logger.notifyChannel("init", netsvc.LOG_WARNING, "The tag is deprecated, use ") + self.logger.notifyChannel("init", netsvc.LOG_WARNING, "The tag is deprecated, use ") for n in [i for i in de.childNodes if (i.nodeType == i.ELEMENT_NODE and i.nodeName=="data")]: for rec in n.childNodes: @@ -747,7 +747,7 @@ form: module.record_id""" % (xml_id,) try: self._tags[rec.nodeName](self.cr, rec, n) except: - self.logger.notifyChannel("init", netsvc.LOG_INFO, '\n'+rec.toxml()) + self.logger.notifyChannel("init", netsvc.LOG_ERROR, '\n'+rec.toxml()) self.cr.rollback() raise return True @@ -821,7 +821,8 @@ def convert_csv_import(cr, module, fname, csvcontent, idref=None, mode='init', try: datas.append(map(lambda x: misc.ustr(x), line)) except: - print "ERROR while importing the line: ", line + logger = netsvc.Logger() + logger.notifyChannel("init", netsvc.LOG_ERROR, "Can not import the line: %s" % line) pool.get(model).import_data(cr, uid, fields, datas,mode, module,noupdate,filename=fname_partial) if config.get('import_partial'): data = pickle.load(file(config.get('import_partial'))) From 880d0578e013536bfc6224ff13b6825ab9c8c7d0 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Wed, 10 Dec 2008 22:32:29 +0100 Subject: [PATCH 043/137] [IMP] Use the warning level for the pytz library if missing bzr revid: stephane@tinyerp.com-20081210213229-e22ebweqg8a7byvh --- bin/tools/convert.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/tools/convert.py b/bin/tools/convert.py index 982d9ccdd88..887160afe6a 100644 --- a/bin/tools/convert.py +++ b/bin/tools/convert.py @@ -100,7 +100,7 @@ def _eval_xml(self,node, pool, cr, uid, idref, context=None): import pytz except: logger = netsvc.Logger() - logger.notifyChannel("init", netsvc.LOG_INFO, 'could not find pytz library') + logger.notifyChannel("init", netsvc.LOG_WARNING, 'could not find pytz library') class pytzclass(object): all_timezones=[] pytz=pytzclass() From 55ec2ebdd0cf66192c913dd413339fa3460b5714 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Wed, 10 Dec 2008 22:36:04 +0100 Subject: [PATCH 044/137] [IMP] Add the FIXME message bzr revid: stephane@tinyerp.com-20081210213604-wd1thxun1a4bv964 --- bin/tools/misc.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/tools/misc.py b/bin/tools/misc.py index 0466de4ad62..a36fa2408e4 100644 --- a/bin/tools/misc.py +++ b/bin/tools/misc.py @@ -385,6 +385,7 @@ def sms_send(user, password, api_id, text, to): params = urllib.urlencode({'user': user, 'password': password, 'api_id': api_id, 'text': text, 'to':to}) #f = urllib.urlopen("http://api.clickatell.com/http/sendmsg", params) f = urllib.urlopen("http://196.7.150.220/http/sendmsg", params) + # FIXME: Use the logger if there is an error print f.read() return True From b08de4107e19dafd9f9d6c2743744c0f3a1c7f87 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Wed, 10 Dec 2008 22:43:08 +0100 Subject: [PATCH 045/137] [IMP] Use the logger to show the output from the logged function bzr revid: stephane@tinyerp.com-20081210214308-c6l296vkka9o92d3 --- bin/tools/misc.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bin/tools/misc.py b/bin/tools/misc.py index a36fa2408e4..63c7b3631f9 100644 --- a/bin/tools/misc.py +++ b/bin/tools/misc.py @@ -690,6 +690,7 @@ def human_size(sz): return "%0.2f %s" % (s, units[i]) def logged(when): + import netsvc def log(f, res, *args, **kwargs): vector = ['Call -> function: %s' % f] for i, arg in enumerate(args): @@ -697,7 +698,7 @@ def logged(when): for key, value in kwargs.items(): vector.append( ' kwarg %10s: %r' % ( key, value ) ) vector.append( ' result: %r' % res ) - print "\n".join(vector) + netsvc.Logger().notifyChannel('logged', netsvc.LOG_DEBUG, vector) def pre_logged(f): def wrapper(*args, **kwargs): @@ -715,7 +716,7 @@ def logged(when): return res finally: log(f, res, *args, **kwargs) - print " time delta: %s" % (time.time() - now) + netsvc.Logger().notifyChannel('logged', netsvc.LOG_DEBUG, "time delta: %s" % (time.time() - now)) return wrapper try: From a49463c7b4a25a98ba254ef2690995ea41d1c2be Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Wed, 10 Dec 2008 22:43:57 +0100 Subject: [PATCH 046/137] [IMP] Remove the print statement bzr revid: stephane@tinyerp.com-20081210214357-xrdp1k23y5va5o8u --- bin/tools/graph.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/bin/tools/graph.py b/bin/tools/graph.py index 628c886d812..80853cd09ee 100644 --- a/bin/tools/graph.py +++ b/bin/tools/graph.py @@ -759,8 +759,6 @@ if __name__=='__main__': g.process(starting_node) g.scale(radius*3,radius*3, radius, radius) - print g - import Image import ImageDraw img = Image.new("RGB", (800, 600), "#ffffff") From 7d3ab11f9772351190077a91cca2e672daf457d8 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Wed, 10 Dec 2008 22:46:17 +0100 Subject: [PATCH 047/137] [IMP] Remove the unused code bzr revid: stephane@tinyerp.com-20081210214617-359x2kq97k8vpcam --- bin/openerp-server.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/bin/openerp-server.py b/bin/openerp-server.py index f353dc236b9..7c65a923e52 100755 --- a/bin/openerp-server.py +++ b/bin/openerp-server.py @@ -65,8 +65,6 @@ if sys.platform == 'win32': import mx.DateTime mx.DateTime.strptime = lambda x, y: mx.DateTime.mktime(time.strptime(x, y)) -#os.chdir(tools.file_path_root) - #---------------------------------------------------------- # init net service #---------------------------------------------------------- From a1d6019076ddd338c54136d4a5bfa0dcd7e0b8cb Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Wed, 10 Dec 2008 22:48:30 +0100 Subject: [PATCH 048/137] [IMP] Use the logger bzr revid: stephane@tinyerp.com-20081210214830-bzgox1uw469v6e5f --- bin/addons/base/ir/ir_report_custom.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/addons/base/ir/ir_report_custom.py b/bin/addons/base/ir/ir_report_custom.py index 64fbeca83ef..15fd0e0b475 100644 --- a/bin/addons/base/ir/ir_report_custom.py +++ b/bin/addons/base/ir/ir_report_custom.py @@ -25,6 +25,7 @@ from osv.orm import browse_null import ir import report.custom from tools.translate import _ +import netsvc class report_custom(osv.osv): _name = 'ir.report.custom' @@ -187,7 +188,7 @@ class report_custom_fields(osv.osv): } } else: - print _("Warning: using a relation field which uses an unknown object") #TODO use the logger + netsvc.Logger().notifyChannel('web-services', netsvc.LOG_WARNING, _("Using a relation field which uses an unknown object")) return {'required': {next_level_field_name: True}} else: return {'domain': {next_level_field_name: []}} From 424ba1e7cd874d79ffefc453bdef30288c63bf1f Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Wed, 10 Dec 2008 22:55:49 +0100 Subject: [PATCH 049/137] [REF] Remove the unused code and print statement bzr revid: stephane@tinyerp.com-20081210215549-yxxdiz0x4uc6ozkr --- bin/report/interface.py | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/bin/report/interface.py b/bin/report/interface.py index eb82025cd19..8b303e473aa 100644 --- a/bin/report/interface.py +++ b/bin/report/interface.py @@ -77,28 +77,21 @@ class report_rml(report_int): self.xsl = xsl self.bin_datas = {} self.generators = { - 'pdf': self.create_pdf, - 'html': self.create_html, - 'raw': self.create_raw, - 'sxw': self.create_sxw, - } + 'pdf': self.create_pdf, + 'html': self.create_html, + 'raw': self.create_raw, + 'sxw': self.create_sxw, + } def create(self, cr, uid, ids, datas, context): xml = self.create_xml(cr, uid, ids, datas, context) -# file('/tmp/terp.xml','wb+').write(xml) if datas.get('report_type', 'pdf') == 'raw': return xml rml = self.create_rml(cr, xml, uid, context) -# file('/tmp/terp.rml','wb+').write(rml) pool = pooler.get_pool(cr.dbname) ir_actions_report_xml_obj = pool.get('ir.actions.report.xml') - try: - report_xml_ids = ir_actions_report_xml_obj.search(cr, uid, - [('report_name', '=', self.name[7:])], context=context) - self.title = ir_actions_report_xml_obj.browse(cr,uid,report_xml_ids)[0].name - except: - print 'Report not Found !' - self.title = 'Unknown' + report_xml_ids = ir_actions_report_xml_obj.search(cr, uid, [('report_name', '=', self.name[7:])], context=context) + self.title = report_xml_ids and ir_actions_report_xml_obj.browse(cr,uid,report_xml_ids)[0].name or 'OpenERP Report' report_type = datas.get('report_type', 'pdf') create_doc = self.generators[report_type] pdf = create_doc(rml, title=self.title) From 242528a3b0d36e77f205be08c36a458ed1173a26 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Wed, 10 Dec 2008 23:08:00 +0100 Subject: [PATCH 050/137] [IMP] Use the logger bzr revid: stephane@tinyerp.com-20081210220800-pxm9xmkhnrnkvnzx --- bin/osv/orm.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index f623e10471e..920c27da946 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -1462,7 +1462,12 @@ class orm(orm_template): cr.execute('CREATE INDEX "%s_%s_index" ON "%s" ("%s")' % (f._rel, f._id2, f._rel, f._id2)) cr.commit() else: - cr.execute("SELECT c.relname,a.attname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,t.typname,CASE WHEN a.attlen=-1 THEN a.atttypmod-4 ELSE a.attlen END as size FROM pg_class c,pg_attribute a,pg_type t WHERE c.relname=%s AND a.attname=%s AND c.oid=a.attrelid AND a.atttypid=t.oid", (self._table, k)) + cr.execute("SELECT c.relname,a.attname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,t.typname,CASE WHEN a.attlen=-1 THEN a.atttypmod-4 ELSE a.attlen END as size " \ + "FROM pg_class c,pg_attribute a,pg_type t " \ + "WHERE c.relname=%s " \ + "AND a.attname=%s " \ + "AND c.oid=a.attrelid " \ + "AND a.atttypid=t.oid", (self._table, k)) res = cr.dictfetchall() if not res: if not isinstance(f, fields.function) or f.store: @@ -1600,7 +1605,8 @@ class orm(orm_template): cr.execute('ALTER TABLE "' + self._table + '" ADD FOREIGN KEY ("' + k + '") REFERENCES "' + ref + '" ON DELETE ' + f.ondelete) cr.commit() else: - print "ERROR" + logger = netsvc.Logger() + logger.notifyChannel('orm', netsvc.LOG_ERROR, "Programming error !") for f,k in todo_update_store: ss = self._columns[k]._symbol_set update_query = 'UPDATE "%s" SET "%s"=%s WHERE id=%%s' % (self._table, k, ss[0]) From 26a6c764bbb1640d4d33558625917fc8dd879416 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Wed, 10 Dec 2008 23:11:04 +0100 Subject: [PATCH 051/137] [IMP] Use the logger bzr revid: stephane@tinyerp.com-20081210221104-j4gv4f22pxobigzf --- bin/service/web_services.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bin/service/web_services.py b/bin/service/web_services.py index 55ecdf91f04..71821d15fe3 100644 --- a/bin/service/web_services.py +++ b/bin/service/web_services.py @@ -108,13 +108,12 @@ class db(netsvc.Service): traceback.print_exc(file=e_str) traceback_str = e_str.getvalue() e_str.close() - print traceback_str + netsvc.Logger().notifyChannel('web-services', netsvc.LOG_ERROR, 'CREATE DATABASE\n%s' % (traceback_str)) serv.actions[id]['traceback'] = traceback_str if cr: cr.close() logger = netsvc.Logger() - logger.notifyChannel("web-services", netsvc.LOG_INFO, - 'CREATE DB: %s' % (db_name.lower())) + logger.notifyChannel("web-services", netsvc.LOG_INFO, 'CREATE DATABASE: %s' % (db_name.lower())) dbi = DBInitialize() create_thread = threading.Thread(target=dbi, args=(self, id, db_name, demo, lang, user_password)) From 08d926bf8163036be61a08e8fa7ce63f25c8fdf0 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Wed, 10 Dec 2008 23:12:57 +0100 Subject: [PATCH 052/137] [IMP] Remove the print statements bzr revid: stephane@tinyerp.com-20081210221257-apvp2q47f7vrkh7n --- bin/report/print_xml.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/bin/report/print_xml.py b/bin/report/print_xml.py index f5b66d8a88d..796ef6989b6 100644 --- a/bin/report/print_xml.py +++ b/bin/report/print_xml.py @@ -78,17 +78,13 @@ class document(object): fields = field_path.split('.') if not len(fields): - print "WARNING: field name is empty!" return '' value = browser for f in fields: if isinstance(value, list): if len(value)==0: - print "WARNING: empty list found!" return '' -# elif len(value)>1: -# print "WARNING:", len(value), "possibilities for", value[0]._table_name , "picking first..." value = value[0] if isinstance(value, browse_null): return '' @@ -128,12 +124,6 @@ class document(object): # parent = the parent node in the xml data tree we are creating if node.nodeType == node.ELEMENT_NODE: -# print '-'*60 -# print "parse_node", node -# print "parent: ", parent -# print "ids:", ids -# print "model:", model -# print "datas:", datas # convert the attributes of the node to a dictionary @@ -203,9 +193,6 @@ class document(object): el.appendChild(el_txt) elif attrs['type']=='eval': -#TODO: faire ca plus proprement - if isinstance(browser, list): - print "ERROR: EVAL!" el = self.doc.createElement(node.localName) parent.appendChild(el) value = self.eval(browser, attrs['expr']) @@ -270,8 +257,6 @@ class document(object): parent.appendChild(el) atr = self.node_attrs_get(node) if 'value' in atr: - #print "type=>",type(datas[atr['value']]) - #print "value=>",datas[atr['value']] if not isinstance(datas[atr['value']], (str, unicode)): txt = self.doc.createTextNode(str(datas[atr['value']])) else: From 30fba46139e9400574e6bab4fe608cc653cf0489 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Wed, 10 Dec 2008 23:16:57 +0100 Subject: [PATCH 053/137] [IMP] Use the logger bzr revid: stephane@tinyerp.com-20081210221657-qyu25oj1cid926k4 --- bin/tools/amount_to_text_en.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/bin/tools/amount_to_text_en.py b/bin/tools/amount_to_text_en.py index 91c27712715..c8cf4cb0e94 100644 --- a/bin/tools/amount_to_text_en.py +++ b/bin/tools/amount_to_text_en.py @@ -116,15 +116,14 @@ def amount_to_text(nbr, lang='en', currency='euro'): Example: 1654: thousands six cent cinquante-quatre. """ + import netsvc if nbr > 10000000: -#TODO: use logger - print "WARNING: number too large '%d', can't translate it!" % (nbr,) + netsvc.Logger().notifyChannel('translate', netsvc.LOG_WARNING, _("Number too large '%d', can not translate it")) return str(nbr) if not _translate_funcs.has_key(lang): -#TODO: use logger - print "WARNING: no translation function found for lang: '%s'" % (lang,) -#TODO: (default should be en) same as above + netsvc.Logger().notifyChannel('translate', netsvc.LOG_WARNING, _("no translation function found for lang: '%s'" % (lang,))) + #TODO: (default should be en) same as above lang = 'en' return _translate_funcs[lang](nbr, currency) From 720126aeec4425c46860d91ca26bc7025d1ff286 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Thu, 11 Dec 2008 00:50:53 +0100 Subject: [PATCH 054/137] [IMP] add a command line switch allowing to filter the log on the level bzr revid: christophe@tinyerp.com-20081210235053-v54zj54vu3jebvib --- bin/netsvc.py | 2 +- bin/tools/config.py | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/bin/netsvc.py b/bin/netsvc.py index a972fa84484..cc0ef093b17 100644 --- a/bin/netsvc.py +++ b/bin/netsvc.py @@ -177,7 +177,7 @@ def init_logger(): # add the handler to the root logger logging.getLogger().addHandler(handler) - logging.getLogger().setLevel(logging.INFO) + logging.getLogger().setLevel(config['log_level']) if isinstance(handler, logging.StreamHandler) and os.name != 'nt': # change color of level names diff --git a/bin/tools/config.py b/bin/tools/config.py index 8ab6d299a56..34434086610 100644 --- a/bin/tools/config.py +++ b/bin/tools/config.py @@ -62,10 +62,11 @@ class configmanager(object): 'stop_after_init': False, # this will stop the server after initialization 'price_accuracy': 2, - 'assert_exit_level': logging.WARNING, # level above which a failed assert will + 'log_level': logging.INFO, + 'assert_exit_level': logging.WARNING, # level above which a failed assert will be raise } - assert_exit_levels = (netsvc.LOG_CRITICAL, netsvc.LOG_ERROR, netsvc.LOG_WARNING, netsvc.LOG_INFO, netsvc.LOG_DEBUG) + loglevels = dict([(getattr(netsvc, 'LOG_%s' % x), getattr(logging, x)) for x in ('CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG')]) version = "%s %s" % (release.description, release.version) parser = optparse.OptionParser(version=version) @@ -89,7 +90,8 @@ class configmanager(object): # stops the server from launching after initialization parser.add_option("--stop-after-init", action="store_true", dest="stop_after_init", default=False, help="stop the server after it initializes") parser.add_option('--debug', dest='debug_mode', action='store_true', default=False, help='enable debug mode') - parser.add_option("--assert-exit-level", dest='assert_exit_level', help="specify the level at which a failed assertion will stop the server " + str(assert_exit_levels)) + parser.add_option('--log-level', dest='log_level', type='choice', choices=loglevels.keys(), help='specify the level of the logging. Accepted values: ' + str(loglevels.keys())) + parser.add_option("--assert-exit-level", dest='assert_exit_level', type="choice", choices=loglevels.keys(), help="specify the level at which a failed assertion will stop the server. Accepted values: " + str(loglevels.keys())) parser.add_option("-S", "--secure", dest="secure", action="store_true", help="launch server over https instead of http", default=False) parser.add_option('--email-from', dest='email_from', default='', help='specify the SMTP email address for sending email') @@ -163,8 +165,9 @@ class configmanager(object): self.options[arg] = getattr(opt, arg) if opt.assert_exit_level: - assert opt.assert_exit_level in assert_exit_levels, 'ERROR: The assert-exit-level must be one of those values: '+str(assert_exit_levels) - self.options['assert_exit_level'] = getattr(logging, opt.assert_exit_level.upper()) + self.options['assert_exit_level'] = loglevels[opt.assert_exit_level] + if opt.log_level: + self.options['log_level'] = loglevels[opt.log_level] if not self.options['root_path'] or self.options['root_path']=='None': self.options['root_path'] = os.path.abspath(os.path.dirname(sys.argv[0])) From f3e7dc68d32e1f4b000126878962f111efcfc761 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Thu, 11 Dec 2008 09:19:31 +0100 Subject: [PATCH 055/137] bugfixes_in_flight bzr revid: fp@tinyerp.com-20081211081931-z2f8y6fuqk7hf65x --- bin/addons/base/base_menu.xml | 6 +- bin/addons/base/base_update.xml | 2 +- bin/addons/base/ir/ir.xml | 28 +++---- bin/addons/base/ir/ir_ui_view.py | 1 - bin/addons/base/ir/workflow/workflow_view.xml | 8 +- bin/addons/base/module/module.py | 68 +++++++---------- .../module/report/ir_module_reference.rml | 7 ++ bin/addons/base/res/ir_property_view.xml | 3 +- bin/addons/base/rng/view.rng | 75 +++++++++++++++---- 9 files changed, 121 insertions(+), 77 deletions(-) diff --git a/bin/addons/base/base_menu.xml b/bin/addons/base/base_menu.xml index 1204ab5b42b..84a5bb9e230 100644 --- a/bin/addons/base/base_menu.xml +++ b/bin/addons/base/base_menu.xml @@ -2,7 +2,11 @@ - + + + + + diff --git a/bin/addons/base/base_update.xml b/bin/addons/base/base_update.xml index a8b8e269919..49bc289f337 100644 --- a/bin/addons/base/base_update.xml +++ b/bin/addons/base/base_update.xml @@ -6,7 +6,7 @@ Languages ====================== --> - + @@ -114,7 +113,7 @@ {'active_test': False} - + @@ -464,7 +463,7 @@ ir.ui.view form -
+ @@ -480,7 +479,7 @@ ir.ui.view tree - + @@ -488,7 +487,7 @@ - View + Views ir.actions.act_window ir.ui.view @@ -719,7 +718,7 @@ - + @@ -786,7 +785,7 @@ - + @@ -933,7 +932,7 @@ - Grant access to menu + Grant Access To Menus ir.ui.menu form @@ -991,7 +990,7 @@ {'active_test': False} - + @@ -1175,12 +1174,12 @@ - + - +
- + - - - + + + + + + + + + diff --git a/bin/addons/base/ir/ir_actions.py b/bin/addons/base/ir/ir_actions.py index 41ebe76ba51..84970c33fb7 100644 --- a/bin/addons/base/ir/ir_actions.py +++ b/bin/addons/base/ir/ir_actions.py @@ -387,8 +387,9 @@ class actions_server(osv.osv): 'action_id': fields.many2one('ir.actions.actions', 'Client Action'), 'trigger_name': fields.char('Trigger Name', size=128), 'trigger_obj_id': fields.reference('Trigger On', selection=model_get, size=128), + 'email': fields.many2one('ir.model.fields', 'Contact'), 'message': fields.text('Message', translate=True), - 'address': fields.many2one('ir.model.fields', 'Email / Mobile'), + 'mobile': fields.many2one('ir.model.fields', 'Contact'), 'sms': fields.char('SMS', size=160, translate=True), 'child_ids': fields.one2many('ir.actions.actions', 'parent_id', 'Others Actions'), 'usage': fields.char('Action Usage', size=32), @@ -416,17 +417,39 @@ class actions_server(osv.osv): 'otype': lambda *a: 'copy', } - def get_field_value(self, cr, uid, action, context): + + def get_email(self, cr, uid, action, context): obj_pool = self.pool.get(action.model_id.model) id = context.get('active_id') obj = obj_pool.browse(cr, uid, id) fields = None - if '/' in action.address.complete_name: - fields = action.address.complete_name.split('/') - elif '.' in action.address.complete_name: - fields = action.address.complete_name.split('.') + if '/' in action.email.complete_name: + fields = action.email.complete_name.split('/') + elif '.' in action.email.complete_name: + fields = action.email.complete_name.split('.') + + for field in fields: + try: + obj = getattr(obj, field) + except Exception,e : + logger.notifyChannel('Workflow', netsvc.LOG_ERROR, 'Failed to parse : %s' % (match.group())) + + return obj + + + def get_mobile(self, cr, uid, action, context): + obj_pool = self.pool.get(action.model_id.model) + id = context.get('active_id') + obj = obj_pool.browse(cr, uid, id) + + fields = None + + if '/' in action.mobile.complete_name: + fields = action.mobile.complete_name.split('/') + elif '.' in action.mobile.complete_name: + fields = action.mobile.complete_name.split('.') for field in fields: try: @@ -442,13 +465,13 @@ class actions_server(osv.osv): obj_pool = self.pool.get(action.model_id.model) id = context.get('active_id') obj = obj_pool.browse(cr, uid, id) - return eval(match[2:-2], {'object':obj, 'context': context,'time':time}) + exp = str(match.group()[2:-2]).strip() + return eval(exp, {'object':obj, 'context': context,'time':time}) com = re.compile('(\[\[.+?\]\])') message = com.sub(merge, keystr) return message - # # Context should contains: # ids : original ids # id : current id of the object @@ -478,11 +501,14 @@ class actions_server(osv.osv): if action.state == 'email': user = config['email_from'] subject = action.name - address = self.get_field_value(cr, uid, action, context) + address = self.get_email(cr, uid, action, context) if not address: raise osv.except_osv(_('Error'), _("Please specify the Partner Email address !")) + if not user: + raise osv.except_osv(_('Error'), _("Please specify server option --smtp-from !")) + body = self.merge_message(cr, uid, str(action.message), action, context) - if tools.email_send_attach(user, address, subject, body, debug=False) == True: + if tools.email_send(user, address, subject, body, debug=False) == True: logger.notifyChannel('email', netsvc.LOG_INFO, 'Email successfully send to : %s' % (address)) else: logger.notifyChannel('email', netsvc.LOG_ERROR, 'Failed to send email to : %s' % (address)) @@ -499,7 +525,7 @@ class actions_server(osv.osv): # for the sms gateway user / password api_id = '' text = action.sms - to = self.get_field_value(cr, uid, action, context) + to = self.get_mobile(cr, uid, action, context) #TODO: Apply message mearge with the field if tools.sms_send(user, password, api_id, text, to) == True: logger.notifyChannel('sms', netsvc.LOG_INFO, 'SMS successfully send to : %s' % (action.address)) diff --git a/bin/addons/base/ir/ir_model.py b/bin/addons/base/ir/ir_model.py index 4d8e2175d9d..2c2ba419e39 100644 --- a/bin/addons/base/ir/ir_model.py +++ b/bin/addons/base/ir/ir_model.py @@ -193,7 +193,9 @@ class ir_model_fields(osv.osv): _columns = { 'name': fields.char('Name', required=True, size=64, select=1), 'model': fields.char('Object Name', size=64, required=True), + 'relation_id':fields.many2one('ir.model', 'Object Relation'), 'relation': fields.char('Object Relation', size=64), + 'relation_field_id':fields.many2one('ir.model.fields', 'Relation Field'), 'relation_field': fields.char('Relation Field', size=64), 'model_id': fields.many2one('ir.model', 'Object id', required=True, select=True, ondelete='cascade'), 'field_description': fields.char('Field Label', required=True, size=256), @@ -231,8 +233,26 @@ class ir_model_fields(osv.osv): # MAY BE ADD A ALTER TABLE DROP ? # return super(ir_model_fields, self).unlink(cr, user, ids, context) - + + def write(self, cr, uid, ids, vals, context=None): + res = False + if 'relation_id' in vals: + model_data = self.pool.get('ir.model').browse(cr, uid, vals['relation_id']) + vals['relation'] = model_data.model + if 'relation_field_id' in vals: + field_data = self.pool.get('ir.model.fields').browse(cr, uid, vals['relation_field_id']) + vals['relation'] = field_data.name + + res = super(ir_model_fields, self).write(cr, uid, ids, vals, context) + return res + def create(self, cr, user, vals, context=None): + if 'relation_id' in vals: + model_data = self.pool.get('ir.model').browse(cr,user,vals['relation_id']) + vals['relation']=model_data.model + if 'relation_field_id' in vals: + field_data = self.pool.get('ir.model.fields').browse(cr, uid, vals['relation_field_id']) + vals['relation'] = field_data.name if 'model_id' in vals: model_data=self.pool.get('ir.model').browse(cr,user,vals['model_id']) vals['model']=model_data.model From 765ef60221c8435b0d07d30d6d4a5857d88bdc37 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Thu, 11 Dec 2008 12:44:13 +0100 Subject: [PATCH 063/137] [FIX] ir.module.module: Incorrect field names !! * installed_version refer the latest version (the one on disk) * latest_version refer the installed version (the one in database) * published_version refer the version available on the repository bzr revid: christophe@tinyerp.com-20081211114413-olfcmv4g650o350f --- bin/addons/__init__.py | 10 ++++---- bin/addons/base/module/module.py | 41 ++++++++++++++++---------------- bin/tools/misc.py | 5 ++-- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/bin/addons/__init__.py b/bin/addons/__init__.py index 8e9932a2cfc..63447a04c4d 100644 --- a/bin/addons/__init__.py +++ b/bin/addons/__init__.py @@ -380,7 +380,7 @@ class MigrationManager(object): from tools.parse_version import parse_version - parsed_installed_version = parse_version(pkg.latest_version) + parsed_installed_version = parse_version(pkg.installed_version) current_version = parse_version(convert_version(pkg.data.get('version', '0'))) versions = _get_migration_versions(pkg) @@ -402,7 +402,7 @@ class MigrationManager(object): try: mod = imp.load_source(name, pyfile, fp) logger.notifyChannel('migration', netsvc.LOG_INFO, 'addon %(addon)s: Running migration %(version)s %(name)s"' % mergedict({'name': mod.__name__},strfmt)) - mod.migrate(self.cr, pkg.latest_version) + mod.migrate(self.cr, pkg.installed_version) except ImportError: logger.notifyChannel('migration', netsvc.LOG_ERROR, 'addon %(addon)s: Unable to load %(stage)-migration file %(file)s' % mergedict({'file': opj(modulename,pyfile)}, strfmt)) raise @@ -427,13 +427,14 @@ def load_module_graph(cr, graph, status=None, check_access_rules=True, **kwargs) # update the graph with values from the database (if exist) ## First, we set the default values for each package in graph - additional_data = dict.fromkeys([p.name for p in graph], {'id': 0, 'state': 'uninstalled', 'dbdemo': False, 'latest_version': None}) + additional_data = dict.fromkeys([p.name for p in graph], {'id': 0, 'state': 'uninstalled', 'dbdemo': False, 'installed_version': None}) ## Then we get the values from the database - cr.execute('SELECT name, id, state, demo AS dbdemo, latest_version' + cr.execute('SELECT name, id, state, demo AS dbdemo, latest_version AS installed_version' ' FROM ir_module_module' ' WHERE name in (%s)' % (','.join(['%s'] * len(graph))), additional_data.keys() ) + ## and we update the default values with values from the database additional_data.update(dict([(x.pop('name'), x) for x in cr.dictfetchall()])) @@ -491,6 +492,7 @@ def load_module_graph(cr, graph, status=None, check_access_rules=True, **kwargs) cr.execute('update ir_module_module set demo=%s where id=%s', (True, mid)) package_todo.append(package.name) ver = release.major_version + '.' + package.data.get('version', '1.0') + # update the installed version in database... cr.execute("update ir_module_module set state='installed', latest_version=%s where id=%s", (ver, mid,)) cr.commit() diff --git a/bin/addons/base/module/module.py b/bin/addons/base/module/module.py index 0505d8629a6..be7e2bf6156 100644 --- a/bin/addons/base/module/module.py +++ b/bin/addons/base/module/module.py @@ -98,13 +98,10 @@ class module(osv.osv): return {} return info - def _get_installed_version(self, cr, uid, ids, field_name=None, arg=None, context={}): - res = {} + def _get_latest_version(self, cr, uid, ids, field_name=None, arg=None, context={}): + res = dict.setdefault(ids, '') for m in self.browse(cr, uid, ids): - if m.state in ('installed', 'to upgrade', 'to remove'): - res[m.id] = self.get_module_info(m.name).get('version', '') - else: - res[m.id] = '' + res[m.id] = self.get_module_info(m.name).get('version', '') return res def _get_views(self, cr, uid, ids, field_name=None, arg=None, context={}): @@ -143,10 +140,16 @@ class module(osv.osv): 'description': fields.text("Description", readonly=True, translate=True), 'author': fields.char("Author", size=128, readonly=True), 'website': fields.char("Website", size=256, readonly=True), - 'installed_version': fields.function(_get_installed_version, method=True, - string='Installed version', type='char'), - 'latest_version': fields.char('Latest version', size=64, readonly=True), + + # attention: Incorrect field names !! + # installed_version refer the latest version (the one on disk) + # latest_version refer the installed version (the one in database) + # published_version refer the version available on the repository + 'installed_version': fields.function(_get_latest_version, method=True, + string='Latest version', type='char'), + 'latest_version': fields.char('Installed version', size=64, readonly=True), 'published_version': fields.char('Published Version', size=64, readonly=True), + 'url': fields.char('URL', size=128), 'dependencies_id': fields.one2many('ir.module.module.dependency', 'module_id', 'Dependencies', readonly=True), @@ -289,7 +292,6 @@ class module(osv.osv): self.write(cr, uid, id, {'state': 'uninstalled'}) if parse_version(terp.get('version', '')) > parse_version(mod.latest_version or ''): self.write(cr, uid, id, { - 'latest_version': terp.get('version'), 'url': ''}) res[0] += 1 self.write(cr, uid, id, { @@ -328,7 +330,6 @@ class module(osv.osv): 'shortdesc': terp.get('name', ''), 'author': terp.get('author', 'Unknown'), 'website': terp.get('website', ''), - 'latest_version': terp.get('version', ''), 'license': terp.get('license', 'GPL-2'), }) res[1] += 1 @@ -365,7 +366,6 @@ class module(osv.osv): if not ids: self.create(cr, uid, { 'name': name, - 'latest_version': version, 'published_version': version, 'url': url, 'state': 'uninstalled', @@ -373,16 +373,15 @@ class module(osv.osv): res[1] += 1 else: id = ids[0] - latest_version = self.read(cr, uid, id, ['latest_version'])\ - ['latest_version'] - if latest_version == 'x': # 'x' version was a mistake - latest_version = '0' - if parse_version(version) > parse_version(latest_version): - self.write(cr, uid, id, - {'latest_version': version, 'url': url}) + installed_version = self.read(cr, uid, id, ['latest_version'])['latest_version'] + if installed_version == 'x': # 'x' version was a mistake + installed_version = '0' + if parse_version(version) > parse_version(installed_version): + self.write(cr, uid, id, { + 'url': url + }) res[0] += 1 - published_version = self.read(cr, uid, id, ['published_version'])\ - ['published_version'] + published_version = self.read(cr, uid, id, ['published_version'])['published_version'] if published_version == 'x' or not published_version: published_version = '0' if parse_version(version) > parse_version(published_version): diff --git a/bin/tools/misc.py b/bin/tools/misc.py index 63c7b3631f9..183f172d488 100644 --- a/bin/tools/misc.py +++ b/bin/tools/misc.py @@ -97,11 +97,10 @@ def init_db(cr): cr.execute('select nextval(\'ir_module_module_id_seq\')') id = cr.fetchone()[0] cr.execute('insert into ir_module_module \ - (id, author, latest_version, website, name, shortdesc, description, \ + (id, author, website, name, shortdesc, description, \ category_id, state) \ - values (%s, %s, %s, %s, %s, %s, %s, %s, %s)', ( + values (%s, %s, %s, %s, %s, %s, %s, %s)', ( id, info.get('author', ''), - release.major_version + '.' + info.get('version', ''), info.get('website', ''), i, info.get('name', False), info.get('description', ''), p_id, state)) dependencies = info.get('depends', []) From 46a67112521a6945fe6cd5483e437d22f49b5e8b Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Thu, 11 Dec 2008 13:08:32 +0100 Subject: [PATCH 064/137] improve bzr revid: fp@tinyerp.com-20081211120832-2sn25d5or5zz97ge --- addons/account/account_view.xml | 2 +- .../base_module_record_wizard.xml | 101 ++-- addons/hr_holidays/hr_view.xml | 2 +- addons/process/process_view.xml | 2 +- addons/product/product.py | 2 +- addons/product/product_data.xml | 2 +- addons/project/project_view.xml | 2 +- .../report_document/report_document_view.xml | 520 +++++++++--------- addons/stock/stock_view.xml | 2 +- addons/wiki/wiki_view.xml | 8 +- 10 files changed, 324 insertions(+), 319 deletions(-) diff --git a/addons/account/account_view.xml b/addons/account/account_view.xml index c73b829f14b..85a2d50f84b 100644 --- a/addons/account/account_view.xml +++ b/addons/account/account_view.xml @@ -134,7 +134,7 @@ - /> + diff --git a/addons/base_module_record/base_module_record_wizard.xml b/addons/base_module_record/base_module_record_wizard.xml index 11113e12f5a..abced76678a 100644 --- a/addons/base_module_record/base_module_record_wizard.xml +++ b/addons/base_module_record/base_module_record_wizard.xml @@ -1,58 +1,63 @@ - - + + - - + + - + + + - + - + - - + + - + diff --git a/addons/hr_holidays/hr_view.xml b/addons/hr_holidays/hr_view.xml index 37667e2457f..dcf73f3e9f9 100644 --- a/addons/hr_holidays/hr_view.xml +++ b/addons/hr_holidays/hr_view.xml @@ -17,7 +17,7 @@ - + diff --git a/addons/process/process_view.xml b/addons/process/process_view.xml index 3f294ef0302..8083ba278d4 100644 --- a/addons/process/process_view.xml +++ b/addons/process/process_view.xml @@ -4,7 +4,7 @@ diff --git a/addons/product/product.py b/addons/product/product.py index e830ea91cee..56a96a4258d 100644 --- a/addons/product/product.py +++ b/addons/product/product.py @@ -160,7 +160,7 @@ class product_ul(osv.osv): _name = "product.ul" _description = "Shipping Unit" _columns = { - 'name' : fields.char('Name', size=64,select=True), + 'name' : fields.char('Name', size=64,select=True, required=True), 'type' : fields.selection([('unit','Unit'),('pack','Pack'),('box', 'Box'), ('palet', 'Palet')], 'Type', required=True), } product_ul() diff --git a/addons/product/product_data.xml b/addons/product/product_data.xml index 0d784421a07..87b28be3bdb 100644 --- a/addons/product/product_data.xml +++ b/addons/product/product_data.xml @@ -86,7 +86,7 @@ parameter) will see those record just disappear. property_product_pricelist - + diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml index 32c7ed49c27..0159e019572 100644 --- a/addons/project/project_view.xml +++ b/addons/project/project_view.xml @@ -329,7 +329,7 @@ calendar - + diff --git a/addons/report_document/report_document_view.xml b/addons/report_document/report_document_view.xml index bc909dbdded..9dfb987c0d0 100644 --- a/addons/report_document/report_document_view.xml +++ b/addons/report_document/report_document_view.xml @@ -2,287 +2,287 @@ - - report.document.user.form - report.document.user - form - -
- - - - - - - - -
+ + report.document.user.form + report.document.user + form + +
+ + + + + + + + +
- - report.document.user.tree - report.document.user - tree - - - - - - - - - - - + + report.document.user.tree + report.document.user + tree + + + + + + + + + + + - - My files (This months) - report.document.user - form - tree - [('user_id','=',uid),('name','=',time.strftime('%Y-%m-01'))] - - - - - - + + My files (This months) + report.document.user + form + tree + [('user_id','=',uid),('name','=',time.strftime('%Y-%m-01'))] + + + + + + - - My files (All months) - report.document.user - form - tree,graph - [('user_id','=',uid)] - - - - + + My files (All months) + report.document.user + form + tree,graph + [('user_id','=',uid)] + + + + - - All Users files (This month) - report.document.user - form - tree,graph - [('name','=',time.strftime('%Y-%m-01'))] - - - + + All Users files (This month) + report.document.user + form + tree,graph + [('name','=',time.strftime('%Y-%m-01'))] + + + - - All Users files (All months) - report.document.user - form - tree - - - - - - - report.document.wall.form - report.document.wall - form - -
- - - - - - -
+ + All Users files (All months) + report.document.user + form + tree + + + + + + + report.document.wall.form + report.document.wall + form + +
+ + + + + + +
- - report.document.wall.tree - report.document.wall - tree - - - - - - - - - - - - Wall of Shame - report.document.wall - form - tree,form - - - + + report.document.wall.tree + report.document.wall + tree + + + + + + + + + + + + Wall of Shame + report.document.wall + form + tree,form + + + - - report.document.resource.graph - report.document.user - graph - - - - - - - - - - - - - - - - - - - - + + report.document.resource.graph + report.document.user + graph + + + + + + + + + + + + + + + + + + + + - - Files by Resource Type - report.document.user - - form - tree - - + + Files by Resource Type + report.document.user + + form + tree + + - - report.document.user.graph - report.document.file - graph - - - - - - - - - - report.document.user.tree - report.document.file - tree - - - - - - - - - File Size by Month - report.document.file - - form - tree - - + + report.document.user.graph + report.document.file + graph + + + + + + + + + + report.document.user.tree + report.document.file + tree + + + + + + + + + File Size by Month + report.document.file + + form + tree + + - - - report.file.month.graph - report.document.user - graph - - - - - - - - - - - - - report.file.month.tree - report.document.user - tree - - - - - - - - - - Files by Month - report.document.user - - form - tree - - - + + + report.file.month.graph + report.document.user + graph + + + + + + + + + + + + + report.file.month.tree + report.document.user + tree + + + + + + + + + + Files by Month + report.document.user + + form + tree + + + - - report.document.user.graph - report.document.user - graph - - - - - - - - - - Files By Users - report.document.user - - form - tree - - - + + report.document.user.graph + report.document.user + graph + + + + + + + + + + Files By Users + report.document.user + + form + tree + + + - - view.files.partner.graph - report.files.partner - graph - - - - + + view.files.partner.graph + report.files.partner + graph + + + + - - - - - - view.files.partner.tree - report.files.partner - tree - - - - - - - - - - Files Per Month - report.files.partner - - form - tree - - + + + + + + view.files.partner.tree + report.files.partner + tree + + + + + + + + + + Files Per Month + report.files.partner + + form + tree + + -
+
diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml index ad16df6d958..fca543de59a 100644 --- a/addons/stock/stock_view.xml +++ b/addons/stock/stock_view.xml @@ -350,7 +350,7 @@ - > + diff --git a/addons/wiki/wiki_view.xml b/addons/wiki/wiki_view.xml index 8dc80ed2752..7a8d17e47e4 100644 --- a/addons/wiki/wiki_view.xml +++ b/addons/wiki/wiki_view.xml @@ -17,7 +17,7 @@ tree child_ids - + @@ -27,7 +27,7 @@ wiki.groups form -
+ @@ -132,7 +132,7 @@ wiki.wiki.history tree - + @@ -146,7 +146,7 @@ wiki.wiki.history form - + From 0d7ee55319c263ccc0fc23b4a66d8ea961f396db Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Thu, 11 Dec 2008 13:20:07 +0100 Subject: [PATCH 065/137] [FIX] Use fromkeys and not setdefault bzr revid: stephane@tinyerp.com-20081211122007-ykmckeajss5i8nm5 --- bin/addons/base/module/module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/addons/base/module/module.py b/bin/addons/base/module/module.py index be7e2bf6156..cde52e36a19 100644 --- a/bin/addons/base/module/module.py +++ b/bin/addons/base/module/module.py @@ -99,7 +99,7 @@ class module(osv.osv): return info def _get_latest_version(self, cr, uid, ids, field_name=None, arg=None, context={}): - res = dict.setdefault(ids, '') + res = dict.fromkeys(ids, '') for m in self.browse(cr, uid, ids): res[m.id] = self.get_module_info(m.name).get('version', '') return res From 646113967472aec49af0d5106d1d1b8b970ec55b Mon Sep 17 00:00:00 2001 From: Jay Vora Date: Thu, 11 Dec 2008 18:03:16 +0530 Subject: [PATCH 066/137] Minor edit and bugfix on calendar view of project.task(ref:AME) bzr revid: jvo@tinyerp.com-20081211123316-hbmy9upkavwf03co --- addons/crm/__terp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/crm/__terp__.py b/addons/crm/__terp__.py index 7bf93a5c550..b3d8e255876 100644 --- a/addons/crm/__terp__.py +++ b/addons/crm/__terp__.py @@ -30,7 +30,7 @@ people to intelligently and efficiently manage tasks, issues, and requests. It manages key tasks such as communication, identification, prioritization, assignment, resolution and notification. -Open ERP ensures that all cases are successfly tracked by users, customers and +Open ERP ensures that all cases are successfully tracked by users, customers and suppliers. It can automatically send reminders, escalate the request, trigger specific methods and lots of others actions based on your enterprise own rules. From 591789e96106d69b295738f21bbb189e8f7666e9 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Thu, 11 Dec 2008 13:45:48 +0100 Subject: [PATCH 067/137] [FIX] correct view bzr revid: christophe@tinyerp.com-20081211124548-m315khhlr4k287el --- addons/report_document/report_document_view.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/addons/report_document/report_document_view.xml b/addons/report_document/report_document_view.xml index e739a3fe629..8f68875ea40 100644 --- a/addons/report_document/report_document_view.xml +++ b/addons/report_document/report_document_view.xml @@ -1,8 +1,6 @@ - -<<<<<<< TREE report.document.user.form report.document.user From 7b0b4cca4f9d33a72a382adf7e96e616e9901dbf Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Thu, 11 Dec 2008 13:46:39 +0100 Subject: [PATCH 068/137] bugfix bzr revid: fp@tinyerp.com-20081211124639-jzp2oud0q5y6o84a --- addons/report_document/report_document_view.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/report_document/report_document_view.xml b/addons/report_document/report_document_view.xml index e739a3fe629..b4b5eaca1d5 100644 --- a/addons/report_document/report_document_view.xml +++ b/addons/report_document/report_document_view.xml @@ -2,7 +2,6 @@ -<<<<<<< TREE report.document.user.form report.document.user From 458324a685a10a661b95d94c6691550a0c38b839 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Thu, 11 Dec 2008 13:47:24 +0100 Subject: [PATCH 069/137] [FIX] handle the case when the addons has no version bzr revid: christophe@tinyerp.com-20081211124724-6fj8g1er1iaet3ov --- bin/addons/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/addons/__init__.py b/bin/addons/__init__.py index 63447a04c4d..95949633582 100644 --- a/bin/addons/__init__.py +++ b/bin/addons/__init__.py @@ -380,7 +380,7 @@ class MigrationManager(object): from tools.parse_version import parse_version - parsed_installed_version = parse_version(pkg.installed_version) + parsed_installed_version = parse_version(pkg.installed_version or '') current_version = parse_version(convert_version(pkg.data.get('version', '0'))) versions = _get_migration_versions(pkg) From 5971bf35a6616a4fab9904ee9a80e2df530e3f1c Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Thu, 11 Dec 2008 13:49:21 +0100 Subject: [PATCH 070/137] bugfix bzr revid: fp@tinyerp.com-20081211124921-9022irf32yc8xsaa --- bin/addons/base/rng/view.rng | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/addons/base/rng/view.rng b/bin/addons/base/rng/view.rng index fc75dc23f5d..e7626484d4a 100644 --- a/bin/addons/base/rng/view.rng +++ b/bin/addons/base/rng/view.rng @@ -213,6 +213,7 @@ + From d1ab49e090f8d7c6f09dac8199607e759660e050 Mon Sep 17 00:00:00 2001 From: Husen Daudi Date: Thu, 11 Dec 2008 18:22:01 +0530 Subject: [PATCH 071/137] bufgix for xml validation bzr revid: hda@tinyerp.com-20081211125201-91lce3aqxtr8swe7 --- bin/addons/base/rng/view.rng | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bin/addons/base/rng/view.rng b/bin/addons/base/rng/view.rng index e7626484d4a..717ce00e62d 100644 --- a/bin/addons/base/rng/view.rng +++ b/bin/addons/base/rng/view.rng @@ -35,6 +35,7 @@ + @@ -230,6 +231,7 @@ + @@ -237,6 +239,7 @@ + @@ -278,6 +281,7 @@ + From c82e1831a18d76a61d034104cf0df1021d3ff971 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Thu, 11 Dec 2008 14:08:01 +0100 Subject: [PATCH 072/137] bugfix bzr revid: fp@tinyerp.com-20081211130801-y0yyo6ao1nff33s0 --- addons/account_reporting/account_view.xml | 108 +++++++++++----------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/addons/account_reporting/account_view.xml b/addons/account_reporting/account_view.xml index 8e12951ee84..1eb4daf6dc9 100644 --- a/addons/account_reporting/account_view.xml +++ b/addons/account_reporting/account_view.xml @@ -2,62 +2,62 @@ - - account.report.bs.form - account.report.bs - form - - - - - - - - - - - - - - - - - - - - - - + + account.report.bs.form + account.report.bs + form + +
+ + + + + + + + + + + + + + + + + +
+
+
- - account.report.report.tree.bs - account.report.bs - tree - child_id - - - - - - - - - ir.actions.act_window - account.report.bs - [('parent_id','=',False)] - tree - - - - + + account.report.report.tree.bs + account.report.bs + tree + child_id + + + + + + + + + ir.actions.act_window + account.report.bs + [('parent_id','=',False)] + tree + + + + - - ir.actions.act_window - account.report.bs - form - - - + + ir.actions.act_window + account.report.bs + form + + + From cfc14c69aebfa5ae8cb0536712c4cf9168e43fe9 Mon Sep 17 00:00:00 2001 From: apa-tiny Date: Thu, 11 Dec 2008 19:00:48 +0530 Subject: [PATCH 073/137] add logout method for ajm bzr revid: patelamit2003@gmail.com-20081211133048-x1me7ic1dft9qgs8 --- bin/service/security.py | 10 ++++++++++ bin/service/web_services.py | 24 +++++++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/bin/service/security.py b/bin/service/security.py index 81c6ef99744..4b6d5055bc1 100644 --- a/bin/service/security.py +++ b/bin/service/security.py @@ -35,6 +35,16 @@ def login(db, login, password): else: return False +def logout(db, login, password): + cr = pooler.get_db(db).cursor() + cr.execute('select login from res_users where id=%d'%(login)) + res = cr.fetchone() + cr.close() + if res: + return res[0] + else: + return False + def check_super(passwd): if passwd == tools.config['admin_passwd']: return True diff --git a/bin/service/web_services.py b/bin/service/web_services.py index ce395d3cd67..7b79ecb116e 100644 --- a/bin/service/web_services.py +++ b/bin/service/web_services.py @@ -282,6 +282,7 @@ class common(netsvc.Service): self.exportMethod(self.ir_del) self.exportMethod(self.about) self.exportMethod(self.login) + self.exportMethod(self.logout) self.exportMethod(self.timezone_get) def ir_set(self, db, uid, password, keys, args, name, value, replace=True, isobject=False): @@ -316,8 +317,29 @@ class common(netsvc.Service): res = security.login(db, login, password) logger = netsvc.Logger() msg = res and 'successful login' or 'bad login or password' - logger.notifyChannel("web-services", netsvc.LOG_INFO, "%s from '%s' using database '%s'" % (msg, login, db.lower())) + logger.notifyChannel("web-service", netsvc.LOG_INFO, "%s from '%s' using database '%s'" % (msg, login, db.lower())) return res or False + + def logout(self, db, login, password): + res = security.logout(db, login, password) + service = netsvc.LocalService("object_proxy") + fields = service.execute(db, login, 'res.users', 'fields_get', {}) + try: + if 'current_status' in fields.keys(): + service.execute(db, login, 'res.users', 'write', login, {'current_status':False}) + emp_id = service.execute(db, login, 'hr.employee', 'search',[('user_id','=',login)]) + emp = emp_id[0] + service.execute(db, login, 'hr.attendance', 'create',{'action':'sign_out','employee_id':emp}) + cr = pooler.get_db(db).cursor() + cr.execute("delete from time_sheet_remote_temp where user_id = '%s'"%(res)) + cr.commit() + cr.close() + except: + pass + logger = netsvc.Logger() + logger.notifyChannel("web-service", netsvc.LOG_INFO,'Logout=>%s from database %s'%(res,db.lower())) + + def about(self, extended=False): """Return information about the OpenERP Server. From ba0f20b57365f28264150365be871b5b65838a67 Mon Sep 17 00:00:00 2001 From: Mantavya Gajjar Date: Thu, 11 Dec 2008 19:04:57 +0530 Subject: [PATCH 074/137] change small things bug-fix in the create method bzr revid: mga@tinyerp.com-20081211133457-s304k5ct5kvgiiju --- bin/addons/base/ir/ir.xml | 7 +++---- bin/addons/base/ir/ir_actions.py | 2 +- bin/addons/base/ir/ir_model.py | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/bin/addons/base/ir/ir.xml b/bin/addons/base/ir/ir.xml index 99a8be878be..b717e26e106 100644 --- a/bin/addons/base/ir/ir.xml +++ b/bin/addons/base/ir/ir.xml @@ -1177,8 +1177,8 @@ - - + + @@ -1200,8 +1200,7 @@ - - +
diff --git a/bin/addons/base/ir/ir_actions.py b/bin/addons/base/ir/ir_actions.py index 84970c33fb7..fb7b187e92c 100644 --- a/bin/addons/base/ir/ir_actions.py +++ b/bin/addons/base/ir/ir_actions.py @@ -508,7 +508,7 @@ class actions_server(osv.osv): raise osv.except_osv(_('Error'), _("Please specify server option --smtp-from !")) body = self.merge_message(cr, uid, str(action.message), action, context) - if tools.email_send(user, address, subject, body, debug=False) == True: + if tools.email_send(user, [address], subject, body, debug=False) == True: logger.notifyChannel('email', netsvc.LOG_INFO, 'Email successfully send to : %s' % (address)) else: logger.notifyChannel('email', netsvc.LOG_ERROR, 'Failed to send email to : %s' % (address)) diff --git a/bin/addons/base/ir/ir_model.py b/bin/addons/base/ir/ir_model.py index 2c2ba419e39..4d42dd9411c 100644 --- a/bin/addons/base/ir/ir_model.py +++ b/bin/addons/base/ir/ir_model.py @@ -252,7 +252,7 @@ class ir_model_fields(osv.osv): vals['relation']=model_data.model if 'relation_field_id' in vals: field_data = self.pool.get('ir.model.fields').browse(cr, uid, vals['relation_field_id']) - vals['relation'] = field_data.name + vals['relation_field'] = field_data.name if 'model_id' in vals: model_data=self.pool.get('ir.model').browse(cr,user,vals['model_id']) vals['model']=model_data.model From 080e0dc652d8e70d91dbb5fcc33d95b2899da251 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Thu, 11 Dec 2008 14:52:36 +0100 Subject: [PATCH 075/137] [FIX] module upgrade: revert (bad) patch to mark new deps to be installed bzr revid: christophe@tinyerp.com-20081211135236-z30llytkl40i1qnt --- bin/addons/base/module/module.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/bin/addons/base/module/module.py b/bin/addons/base/module/module.py index cde52e36a19..26570685f43 100644 --- a/bin/addons/base/module/module.py +++ b/bin/addons/base/module/module.py @@ -248,7 +248,6 @@ class module(osv.osv): def button_upgrade(self, cr, uid, ids, context=None): depobj = self.pool.get('ir.module.module.dependency') todo = self.browse(cr, uid, ids, context=context) - to_install = set() i = 0 while i Date: Thu, 11 Dec 2008 19:34:27 +0530 Subject: [PATCH 076/137] improvement in the fields and model view bzr revid: mga@tinyerp.com-20081211140427-5893mrgicv0d2tsd --- bin/addons/base/ir/ir.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/addons/base/ir/ir.xml b/bin/addons/base/ir/ir.xml index b717e26e106..fa541535dd7 100644 --- a/bin/addons/base/ir/ir.xml +++ b/bin/addons/base/ir/ir.xml @@ -689,7 +689,7 @@ + 'readonly': [('ttype','!=','one2many'), ('ttype','!=','many2one'), ('ttype','!=','many2many')]}"/> From e85e69dffd48a7573769cf5c7dfa7e2d9b6f9d43 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Thu, 11 Dec 2008 15:53:05 +0100 Subject: [PATCH 077/137] [IMP] osutil.listdir follow symlinks bzr revid: christophe@tinyerp.com-20081211145305-9vf5k996rcaueat4 --- bin/tools/osutil.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/tools/osutil.py b/bin/tools/osutil.py index ba1d650f4ef..1925f82f671 100644 --- a/bin/tools/osutil.py +++ b/bin/tools/osutil.py @@ -34,7 +34,7 @@ def listdir(dir, recursive=False): return os.listdir(dir) res = [] - for root, dirs, files in os.walk(dir): + for root, dirs, files in walksymlinks(dir): root = root[len(dir)+1:] res.extend([opj(root, f) for f in files]) return res From 5e510fc9775ca75bd316b8d08319e6f57617cc0a Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Thu, 11 Dec 2008 15:54:20 +0100 Subject: [PATCH 078/137] [FIX] upgrade a module now install the new dependencies bzr revid: christophe@tinyerp.com-20081211145420-2dy5ym0mo8s0bsex --- bin/addons/base/module/module.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bin/addons/base/module/module.py b/bin/addons/base/module/module.py index 26570685f43..5ed36511d95 100644 --- a/bin/addons/base/module/module.py +++ b/bin/addons/base/module/module.py @@ -259,7 +259,10 @@ class module(osv.osv): for dep in depobj.browse(cr, uid, iids, context=context): if dep.module_id.state=='installed': todo.append(dep.module_id) - self.write(cr,uid, map(lambda x: x.id, todo), {'state':'to upgrade'}, context=context) + + ids = map(lambda x: x.id, todo) + self.write(cr, uid, ids, {'state':'to upgrade'}, context=context) + self.button_install(cr, uid, ids, context=context) return True def button_upgrade_cancel(self, cr, uid, ids, context={}): From 4cdb307f121f9cc6d7a99990151255400e345f3c Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Thu, 11 Dec 2008 15:55:51 +0100 Subject: [PATCH 079/137] removed_test bzr revid: fp@tinyerp.com-20081211145551-1v5pidkcgf6mlepu --- addons/account/account_unit_test.xml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/addons/account/account_unit_test.xml b/addons/account/account_unit_test.xml index 6da81e996d9..f321d311b21 100644 --- a/addons/account/account_unit_test.xml +++ b/addons/account/account_unit_test.xml @@ -1,6 +1,6 @@ - + @@ -40,10 +40,11 @@ + + From 5ee1dff04cca5d6c0dd502208d432ea1a890b54a Mon Sep 17 00:00:00 2001 From: Mantavya Gajjar Date: Thu, 11 Dec 2008 20:31:47 +0530 Subject: [PATCH 080/137] improvement in the server action bzr revid: mga@tinyerp.com-20081211150147-5j2bnp04h3g640bq --- bin/addons/base/ir/ir.xml | 4 ++-- bin/addons/base/ir/ir_actions.py | 27 +++++++++++++-------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/bin/addons/base/ir/ir.xml b/bin/addons/base/ir/ir.xml index fa541535dd7..4230d63c0b7 100644 --- a/bin/addons/base/ir/ir.xml +++ b/bin/addons/base/ir/ir.xml @@ -1177,8 +1177,7 @@ - - + @@ -1191,6 +1190,7 @@ + diff --git a/bin/addons/base/ir/ir_actions.py b/bin/addons/base/ir/ir_actions.py index fb7b187e92c..0bd04398bb9 100644 --- a/bin/addons/base/ir/ir_actions.py +++ b/bin/addons/base/ir/ir_actions.py @@ -396,10 +396,7 @@ class actions_server(osv.osv): 'type': fields.char('Report Type', size=32, required=True), 'srcmodel_id': fields.many2one('ir.model', 'Model'), 'fields_lines': fields.one2many('ir.server.object.lines', 'server_id', 'Fields Mapping'), - 'otype': fields.selection([ - ('copy','Create in Same Model'), - ('new','Create in Other Model') - ], 'Create Model', size=32, change_default=True), + 'record_id':fields.many2one('ir.model.fields', 'Record Id') } _defaults = { 'state': lambda *a: 'dummy', @@ -414,7 +411,6 @@ class actions_server(osv.osv): # - ids # If you plan to return an action, assign: action = {...} """, - 'otype': lambda *a: 'copy', } @@ -558,9 +554,15 @@ class actions_server(osv.osv): else: expr = exp.value res[exp.col1.name] = expr - obj_pool = self.pool.get(action.model_id.model) - obj_pool.write(cr, uid, [context.get('active_id')], res) + if not action.srcmodel_id: + obj_pool = self.pool.get(action.model_id.model) + obj_pool.write(cr, uid, [context.get('active_id')], res) + else: + obj_pool = self.pool.get(action.srcmodel_id.model) + id = self.pool.get(action.model_id.model).read(cr, uid, [context.get('active_id')], [action.record_id.name]) + obj_pool.write(cr, uid, [int(id[0][action.record_id.name])], res) + if action.state == 'object_create': res = {} for exp in action.fields_lines: @@ -574,13 +576,10 @@ class actions_server(osv.osv): res[exp.col1.name] = expr obj_pool = None - if action.state == 'object_create' and action.otype == 'new': - obj_pool = self.pool.get(action.srcmodel_id.model) - obj_pool.create(cr, uid, res) - else: - obj_pool = self.pool.get(action.model_id.model) - id = context.get('active_id') - obj_pool.copy(cr, uid, id, res) + res_id = False + obj_pool = self.pool.get(action.srcmodel_id.model) + res_id = obj_pool.create(cr, uid, res) + self.pool.get(action.model_id.model).write(cr, uid, [context.get('active_id')], {action.record_id.name:res_id}) return False actions_server() From cfe89367cdca32a42788778c2f108f4d316bef98 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Thu, 11 Dec 2008 17:07:46 +0100 Subject: [PATCH 081/137] [IMP] improve rapidity bzr revid: christophe@tinyerp.com-20081211160746-h111up81ofun9asg --- bin/addons/base/module/module.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/bin/addons/base/module/module.py b/bin/addons/base/module/module.py index 5ed36511d95..9a5ba75a57d 100644 --- a/bin/addons/base/module/module.py +++ b/bin/addons/base/module/module.py @@ -259,10 +259,20 @@ class module(osv.osv): for dep in depobj.browse(cr, uid, iids, context=context): if dep.module_id.state=='installed': todo.append(dep.module_id) - + ids = map(lambda x: x.id, todo) self.write(cr, uid, ids, {'state':'to upgrade'}, context=context) - self.button_install(cr, uid, ids, context=context) + + to_install = [] + for mod in todo: + for dep in mod.dependencies_id: + if dep.state == 'unknown': + raise orm.except_orm(_('Error'), _('You try to upgrade a module that depends on the module: %s.\nBut this module is not available in your system.') % (dep.name,)) + if dep.state == 'uninstalled': + ids2 = self.search(cr, uid, [('name','=',dep.name)]) + to_install.extend(ids2) + + self.button_install(cr, uid, to_install, context=context) return True def button_upgrade_cancel(self, cr, uid, ids, context={}): From 05006c78fdc761e9c9e3a962dfe6e0fac0687d06 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Thu, 11 Dec 2008 18:37:12 +0100 Subject: [PATCH 082/137] [FIX] (ugly) logout method must not return None lp bug: https://launchpad.net/bugs/307226 fixed bzr revid: christophe@tinyerp.com-20081211173712-bhbh03oykm6kdz4h --- bin/service/web_services.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/service/web_services.py b/bin/service/web_services.py index 7b79ecb116e..a0005bd8e78 100644 --- a/bin/service/web_services.py +++ b/bin/service/web_services.py @@ -321,6 +321,7 @@ class common(netsvc.Service): return res or False def logout(self, db, login, password): + # FIXME: WTF !!! what is this hardcoding ? res = security.logout(db, login, password) service = netsvc.LocalService("object_proxy") fields = service.execute(db, login, 'res.users', 'fields_get', {}) @@ -338,7 +339,8 @@ class common(netsvc.Service): pass logger = netsvc.Logger() logger.notifyChannel("web-service", netsvc.LOG_INFO,'Logout=>%s from database %s'%(res,db.lower())) - + return True + def about(self, extended=False): From 4edacbb1901e5b4e30d80dc7f52d581f5e412080 Mon Sep 17 00:00:00 2001 From: Fabian Semal Date: Thu, 11 Dec 2008 18:46:28 +0100 Subject: [PATCH 083/137] * Added relaxng rule for button in tree view * Improved report_sxw.py to use other model then active one bzr revid: fabian@tinyerp.com-20081211174628-m6dr3wdal9ntrpff --- bin/addons/base/rng/view.rng | 1 + bin/report/report_sxw.py | 1 + 2 files changed, 2 insertions(+) diff --git a/bin/addons/base/rng/view.rng b/bin/addons/base/rng/view.rng index 717ce00e62d..a02a3f3d680 100644 --- a/bin/addons/base/rng/view.rng +++ b/bin/addons/base/rng/view.rng @@ -41,6 +41,7 @@ + diff --git a/bin/report/report_sxw.py b/bin/report/report_sxw.py index ddf0393e910..416db51fcc5 100644 --- a/bin/report/report_sxw.py +++ b/bin/report/report_sxw.py @@ -610,6 +610,7 @@ class report_sxw(report_rml): attach = report_xml.attachment rml = report_xml.report_rml_content report_type = report_xml.report_type + context['actual_model']=report_xml.actual_model else: ir_menu_report_obj = pool.get('ir.ui.menu') report_menu_ids = ir_menu_report_obj.search(cr, uid, From 8575d47abc01a79ab97171e59b5691659ec804aa Mon Sep 17 00:00:00 2001 From: Niels Huylebroeck Date: Thu, 11 Dec 2008 20:07:19 +0100 Subject: [PATCH 084/137] Fixed typo in separator in warning_view.xml bzr revid: niels@bubbles-it.be-20081211190719-mjyjgb43iv0glcdw --- addons/warning/warning_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/warning/warning_view.xml b/addons/warning/warning_view.xml index 2adba29c996..6ea8b5cef0e 100644 --- a/addons/warning/warning_view.xml +++ b/addons/warning/warning_view.xml @@ -13,7 +13,7 @@ - + From 68afd07dddfd4c0064029faabec144caed8fb506 Mon Sep 17 00:00:00 2001 From: Niels Huylebroeck Date: Thu, 11 Dec 2008 20:09:14 +0100 Subject: [PATCH 085/137] Another typo on the product form bzr revid: niels@bubbles-it.be-20081211190914-lpf3vx2xefmsvbfh --- addons/warning/warning_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/warning/warning_view.xml b/addons/warning/warning_view.xml index 6ea8b5cef0e..3f9f7f24ec2 100644 --- a/addons/warning/warning_view.xml +++ b/addons/warning/warning_view.xml @@ -38,7 +38,7 @@ - +
From 4d018bef8c734e05f5dc42461e89e9b279eedf7d Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Thu, 11 Dec 2008 21:44:42 +0100 Subject: [PATCH 086/137] [IMP] Change the website in the base module bzr revid: stephane@tinyerp.com-20081211204442-drli4p5wxfy4jepo --- bin/addons/base/__terp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/addons/base/__terp__.py b/bin/addons/base/__terp__.py index 380fb16c55c..0411acccfe4 100644 --- a/bin/addons/base/__terp__.py +++ b/bin/addons/base/__terp__.py @@ -23,7 +23,7 @@ "name" : "Base", "version" : "1.0", "author" : "Tiny", - "website" : "http://openerp.com", + "website" : "http://www.openerp.com", "category" : "Generic Modules/Base", "description": "The kernel of OpenERP, needed for all installation.", "depends" : [], From 6827e34569b4157c982213231931dfc20acdc6eb Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Thu, 11 Dec 2008 22:20:56 +0100 Subject: [PATCH 087/137] [IMP] Add the server's version and the addon_path in the logger bzr revid: stephane@tinyerp.com-20081211212056-j8kxsswehue3go9x --- bin/openerp-server.py | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/bin/openerp-server.py b/bin/openerp-server.py index 7c65a923e52..05734f7fdf7 100755 --- a/bin/openerp-server.py +++ b/bin/openerp-server.py @@ -59,6 +59,12 @@ logger = netsvc.Logger() # import the tools module so that the commandline parameters are parsed #----------------------------------------------------------------------- import tools + +logger.notifyChannel("server", netsvc.LOG_INFO, "version - %s" % release.version ) +for name, value in [('addons_path', tools.config['addons_path']), + ('database hostname', tools.config['db_host'] or 'localhost')]: + logger.notifyChannel("server", netsvc.LOG_INFO, "%s - %s" % ( name, value )) + import time if sys.platform == 'win32': @@ -93,7 +99,10 @@ if tools.config['upgrade']: #---------------------------------------------------------- # import basic modules #---------------------------------------------------------- -import osv, workflow, report, service +import osv +import workflow +import report +import service #---------------------------------------------------------- # import addons @@ -152,17 +161,14 @@ if tools.config['xmlrpc']: if tools.config["xmlrpc"]: xml_gw = netsvc.xmlrpc.RpcGateway('web-services') httpd.attach("/xmlrpc", xml_gw) - logger.notifyChannel("web-services", netsvc.LOG_INFO, - "starting XML-RPC" + \ - (tools.config['secure'] and ' Secure' or '') + \ - " services, port " + str(port)) + logger.notifyChannel("web-services", netsvc.LOG_INFO, "starting XML-RPC%s services, port %s" % ((tools.config['secure'] and ' Secure' or ''), port)) - # - #if tools.config["soap"]: - # soap_gw = netsvc.xmlrpc.RpcGateway('web-services') - # httpd.attach("/soap", soap_gw ) - # logger.notifyChannel("web-services", netsvc.LOG_INFO, 'starting SOAP services, port '+str(port)) - # +# +#if tools.config["soap"]: +# soap_gw = netsvc.xmlrpc.RpcGateway('web-services') +# httpd.attach("/soap", soap_gw ) +# logger.notifyChannel("web-services", netsvc.LOG_INFO, 'starting SOAP services, port '+str(port)) +# if tools.config['netrpc']: try: From cf0936044472a84461791f7aa3dbb1a9f41737b6 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Thu, 11 Dec 2008 23:00:09 +0100 Subject: [PATCH 088/137] [FIX] Remove the decode(utf8) function lp bug: https://launchpad.net/bugs/307248 fixed bzr revid: stephane@tinyerp.com-20081211220009-el7lc2bb0pqc99pc --- bin/osv/orm.py | 4 ++-- bin/wizard/__init__.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index 920c27da946..148626ae26c 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -842,11 +842,11 @@ class orm_template(object): if not trans and ('base_model_name' in context): trans = tools.translate(cr, context['base_model_name'], 'view', context['lang'], node.getAttribute('string').encode('utf8')) if trans: - node.setAttribute('string', trans.decode('utf8')) + node.setAttribute('string', trans) if node.hasAttribute('sum') and node.getAttribute('sum'): trans = tools.translate(cr, self._name, 'view', context['lang'], node.getAttribute('sum').encode('utf8')) if trans: - node.setAttribute('sum', trans.decode('utf8')) + node.setAttribute('sum', trans) if childs: for f in node.childNodes: diff --git a/bin/wizard/__init__.py b/bin/wizard/__init__.py index 72be97b3958..fcacf67a476 100644 --- a/bin/wizard/__init__.py +++ b/bin/wizard/__init__.py @@ -54,7 +54,7 @@ class interface(netsvc.Service): if node.hasAttribute('string') and node.getAttribute('string'): trans = translate(cr, self.wiz_name+','+state, 'wizard_view', lang, node.getAttribute('string').encode('utf8')) if trans: - node.setAttribute('string', trans.decode('utf8')) + node.setAttribute('string', trans) for n in node.childNodes: self.translate_view(cr, n, state, lang) From cbf2dee7c7a0b71759c5aebad2d974030ac84b88 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Thu, 11 Dec 2008 23:28:01 +0100 Subject: [PATCH 089/137] [FIX] The second parameter of the map function must support iteration lp bug: https://launchpad.net/bugs/307284 fixed bzr revid: stephane@tinyerp.com-20081211222801-343rhnfmr21fw7le --- bin/sql_db.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bin/sql_db.py b/bin/sql_db.py index 4286a98da2f..cf9aa75ac4e 100644 --- a/bin/sql_db.py +++ b/bin/sql_db.py @@ -69,8 +69,11 @@ class Cursor(object): self.dbname = pool.dbname def execute(self, query, params=None): - if not params: + if params is None: params=() + if not isinstance(params, (tuple, list)): + params = (params,) + def base_string(s): if isinstance(s, unicode): return s.encode('utf-8') From 3e3f364abfe84c3c09a44d9a141f8b47794252b6 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Fri, 12 Dec 2008 00:49:48 +0100 Subject: [PATCH 090/137] [FIX] Use a temporary variable for the fetchall lp bug: https://launchpad.net/bugs/307284 fixed bzr revid: stephane@tinyerp.com-20081211234948-8h825jmr6qhluc2l --- addons/crm_profiling/crm_profiling.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/addons/crm_profiling/crm_profiling.py b/addons/crm_profiling/crm_profiling.py index 65f11e8bfba..c5a8b118b0f 100644 --- a/addons/crm_profiling/crm_profiling.py +++ b/addons/crm_profiling/crm_profiling.py @@ -131,22 +131,23 @@ class questionnaire(osv.osv): query = """ select name, id from crm_profiling_question - where id in ( select question from profile_questionnaire_quest_rel where questionnaire = %s)"""% data['form']['questionnaire_name'] - cr.execute(query) + where id in ( select question from profile_questionnaire_quest_rel where questionnaire = %s)""" + res = cr.execute(query, data['form']['questionnaire_name']) + result = cr.fetchall() quest_fields={} quest_form='''
''' % _('Questionnaire') - for x in cr.fetchall(): + for x in result: quest_form = quest_form + '''''' quest_fields['quest_form'+str(x[1])] = {'string': str(x[0]), 'type': 'many2one', 'relation': 'crm_profiling.answer', 'domain': [('question_id','=',x[1])] } quest_form = quest_form + '''''' return quest_form,quest_fields - _columns={ + _columns = { 'name': fields.char("Questionnaire",size=128, required=True), 'description':fields.text("Description", required=True), 'questions_ids': fields.many2many('crm_profiling.question','profile_questionnaire_quest_rel','questionnaire', 'question', "Questions"), - } + } questionnaire() From 5cc55266a70e7f16b2a281064c463f52cc29ba96 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Fri, 12 Dec 2008 01:02:09 +0100 Subject: [PATCH 091/137] [FIX] Use dict.get() instead of r['name'] or '' lp bug: https://launchpad.net/bugs/307248 fixed bzr revid: stephane@tinyerp.com-20081212000209-ak5e4ibl21jlv2tx --- addons/base_contact/base_contact.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/base_contact/base_contact.py b/addons/base_contact/base_contact.py index d24b9bde649..12df255c5e6 100644 --- a/addons/base_contact/base_contact.py +++ b/addons/base_contact/base_contact.py @@ -59,10 +59,10 @@ class res_partner_contact(osv.osv): res = [] for r in self.read(cr, user, ids, ['name','first_name','title']): addr = r['title'] and str(r['title'])+" " or '' - addr +=str(r['name'] or '') + addr += r.get('name', '') if r['name'] and r['first_name']: addr += ' ' - addr += str(r['first_name'] or '') + addr += r.get('first_name', '') res.append((r['id'], addr)) return res res_partner_contact() @@ -79,7 +79,7 @@ class res_partner_address(osv.osv): res.append((r['id'], r['partner_id'][1])) else: addr = str('') - addr += str(r['street'] or '') + ' ' + str(r['zip'] or '') + ' ' + str(r['city'] or '') + addr += "%s %s %s" % ( r.get('street', ''), r.get('zip', ''), r.get('city', '') ) res.append((r['id'], addr.strip() or '/')) return res From 38df72d010f490aef64f5379e60ded510d0b9283 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Fri, 12 Dec 2008 01:28:15 +0100 Subject: [PATCH 092/137] [FIX] Check if dirname is empty or not lp bug: https://launchpad.net/bugs/301983 fixed bzr revid: stephane@tinyerp.com-20081212002815-hcc325x6gjp66lpg --- bin/netsvc.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/bin/netsvc.py b/bin/netsvc.py index 9072421c0b7..a0253c867da 100644 --- a/bin/netsvc.py +++ b/bin/netsvc.py @@ -157,13 +157,12 @@ def init_logger(): if config['logfile']: logf = config['logfile'] - # test if the directories exist, else create them try: dirname = os.path.dirname(logf) - if not os.path.isdir(dirname): - res = os.makedirs(dirname) + if dirname and not os.path.isdir(dirname): + os.makedirs(dirname) handler = logging.handlers.TimedRotatingFileHandler(logf,'D',1,30) - except: + except Exception, ex: sys.stderr.write("ERROR: couldn't create the logfile directory\n") handler = logging.StreamHandler(sys.stdout) else: From 4c29b48db7fade62cc87b858b7feecd63a0ff1a5 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Fri, 12 Dec 2008 01:53:47 +0100 Subject: [PATCH 093/137] [FIX] Specify the osv class for the except_osv exception lp bug: https://launchpad.net/bugs/307319 fixed bzr revid: stephane@tinyerp.com-20081212005347-o71d4vzfrogih3xs --- addons/delivery/delivery.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/delivery/delivery.py b/addons/delivery/delivery.py index 320560dd0a8..b33fff49b85 100644 --- a/addons/delivery/delivery.py +++ b/addons/delivery/delivery.py @@ -21,7 +21,7 @@ ############################################################################## import time import netsvc -from osv import fields,osv,orm +from osv import fields,osv from tools.translate import _ class delivery_carrier(osv.osv): @@ -124,7 +124,7 @@ class delivery_grid(osv.osv): ok = True break if not ok: - raise except_osv(_('No price avaible !'), _('No line matched this order in the choosed delivery grids !')) + raise osv.except_osv(_('No price avaible !'), _('No line matched this order in the choosed delivery grids !')) return price From 0cc9056f9bff5307e8e49340190a96508a444a2a Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Fri, 12 Dec 2008 01:55:57 +0100 Subject: [PATCH 094/137] [FIX] Typo bzr revid: stephane@tinyerp.com-20081212005557-u8e9u6ai78maeyh4 --- addons/delivery/delivery.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/delivery/delivery.py b/addons/delivery/delivery.py index b33fff49b85..2ff5c122472 100644 --- a/addons/delivery/delivery.py +++ b/addons/delivery/delivery.py @@ -124,7 +124,7 @@ class delivery_grid(osv.osv): ok = True break if not ok: - raise osv.except_osv(_('No price avaible !'), _('No line matched this order in the choosed delivery grids !')) + raise osv.except_osv(_('No price available !'), _('No line matched this order in the choosed delivery grids !')) return price From d08f820ca295f6b0e4adf4ecf5d5bcccd33c8ff8 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Fri, 12 Dec 2008 02:19:20 +0100 Subject: [PATCH 095/137] [FIX] Patch from the debian repository lp bug: https://launchpad.net/bugs/303130 fixed bzr revid: stephane@tinyerp.com-20081212011920-a3wgsu5pq793t8r4 --- addons/auction/barcode/test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/auction/barcode/test.py b/addons/auction/barcode/test.py index 5bbd508184d..d22df49b08d 100644 --- a/addons/auction/barcode/test.py +++ b/addons/auction/barcode/test.py @@ -1,4 +1,4 @@ -#!/usr/pkg/bin/python +#!/usr/bin/python from common import * from code39 import * from code93 import * @@ -52,4 +52,4 @@ def run(): if __name__=='__main__': run() - \ No newline at end of file + From a004d7b55f400801633220aa32196bd31a28837b Mon Sep 17 00:00:00 2001 From: apa-tiny Date: Fri, 12 Dec 2008 10:28:02 +0530 Subject: [PATCH 096/137] modified Technical guide report with sxw and rml both bzr revid: patelamit2003@gmail.com-20081212045802-2e9d2w1ha0vw1blf --- .../module/report/ir_module_reference.rml | 214 ++++++++++-------- .../module/report/ir_module_reference.sxw | Bin 12192 -> 13249 bytes 2 files changed, 125 insertions(+), 89 deletions(-) diff --git a/bin/addons/base/module/report/ir_module_reference.rml b/bin/addons/base/module/report/ir_module_reference.rml index 811436ea29c..c047e1127b0 100644 --- a/bin/addons/base/module/report/ir_module_reference.rml +++ b/bin/addons/base/module/report/ir_module_reference.rml @@ -13,57 +13,62 @@ - - - - - - - + - - - - - + + + + + + + + + + + + + + + + - + - - - - + + + + + + + + + + + + + + + + - - - - - + - + + + - - - - - - - - - - - + @@ -72,6 +77,28 @@ + + + + + + + + + + + + + + + + + + + + + + @@ -81,28 +108,28 @@ - + - Reference Guide + Reference Guide - + - [[ company.name ]] + [[ company.name ]] - Introspection report on objects + Introspection report on objects - Printed: [[ time.strftime('%y-%m-%d')]] + Printed: [[ time.strftime('%y-%m-%d')]] @@ -111,77 +138,86 @@
[[ repeatIn(objects, 'module') ]] - + - Module: [[ module.name ]] + Module + + + Name + + + Version + + + Directory + + + Web - + - Name: [[ module.shortdesc]] + [[ module.name ]] - Version: [[module.latest_version]] - - - - - Directory: [[ module.name ]] + [[ module.shortdesc]] - Web: [[ module.website ]] + [[module.latest_version]] + + + [[ module.name ]] + + + [[ module.website ]] - [[ format(module.description or '') ]] -

Menus

- [[ format(module.menus_by_module or '') ]] -

Reports

- [[ format(module.reports_by_module or '') ]] -

Views

- [[ format(module.views_by_module or '') ]] -

Objects

+ + + + [[ module.description ]]
- [[ repeatIn(findobj(module.name) ,'object') ]] + + + + [[ repeatIn(findobj(module.name) ,'object') ]] + + + - Object: [[ object.model ]] - Description : [[ object.name ]] - [[ format(objdoc(object.model)) ]] + Object: [[ object.name ]] [[ objdoc(object.model) ]] - - - - [[ repeatIn(findflds(object.model), 'field') ]] [[ field[0] ]] - - - [[ field[1].get('string', 'Unknown') ]], [[ field[1]['type'] ]] [[field[1].get('required',False) and ', required']] [[field[1].get('readonly',False) and ', readonly']] - [[ field[1].get('help', '') ]] - - - - - - +
+ + + +
+
+ [[ repeatIn(findflds(object.model), 'field') ]] + + + + [[ field[0] ]] + + + [[ field[1].get('string', 'Unknown') ]], [[ field[1]['type'] ]] [[field[1].get('required',False) and ', required']] [[field[1].get('readonly',False) and ', readonly']] + [[ field[1].get('help', '') ]] + + + + + + +
- - - - - - - - -
- - -
diff --git a/bin/addons/base/module/report/ir_module_reference.sxw b/bin/addons/base/module/report/ir_module_reference.sxw index b97959a8d0a33014944160c4a2c8f38e513eebb6..a82a82fb2fdac25030ac53db4943a67f029467bd 100644 GIT binary patch literal 13249 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 X3esTUzfVK>^*R3p1k}#(yY{~TmQrxP literal 12192 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ⅅvYvc^Hr|ukrb;Hsu;T?48XEEV}j7pioYtn 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 Date: Fri, 12 Dec 2008 10:37:38 +0530 Subject: [PATCH 097/137] fix-bug for action write object provides help for the model_id and record_id fields bzr revid: mga@tinyerp.com-20081212050738-z2hmzylp2bvls2gq --- bin/addons/base/ir/ir_actions.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/bin/addons/base/ir/ir_actions.py b/bin/addons/base/ir/ir_actions.py index 0bd04398bb9..b7979112332 100644 --- a/bin/addons/base/ir/ir_actions.py +++ b/bin/addons/base/ir/ir_actions.py @@ -394,9 +394,9 @@ class actions_server(osv.osv): 'child_ids': fields.one2many('ir.actions.actions', 'parent_id', 'Others Actions'), 'usage': fields.char('Action Usage', size=32), 'type': fields.char('Report Type', size=32, required=True), - 'srcmodel_id': fields.many2one('ir.model', 'Model'), + 'srcmodel_id': fields.many2one('ir.model', 'Model', help="In which object you want to create / write the object if its empty refer to the Object field"), 'fields_lines': fields.one2many('ir.server.object.lines', 'server_id', 'Fields Mapping'), - 'record_id':fields.many2one('ir.model.fields', 'Record Id') + 'record_id':fields.many2one('ir.model.fields', 'Record Id', help="privide the field name from where the record id refers, if its empty it will refer to the active id of the object") } _defaults = { 'state': lambda *a: 'dummy', @@ -555,9 +555,13 @@ class actions_server(osv.osv): expr = exp.value res[exp.col1.name] = expr - if not action.srcmodel_id: - obj_pool = self.pool.get(action.model_id.model) - obj_pool.write(cr, uid, [context.get('active_id')], res) + if not action.record_id: + if not action.srcmodel_id: + obj_pool = self.pool.get(action.model_id.model) + obj_pool.write(cr, uid, [context.get('active_id')], res) + else: + obj_pool = self.pool.get(action.srcmodel_id.model) + obj_pool.write(cr, uid, [context.get('active_id')], res) else: obj_pool = self.pool.get(action.srcmodel_id.model) id = self.pool.get(action.model_id.model).read(cr, uid, [context.get('active_id')], [action.record_id.name]) From 5be3b32b54053cbac295724d1d12653e9ebf41d8 Mon Sep 17 00:00:00 2001 From: Husen Daudi Date: Fri, 12 Dec 2008 11:27:18 +0530 Subject: [PATCH 098/137] bugfix bzr revid: hda@tinyerp.com-20081212055718-164wjv8vr7v9oeba --- bin/addons/base/rng/view.rng | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/addons/base/rng/view.rng b/bin/addons/base/rng/view.rng index a02a3f3d680..432161bde38 100644 --- a/bin/addons/base/rng/view.rng +++ b/bin/addons/base/rng/view.rng @@ -260,6 +260,7 @@ + @@ -315,6 +316,7 @@ + From 818bfe81264938736dfde070358c21fdd229e73c Mon Sep 17 00:00:00 2001 From: Naresh Choksy Date: Fri, 12 Dec 2008 11:34:51 +0530 Subject: [PATCH 099/137] bugfix: for xml bzr revid: nch@tinyerp.com-20081212060451-gt8d5gbnpvh5xn31 --- bin/addons/base/rng/view.rng | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bin/addons/base/rng/view.rng b/bin/addons/base/rng/view.rng index 432161bde38..4dbfa512a14 100644 --- a/bin/addons/base/rng/view.rng +++ b/bin/addons/base/rng/view.rng @@ -61,6 +61,10 @@ + + + + @@ -229,6 +233,7 @@ + @@ -295,6 +300,7 @@ + From 36770d1cadd9721cc18846fa68ee3ecc7456907a Mon Sep 17 00:00:00 2001 From: Jay Vora Date: Fri, 12 Dec 2008 11:52:24 +0530 Subject: [PATCH 100/137] Minor edit in logger error message. bzr revid: jvo@tinyerp.com-20081212062224-qwa5i5jaw4jbn260 --- bin/addons/base/ir/ir_ui_view.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/addons/base/ir/ir_ui_view.py b/bin/addons/base/ir/ir_ui_view.py index 30ec2135b3d..afe4990aefc 100644 --- a/bin/addons/base/ir/ir_ui_view.py +++ b/bin/addons/base/ir/ir_ui_view.py @@ -33,7 +33,7 @@ def _check_xml(self, cr, uid, ids, context={}): relaxng = etree.RelaxNG(file=frng) if not relaxng.validate(eview): logger = netsvc.Logger() - logger.notifyChannel('init', netsvc.LOG_ERROR, 'The view do not fit the required schema !') + logger.notifyChannel('init', netsvc.LOG_ERROR, 'The view does not fit the required schema !') logger.notifyChannel('init', netsvc.LOG_ERROR, relaxng.error_log.last_error) return False return True From 059739ca8618c771aa07de3fc4913f40d63ef263 Mon Sep 17 00:00:00 2001 From: ashish Date: Fri, 12 Dec 2008 12:10:25 +0530 Subject: [PATCH 101/137] * Bug Fix bzr revid: ashish@ashish-laptop-20081212064025-fgxz8v3walwazppx --- bin/addons/base/rng/view.rng | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/bin/addons/base/rng/view.rng b/bin/addons/base/rng/view.rng index 4dbfa512a14..82ef44dd0f5 100644 --- a/bin/addons/base/rng/view.rng +++ b/bin/addons/base/rng/view.rng @@ -35,14 +35,13 @@ - - + @@ -61,10 +60,6 @@ - - - - @@ -219,7 +214,6 @@ - @@ -233,11 +227,10 @@ - + - @@ -245,7 +238,6 @@ - @@ -265,7 +257,6 @@ - @@ -288,7 +279,6 @@ - @@ -300,7 +290,6 @@ - From b337300737417cacb356844e70915f2cca9f85e3 Mon Sep 17 00:00:00 2001 From: Mantavya Gajjar Date: Fri, 12 Dec 2008 12:18:19 +0530 Subject: [PATCH 102/137] make changes in the execution of the * Trigger action * Workflow execution bzr revid: mga@tinyerp.com-20081212064819-c818maklfe33a18q --- bin/addons/base/ir/ir.xml | 2 +- bin/addons/base/ir/ir_actions.py | 32 +++++++++++++++++++++++++++----- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/bin/addons/base/ir/ir.xml b/bin/addons/base/ir/ir.xml index 4230d63c0b7..df73a5ea2d9 100644 --- a/bin/addons/base/ir/ir.xml +++ b/bin/addons/base/ir/ir.xml @@ -1151,7 +1151,7 @@ - + diff --git a/bin/addons/base/ir/ir_actions.py b/bin/addons/base/ir/ir_actions.py index b7979112332..b1ed5ebab22 100644 --- a/bin/addons/base/ir/ir_actions.py +++ b/bin/addons/base/ir/ir_actions.py @@ -365,6 +365,23 @@ server_object_lines() # Actions that are run on the server side # class actions_server(osv.osv): + + def _select_signals(self, cr, uid, context={}): + cr.execute("select distinct t.signal as key, t.signal || ' - [ ' || w.osv || ' ] ' as val from wkf w, wkf_activity a, wkf_transition t "\ + " where w.id = a.wkf_id " \ + " and t.act_from = a.wkf_id " \ + " or t.act_to = a.wkf_id ") + return cr.fetchall() + + def on_trigger_obj_id(self, cr, uid, ids, context={}): + cr.execute("select distinct t.signal as key, t.signal as val from wkf w, wkf_activity a, wkf_transition t "\ + " where w.id = a.wkf_id " \ + " and t.act_from = a.wkf_id " \ + " or t.act_to = a.wkf_id " \ + " and w.osv = %s ", ('account.invoice')) + data = cr.fetchall() + return {"values":{'trigger_name':data}} + _name = 'ir.actions.server' _table = 'ir_act_server' _sequence = 'ir_actions_id_seq' @@ -385,8 +402,8 @@ class actions_server(osv.osv): 'sequence': fields.integer('Sequence'), 'model_id': fields.many2one('ir.model', 'Object', required=True), 'action_id': fields.many2one('ir.actions.actions', 'Client Action'), - 'trigger_name': fields.char('Trigger Name', size=128), - 'trigger_obj_id': fields.reference('Trigger On', selection=model_get, size=128), + 'trigger_name': fields.selection(_select_signals, string='Trigger Name', size=128), + 'trigger_obj_id': fields.many2one('ir.model.fields','Trigger On'), 'email': fields.many2one('ir.model.fields', 'Contact'), 'message': fields.text('Message', translate=True), 'mobile': fields.many2one('ir.model.fields', 'Contact'), @@ -477,10 +494,12 @@ class actions_server(osv.osv): def run(self, cr, uid, ids, context={}): logger = netsvc.Logger() for action in self.browse(cr, uid, ids, context): + if action.state=='client_action': if not action.action_id: raise osv.except_osv(_('Error'), _("Please specify an action to launch !")) return self.pool.get(action.action_id.type).read(cr, uid, action.action_id.id, context=context) + if action.state=='python': localdict = { 'self': self.pool.get(action.model_id.model), @@ -512,8 +531,11 @@ class actions_server(osv.osv): if action.state == 'trigger': wf_service = netsvc.LocalService("workflow") res = str(action.trigger_obj_id).split(',') - model = res[0] - id = res[1] + + model = action.model_id.model + obj_pool = self.pool.get(action.model_id.model) + res_id = self.pool.get(action.model_id.model).read(cr, uid, [context.get('active_id')], [action.trigger_obj_id.name]) + id = res_id [0][action.trigger_obj_id.name] wf_service.trg_validate(uid, model, int(id), action.trigger_name, cr) if action.state == 'sms': @@ -527,6 +549,7 @@ class actions_server(osv.osv): logger.notifyChannel('sms', netsvc.LOG_INFO, 'SMS successfully send to : %s' % (action.address)) else: logger.notifyChannel('sms', netsvc.LOG_ERROR, 'Failed to send SMS to : %s' % (action.address)) + if action.state == 'other': localdict = { 'self': self.pool.get(action.model_id.model), @@ -536,7 +559,6 @@ class actions_server(osv.osv): 'cr': cr, 'uid': uid } - for act in action.child_ids: code = """action = {'model':'%s','type':'%s', %s}""" % (action.model_id.model, act.type, act.usage) exec code in localdict From 218e81ac7e6ae75e4a0935827699f4df94bf972b Mon Sep 17 00:00:00 2001 From: apa-tiny Date: Fri, 12 Dec 2008 12:56:02 +0530 Subject: [PATCH 103/137] space added between city and zip code in sale order-vir bzr revid: patelamit2003@gmail.com-20081212072602-5l43vxw2b7iy0vkv --- addons/sale/report/order.rml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/addons/sale/report/order.rml b/addons/sale/report/order.rml index 26f3e8a2cd8..e9b42811414 100644 --- a/addons/sale/report/order.rml +++ b/addons/sale/report/order.rml @@ -144,14 +144,15 @@ [[ o.partner_shipping_id.title or '' ]][[ o.partner_shipping_id.name ]] [[ o.partner_shipping_id.street ]] [[ o.partner_shipping_id.street2 or '' ]] - [[ o.partner_shipping_id.city or '' ]][[ o.partner_shipping_id.zip or '' ]] + [[ o.partner_shipping_id.city or '' ]] [[ o.partner_shipping_id.zip or '' ]] [[ o.partner_shipping_id.state_id and o.partner_shipping_id.state_id.name or '' ]][[ o.partner_shipping_id.country_id and o.partner_shipping_id.country_id.name or '' ]] Invoice address : [[ o.partner_invoice_id.street ]][[ o.partner_invoice_id.street2 and (', %s' % o.partner_invoice_id.street2 or '') ]] - [[ o.partner_invoice_id.zip or '' ]][[ o.partner_invoice_id.city or '' ]][[ o.partner_invoice_id.country_id and (', %s' % (o.partner_invoice_id.country_id and o.partner_invoice_id.country_id.name or '')) ]] + [[ o.partner_invoice_id.city or '' ]] [[ o.partner_invoice_id.zip or '' ]] + [[ o.partner_invoice_id.country_id and ('%s' % (o.partner_invoice_id.country_id and o.partner_invoice_id.country_id.name or '')) ]] @@ -163,7 +164,7 @@ [[ o.partner_order_id.title or '' ]][[ o.partner_order_id.name ]] [[ o.partner_order_id.street ]] [[ o.partner_order_id.street2 or '' ]] - [[ o.partner_order_id.zip or '' ]][[ o.partner_order_id.city or '' ]] + [[ o.partner_order_id.city or '' ]] [[ o.partner_order_id.zip or '' ]] [[ o.partner_order_id.state_id and o.partner_order_id.state_id.name or '' ]][[ o.partner_order_id.country_id and o.partner_order_id.country_id.name or '' ]] From c2b1676848fa10c7c14b6e8be642cc39286cc6df Mon Sep 17 00:00:00 2001 From: Jay Vora Date: Fri, 12 Dec 2008 14:19:39 +0530 Subject: [PATCH 104/137] Upgraded l10n_chart_uk_minimal,bugfixed charts creation. bzr revid: jvo@tinyerp.com-20081212084939-6sc6e4iovqevzhr7 --- addons/account/account.py | 6 +- addons/l10n_chart_uk_minimal/__terp__.py | 4 +- .../l10n_chart_uk_minimal/account_chart.xml | 283 +++----------- addons/l10n_chart_uk_minimal/account_tax.xml | 363 ++++-------------- .../l10n_chart_uk_minimal/account_types.xml | 60 +++ .../l10n_chart_uk_minimal/l10n_uk_wizard.xml | 14 + 6 files changed, 225 insertions(+), 505 deletions(-) create mode 100644 addons/l10n_chart_uk_minimal/account_types.xml create mode 100644 addons/l10n_chart_uk_minimal/l10n_uk_wizard.xml diff --git a/addons/account/account.py b/addons/account/account.py index 5908fa737e0..5fd45977905 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -1994,9 +1994,9 @@ class wizard_multi_charts_accounts(osv.osv_memory): #create the account_account dig = obj_multi.code_digits - code_main = len(account_template.code) - code_acc = account_template.code - if code_main<=dig and account_template.type != 'view': + code_main = account_template.code and len(account_template.code) or 0 + code_acc = account_template.code or '' + if code_main>0 and code_main<=dig and account_template.type != 'view': code_acc=str(code_acc) + (str('0'*(dig-code_main))) vals={ 'name': (obj_acc_root.id == account_template.id) and obj_multi.company_id.name or account_template.name, diff --git a/addons/l10n_chart_uk_minimal/__terp__.py b/addons/l10n_chart_uk_minimal/__terp__.py index fc998f167cf..94da21b59ac 100644 --- a/addons/l10n_chart_uk_minimal/__terp__.py +++ b/addons/l10n_chart_uk_minimal/__terp__.py @@ -66,8 +66,8 @@ "depends" : ["base", "account", "base_iban", "base_vat", "account_chart"], "init_xml" : [], "demo_xml" : [], - "update_xml" : ["account_chart.xml", - "account_tax.xml"], + "update_xml" : ["account_types.xml","account_chart.xml", + "account_tax.xml","l10n_uk_wizard.xml"], "installable": True } diff --git a/addons/l10n_chart_uk_minimal/account_chart.xml b/addons/l10n_chart_uk_minimal/account_chart.xml index 683252462f3..507c836c7e2 100755 --- a/addons/l10n_chart_uk_minimal/account_chart.xml +++ b/addons/l10n_chart_uk_minimal/account_chart.xml @@ -1,345 +1,186 @@ - - - - - - - - - - + + 0 - Account Chart UK - - view - - + - - - - - - + Balance Sheet - - view - - + - - - - + Fixed Assets - - view - - + - - - - + Fixed Asset Account - - - asset - - + other + - - - - + Net Current Assets - - view - - + - - - - + Current Assets - - view - - + - - - - + - Purchased Stocks - - - asset - - + other + - - - - + - Debtors - - receivable - - - + - - + - - - - - - + Output VAT - - - tax - - + other + - - - - + Bank Current Account - - - cash - - + other + - - - - + - Cash - - - cash - - + other + - - - - + Current Liabilities - - view - - + - - - - + - Creditors - - payable - - - + - - + - - - - - - + Input VAT - - - tax - - + other + - - - - - - + Profit and Loss - - view - - + - - - - + Revenue - - view - - + - - - - + - Product Sales - - - income - - + other + - - + - - - - - - + Cost of Sales - - view - - + - - - - + - Cost of Goods Sold - - - expense - - + other + - - - - + Overheads - - view - - + - - - - + - Expenses - - - expense - - + other + - - - + + + - - - diff --git a/addons/l10n_chart_uk_minimal/account_tax.xml b/addons/l10n_chart_uk_minimal/account_tax.xml index c1b254865c7..f9064116d96 100755 --- a/addons/l10n_chart_uk_minimal/account_tax.xml +++ b/addons/l10n_chart_uk_minimal/account_tax.xml @@ -1,444 +1,249 @@ - - - - - - - - - - - - - VAT balance to pay - + + Plan Fees UK + + VAT Balance to Pay + + - - - + Input VAT - - - - - - - Input VAT rate S (17.5%) - + + Input VAT Rate S (17.5%) - - - - - - Input VAT rate R (5%) - + + Input VAT Rate R (5%) - - - - - - - + Output VAT - - - - - - - Output VAT rate S (17.5%) - + + Output VAT Rate S (17.5%) - - - - - - Output VAT rate R (5%) - + + Output VAT Rate R (5%) - - - - - - - - - - Tax bases - + + Tax Bases + - - - - - Taxable purchases base - + + Taxable Purchases Base - - - - - - Taxable purchases rated S (17.5%) - + + Taxable Purchases Rated S (17.5%) - - - - - - Taxable purchases rated R (5%) - + + Taxable Purchases Rated R (5%) - - - - - - Taxable purchases rated Z (0%) - + + Taxable Purchases Rated Z (0%) - - - - - - Taxable purchases type X (Exempt) - + + Taxable Purchases Type X (Exempt) - - - - - - Taxable purchases type O (Out of scope) - + + Taxable Purchases Type O (Out of scope) - - - - - - - - Base of taxable sales - + + Base of Taxable Sales - - - - - - Taxable sales rated S (17.5%) - + + Taxable Sales Rated S (17.5%) - - - - - - Taxable sales rated R (5%) - + + Taxable Sales Rated R (5%) - - - - - - Taxable sales rated Z (0%) - + + Taxable Sales Rated Z (0%) - - - - - - Taxable sales type X (Exempt) - + + Taxable Sales Type X (Exempt) - - - - - - Taxable sales type O (Out of scope) - + + Taxable Sales Type O (Out of scope) - + - - + + UK Account Chart Template + + + + + + + + - - - - - - - + + IVAT S - - percent - - - - - + + - - - - - - - - + + IVAT R - - percent - - - - - + + - - - - - - - - + + IVAT Z - - percent - - - - - - - + + IVAT X - - percent - - - - - - - + + IVAT O - - percent - - - - - - + - - - - + + OVAT S - - percent - - - - - + + - - - - - - - - + + OVAT R - - percent - - - - - + + - - - - - - - - + + OVAT Z - - percent - - - - - - - + + OVAT X - - percent - - - - - - - + + OVAT O - - percent - - - - - - - - - + \ No newline at end of file diff --git a/addons/l10n_chart_uk_minimal/account_types.xml b/addons/l10n_chart_uk_minimal/account_types.xml new file mode 100644 index 00000000000..51040cadbbd --- /dev/null +++ b/addons/l10n_chart_uk_minimal/account_types.xml @@ -0,0 +1,60 @@ + + + + + + Receivable + receivable + unreconciled + + + + Payable + payable + unreconciled + + + + View + view + none + + + + Income + income + none + + + + Expense + expense + none + + + + Tax + tax + unreconciled + + + + Cash + cash + balance + + + + Asset + asset + balance + + + + Equity + equity + balance + + + + diff --git a/addons/l10n_chart_uk_minimal/l10n_uk_wizard.xml b/addons/l10n_chart_uk_minimal/l10n_uk_wizard.xml new file mode 100644 index 00000000000..633209ae612 --- /dev/null +++ b/addons/l10n_chart_uk_minimal/l10n_uk_wizard.xml @@ -0,0 +1,14 @@ + + + + + + Generate Chart of Accounts from a Chart Template + Generate Chart of Accounts from a Chart Template. You will be asked to pass the name of the company, the chart template to follow, the no. of digits to generate the code for your accounts and Bank account, currency to create Journals. Thus,the pure copy of chart Template is generated. +This is the same wizard that runs from Financial Managament/Configuration/Financial Accounting/Financial Accounts/Generate Chart of Accounts from a Chart Template. + + open + + + + \ No newline at end of file From 2ded13c89e141995bd4f81e94a649732eff22c04 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Fri, 12 Dec 2008 11:51:23 +0100 Subject: [PATCH 105/137] [REF] refactor the debug decorator 'logged' bzr revid: christophe@tinyerp.com-20081212105123-f2tyuykyb6dy8icu --- bin/tools/misc.py | 48 +++++++++++++++++++---------------------------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/bin/tools/misc.py b/bin/tools/misc.py index 183f172d488..06a6654af69 100644 --- a/bin/tools/misc.py +++ b/bin/tools/misc.py @@ -688,40 +688,30 @@ def human_size(sz): i = i + 1 return "%0.2f %s" % (s, units[i]) -def logged(when): - import netsvc - def log(f, res, *args, **kwargs): - vector = ['Call -> function: %s' % f] +def logged(f): + from functools import wraps + + @wraps(f) + def wrapper(*args, **kwargs): + import netsvc + from pprint import pformat + + vector = ['Call -> function: %r' % f] for i, arg in enumerate(args): - vector.append( ' arg %02d: %r' % ( i, arg ) ) + vector.append(' arg %02d: %s' % (i, pformat(arg))) for key, value in kwargs.items(): - vector.append( ' kwarg %10s: %r' % ( key, value ) ) - vector.append( ' result: %r' % res ) - netsvc.Logger().notifyChannel('logged', netsvc.LOG_DEBUG, vector) + vector.append(' kwarg %10s: %s' % (key, pformat(value))) - def pre_logged(f): - def wrapper(*args, **kwargs): - res = f(*args, **kwargs) - log(f, res, *args, **kwargs) - return res - return wrapper + timeb4 = time.time() + res = f(*args, **kwargs) + + vector.append(' result: %s' % pformat(res)) + vector.append(' time delta: %s' % (time.time() - timeb4)) + #netsvc.Logger().notifyChannel('logged', netsvc.LOG_DEBUG, '\n'.join(vector)) + return res - def post_logged(f): - def wrapper(*args, **kwargs): - now = time.time() - res = None - try: - res = f(*args, **kwargs) - return res - finally: - log(f, res, *args, **kwargs) - netsvc.Logger().notifyChannel('logged', netsvc.LOG_DEBUG, "time delta: %s" % (time.time() - now)) - return wrapper + return wrapper - try: - return { "pre" : pre_logged, "post" : post_logged}[when] - except KeyError, e: - raise ValueError(e), "must to be 'pre' or 'post'" icons = map(lambda x: (x,x), ['STOCK_ABOUT', 'STOCK_ADD', 'STOCK_APPLY', 'STOCK_BOLD', 'STOCK_CANCEL', 'STOCK_CDROM', 'STOCK_CLEAR', 'STOCK_CLOSE', 'STOCK_COLOR_PICKER', From 71ed4e9e9ce75ab47bd1d08c6fcd8999000aa28f Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Fri, 12 Dec 2008 11:52:08 +0100 Subject: [PATCH 106/137] [FIX] handle correctly the '-i' command line switch bzr revid: christophe@tinyerp.com-20081212105208-i5o9w28su9h9olzv --- bin/addons/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bin/addons/__init__.py b/bin/addons/__init__.py index 95949633582..c1b454df07e 100644 --- a/bin/addons/__init__.py +++ b/bin/addons/__init__.py @@ -539,8 +539,9 @@ def load_modules(db, force_demo=False, status=None, update_module=False): modobj = pool.get('ir.module.module') modobj.update_list(cr, 1) - if tools.config['init']: - ids = modobj.search(cr, 1, ['&', ('state', '=', 'uninstalled'), ('name', 'in', tools.config['init'])]) + mods = [k for k in tools.config['init'] if tools.config['init'][k]] + if mods: + ids = modobj.search(cr, 1, ['&', ('state', '=', 'uninstalled'), ('name', 'in', mods)]) if ids: modobj.button_install(cr, 1, ids) From 0a9426cf068aa74c9c34a9f417564077da8130e6 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Fri, 12 Dec 2008 11:54:17 +0100 Subject: [PATCH 107/137] [IMP] the logging of the workflows is made with the logger bzr revid: christophe@tinyerp.com-20081212105417-up42ltvbothbibpt --- bin/workflow/wkf_logs.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/bin/workflow/wkf_logs.py b/bin/workflow/wkf_logs.py index 17e3bfb1471..72299da8099 100644 --- a/bin/workflow/wkf_logs.py +++ b/bin/workflow/wkf_logs.py @@ -23,9 +23,18 @@ # # May be uncommented to logs workflows modifications # +import netsvc def log(cr,ident,act_id,info=''): - pass + msg = """ +res_type: %r +res_id: %d +uid: %d +act_id: %d +info: %s +""" % (ident[1], ident[2], ident[0], act_id, info) + netsvc.Logger().notifyChannel('wkf_log', netsvc.LOG_DEBUG, msg) + #cr.execute('insert into wkf_logs (res_type, res_id, uid, act_id, time, info) values (%s,%s,%s,%s,current_time,%s)', (ident[1],int(ident[2]),int(ident[0]),int(act_id),info)) # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From a6a9f7382f89032ca0575bc5b0af84448c72057d Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Fri, 12 Dec 2008 11:58:04 +0100 Subject: [PATCH 108/137] [IMP] use the bultin function to strip the workflow action functions bzr revid: christophe@tinyerp.com-20081212105804-9yuf4ir04p5vy52r --- bin/workflow/wkf_expr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/workflow/wkf_expr.py b/bin/workflow/wkf_expr.py index 5c5858ccc3f..fff74884e3f 100644 --- a/bin/workflow/wkf_expr.py +++ b/bin/workflow/wkf_expr.py @@ -66,7 +66,7 @@ def _eval_expr(cr, ident, workitem, action): ret=False assert action, 'You used a NULL action in a workflow, use dummy node instead.' for line in action.split('\n'): - line = line.replace(chr(13),'') + line = line.strip() uid=ident[0] model=ident[1] ids=[ident[2]] From 6706f6b07be67aedab3c19ea91794fcb1acdbeaa Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Fri, 12 Dec 2008 11:59:27 +0100 Subject: [PATCH 109/137] [IMP] check that the cursor has not been closed before execute a query [REF] refactor the debug logging of the queries bzr revid: christophe@tinyerp.com-20081212105927-k9zet8xd2ubj5a4j --- bin/sql_db.py | 54 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/bin/sql_db.py b/bin/sql_db.py index cf9aa75ac4e..64dbaa0f9e2 100644 --- a/bin/sql_db.py +++ b/bin/sql_db.py @@ -60,14 +60,24 @@ class Cursor(object): sql_into_log = {} sql_log = False count = 0 + + def check(f): + from functools import wraps + @wraps(f) + def wrapper(self, *args, **kwargs): + if not hasattr(self, '_obj'): + raise Exception('Unable to use the cursor after having closing it') + return f(self, *args, **kwargs) + return wrapper def __init__(self, pool): self._pool = pool self._cnx = pool.getconn() - self.autocommit(False) self._obj = self._cnx.cursor(cursor_factory=psycopg1cursor) + self.autocommit(False) self.dbname = pool.dbname - + + @check def execute(self, query, params=None): if params is None: params=() @@ -91,12 +101,11 @@ class Cursor(object): if self.sql_log: now = mdt.now() - log("SQL LOG query: %s" % (query,)) - log("SQL LOG params: %r" % (p,)) res = self._obj.execute(query, p or None) if self.sql_log: + log("query: %s" % self._obj.query) self.count+=1 res_from = re_from.match(query.lower()) if res_from: @@ -110,23 +119,26 @@ class Cursor(object): self.sql_into_log[res_into.group(1)][1] += mdt.now() - now return res - def print_log(self, type='from'): - log("SQL LOG %s:" % (type,)) - if type == 'from': - logs = self.sql_from_log.items() - else: - logs = self.sql_into_log.items() - logs.sort(lambda x, y: cmp(x[1][1], y[1][1])) - sum=0 - for r in logs: - log("table: %s: %s/%s" %(r[0], str(r[1][1]), r[1][0])) - sum+= r[1][1] - log("SUM:%s/%d" % (sum, self.count)) + def print_log(self): + def process(type): + sqllogs = {'from':self.sql_from_log, 'into':self.sql_into_log} + if not sqllogs[type]: + return + sqllogitems = sqllogs[type].items() + sqllogitems.sort(key=lambda k: k[1][1]) + sum = 0 + log("SQL LOG %s:" % (type,)) + for r in sqllogitems: + log("table: %s: %s/%s" %(r[0], str(r[1][1]), r[1][0])) + sum+= r[1][1] + log("SUM:%s/%d" % (sum, self.count)) + sqllogs[type].clear() + process('from') + process('into') + @check def close(self): - if self.sql_from_log or self.sql_into_log: - self.print_log('from') - self.print_log('into') + self.print_log() self._obj.close() # This force the cursor to be freed, and thus, available again. It is @@ -137,15 +149,19 @@ class Cursor(object): del self._obj self._pool.putconn(self._cnx) + @check def autocommit(self, on): self._cnx.set_isolation_level([ISOLATION_LEVEL_SERIALIZABLE, ISOLATION_LEVEL_AUTOCOMMIT][bool(on)]) + @check def commit(self): return self._cnx.commit() + @check def rollback(self): return self._cnx.rollback() + @check def __getattr__(self, name): return getattr(self._obj, name) From 5c0eb235a0827ad61e89b2d996f801800b6ac37e Mon Sep 17 00:00:00 2001 From: Mantavya Gajjar Date: Fri, 12 Dec 2008 17:18:54 +0530 Subject: [PATCH 110/137] improvement in the server action * make working the other actions bzr revid: mga@tinyerp.com-20081212114854-l36fcrs72180kuid --- bin/addons/base/ir/ir.xml | 8 ++++---- bin/addons/base/ir/ir_actions.py | 30 ++++++++++-------------------- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/bin/addons/base/ir/ir.xml b/bin/addons/base/ir/ir.xml index df73a5ea2d9..6cd10d7cc3a 100644 --- a/bin/addons/base/ir/ir.xml +++ b/bin/addons/base/ir/ir.xml @@ -151,7 +151,6 @@ - @@ -1143,15 +1142,16 @@ - + - + + diff --git a/bin/addons/base/ir/ir_actions.py b/bin/addons/base/ir/ir_actions.py index b1ed5ebab22..5ac38dd55b9 100644 --- a/bin/addons/base/ir/ir_actions.py +++ b/bin/addons/base/ir/ir_actions.py @@ -34,7 +34,6 @@ class actions(osv.osv): 'name': fields.char('Action Name', required=True, size=64), 'type': fields.char('Action Type', required=True, size=32), 'usage': fields.char('Action Usage', size=32), - 'parent_id': fields.many2one('ir.actions.server', 'Parent Action'), } _defaults = { 'usage': lambda *a: False, @@ -290,7 +289,7 @@ class ir_model_fields(osv.osv): 'complete_name': fields.char('Complete Name', size=64, select=1), } - def name_search(self, cr, uid, name, args=None, operator='ilike', context=None, limit=80): + def name_search(self, cr, uid, name, args=None, operator='ilike', context=None, limit=800): def get_fields(cr, uid, field, rel): result = [] mobj = self.pool.get('ir.model') @@ -389,7 +388,6 @@ class actions_server(osv.osv): 'name': fields.char('Action Name', required=True, size=64), 'state': fields.selection([ ('client_action','Client Action'), - ('python','Python Code'), ('dummy','Dummy'), ('trigger','Trigger'), ('email','Email'), @@ -403,12 +401,13 @@ class actions_server(osv.osv): 'model_id': fields.many2one('ir.model', 'Object', required=True), 'action_id': fields.many2one('ir.actions.actions', 'Client Action'), 'trigger_name': fields.selection(_select_signals, string='Trigger Name', size=128), + 'wkf_model_id': fields.many2one('ir.model', 'Workflow on'), 'trigger_obj_id': fields.many2one('ir.model.fields','Trigger On'), 'email': fields.many2one('ir.model.fields', 'Contact'), 'message': fields.text('Message', translate=True), 'mobile': fields.many2one('ir.model.fields', 'Contact'), 'sms': fields.char('SMS', size=160, translate=True), - 'child_ids': fields.one2many('ir.actions.actions', 'parent_id', 'Others Actions'), + 'child_ids': fields.many2many('ir.actions.server', 'rel_server_actions', 'server_id', 'action_id', 'Others Actions'), 'usage': fields.char('Action Usage', size=32), 'type': fields.char('Report Type', size=32, required=True), 'srcmodel_id': fields.many2one('ir.model', 'Model', help="In which object you want to create / write the object if its empty refer to the Object field"), @@ -530,9 +529,7 @@ class actions_server(osv.osv): if action.state == 'trigger': wf_service = netsvc.LocalService("workflow") - res = str(action.trigger_obj_id).split(',') - - model = action.model_id.model + model = action.wkf_model_id.model obj_pool = self.pool.get(action.model_id.model) res_id = self.pool.get(action.model_id.model).read(cr, uid, [context.get('active_id')], [action.trigger_obj_id.name]) id = res_id [0][action.trigger_obj_id.name] @@ -551,19 +548,12 @@ class actions_server(osv.osv): logger.notifyChannel('sms', netsvc.LOG_ERROR, 'Failed to send SMS to : %s' % (action.address)) if action.state == 'other': - localdict = { - 'self': self.pool.get(action.model_id.model), - 'context': context, - 'time': time, - 'ids': ids, - 'cr': cr, - 'uid': uid - } + res = None for act in action.child_ids: - code = """action = {'model':'%s','type':'%s', %s}""" % (action.model_id.model, act.type, act.usage) - exec code in localdict - if 'action' in localdict: - return localdict['action'] + result = self.run(cr, uid, [act.id], context) + if result: + res = result + return res if action.state == 'object_write': res = {} @@ -588,7 +578,7 @@ class actions_server(osv.osv): obj_pool = self.pool.get(action.srcmodel_id.model) id = self.pool.get(action.model_id.model).read(cr, uid, [context.get('active_id')], [action.record_id.name]) obj_pool.write(cr, uid, [int(id[0][action.record_id.name])], res) - + if action.state == 'object_create': res = {} for exp in action.fields_lines: From a9e72045339b2040686bf72e3ecf9146b6793798 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Fri, 12 Dec 2008 12:49:45 +0100 Subject: [PATCH 111/137] [FIX] fix bug with functools on python 2.4 bzr revid: christophe@tinyerp.com-20081212114945-jh7djsx6dv8sr1kh --- bin/sql_db.py | 3 ++- bin/tools/func.py | 31 +++++++++++++++++++++++++++++++ bin/tools/misc.py | 2 +- 3 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 bin/tools/func.py diff --git a/bin/sql_db.py b/bin/sql_db.py index 64dbaa0f9e2..a63b2eff205 100644 --- a/bin/sql_db.py +++ b/bin/sql_db.py @@ -62,7 +62,8 @@ class Cursor(object): count = 0 def check(f): - from functools import wraps + from tools.func import wraps + @wraps(f) def wrapper(self, *args, **kwargs): if not hasattr(self, '_obj'): diff --git a/bin/tools/func.py b/bin/tools/func.py new file mode 100644 index 00000000000..96113e04072 --- /dev/null +++ b/bin/tools/func.py @@ -0,0 +1,31 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2008 Tiny SPRL (). All Rights Reserved +# $Id$ +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################## + +try: + from functools import wraps +except ImportError: + # this module doesn't exist in python < 2.5 + # we define a identity decorator + def wraps(f): + def identity(x): + return x + return identity diff --git a/bin/tools/misc.py b/bin/tools/misc.py index 06a6654af69..a5be66067da 100644 --- a/bin/tools/misc.py +++ b/bin/tools/misc.py @@ -689,7 +689,7 @@ def human_size(sz): return "%0.2f %s" % (s, units[i]) def logged(f): - from functools import wraps + from tools.func import wraps @wraps(f) def wrapper(*args, **kwargs): From 381ad4fe1f0ca1fb9477a647edb291c0c58d5820 Mon Sep 17 00:00:00 2001 From: Najlaa Date: Fri, 12 Dec 2008 13:38:12 +0100 Subject: [PATCH 112/137] Correct view bzr revid: nel@silver-20081212123812-yfe1gjblbarlk7hx --- bin/addons/base/res/partner/partner_view.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/addons/base/res/partner/partner_view.xml b/bin/addons/base/res/partner/partner_view.xml index f910c1102f6..66c06a21ba1 100644 --- a/bin/addons/base/res/partner/partner_view.xml +++ b/bin/addons/base/res/partner/partner_view.xml @@ -183,7 +183,7 @@ form [('domain','=','partner')] - + Contacts Titles @@ -192,7 +192,7 @@ form [('domain','=','contact')] - + - UK Account Chart Template + UK Minimal Account Chart Template diff --git a/addons/l10n_chart_uk_minimal/l10n_uk_wizard.xml b/addons/l10n_chart_uk_minimal/l10n_uk_wizard.xml index 633209ae612..2ba2fa7478a 100644 --- a/addons/l10n_chart_uk_minimal/l10n_uk_wizard.xml +++ b/addons/l10n_chart_uk_minimal/l10n_uk_wizard.xml @@ -2,13 +2,13 @@ - - Generate Chart of Accounts from a Chart Template - Generate Chart of Accounts from a Chart Template. You will be asked to pass the name of the company, the chart template to follow, the no. of digits to generate the code for your accounts and Bank account, currency to create Journals. Thus,the pure copy of chart Template is generated. -This is the same wizard that runs from Financial Managament/Configuration/Financial Accounting/Financial Accounts/Generate Chart of Accounts from a Chart Template. - - open - + + Generate Chart of Accounts from a Chart Template + Generate Chart of Accounts from a Chart Template. You will be asked to pass the name of the company, the chart template to follow, the no. of digits to generate the code for your accounts and Bank account, currency to create Journals. Thus,the pure copy of chart Template is generated. + This is the same wizard that runs from Financial Managament/Configuration/Financial Accounting/Financial Accounts/Generate Chart of Accounts from a Chart Template. + + open + \ No newline at end of file From 05e4848cbdbbfaa4c946f6781b8c448798c3aa17 Mon Sep 17 00:00:00 2001 From: Husen Daudi Date: Fri, 12 Dec 2008 18:31:57 +0530 Subject: [PATCH 114/137] bugfix bzr revid: hda@tinyerp.com-20081212130157-mzmxcg1178l67zmy --- addons/base_contact/base_contact.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/base_contact/base_contact.py b/addons/base_contact/base_contact.py index 12df255c5e6..289b0b48dc7 100644 --- a/addons/base_contact/base_contact.py +++ b/addons/base_contact/base_contact.py @@ -62,7 +62,7 @@ class res_partner_contact(osv.osv): addr += r.get('name', '') if r['name'] and r['first_name']: addr += ' ' - addr += r.get('first_name', '') + addr += (r.get('first_name', '') or '') res.append((r['id'], addr)) return res res_partner_contact() From 6675a3709c84eb025f33ca1b27c581bd7493134f Mon Sep 17 00:00:00 2001 From: Husen Daudi Date: Fri, 12 Dec 2008 18:35:11 +0530 Subject: [PATCH 115/137] Implemented write method on fields.related bzr revid: hda@tinyerp.com-20081212130511-gcoovgqnkg0txde7 --- bin/osv/fields.py | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/bin/osv/fields.py b/bin/osv/fields.py index 9c2640bcc4c..b6b5dfa4930 100644 --- a/bin/osv/fields.py +++ b/bin/osv/fields.py @@ -654,8 +654,31 @@ class related(function): i -= 1 return [(self._arg[0], 'in', sarg)] - def _fnct_write(self,obj,cr, uid, ids,values, field_name, args, context=None): - raise 'Not Implemented Yet' + def _fnct_write(self,obj,cr, uid, ids, field_name, values, args, context=None): + if values and field_name: + self._field_get2(cr, uid, obj, context) + self._field_get2(cr, uid, obj, context) + relation = obj._name + res = {} + if type(ids) != type([]): + ids=[ids] + objlst = obj.browse(cr, uid, ids) + for data in objlst: + t_data = data + relation = obj._name + for i in range(len(self.arg)): + field_detail = self._relations[i] + relation = field_detail['object'] + if not t_data[self.arg[i]]: + t_data = False + break + if field_detail['type'] in ('one2many', 'many2many'): + t_id=t_data.id + t_data = t_data[self.arg[i]][0] + else: + t_id=t_data['id'] + t_data = t_data[self.arg[i]] + return obj.pool.get(field_detail['object']).write(cr,uid,t_id,{args[-1]:values}) def _fnct_read(self, obj, cr, uid, ids, field_name, args, context=None): self._field_get2(cr, uid, obj, context) @@ -685,7 +708,7 @@ class related(function): def __init__(self, *arg, **args): self.arg = arg self._relations = [] - super(related, self).__init__(self._fnct_read, arg, fnct_inv_arg=arg, method=True, fnct_search=self._fnct_search, **args) + super(related, self).__init__(self._fnct_read, arg, self._fnct_write, fnct_inv_arg=arg, method=True, fnct_search=self._fnct_search, **args) def _field_get2(self, cr, uid, obj, context={}): if self._relations: From 43f0fffd076a60cb53b0dc7831e12b34525ff17f Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Fri, 12 Dec 2008 14:24:16 +0100 Subject: [PATCH 116/137] [FIX] free the database connecion in all cases lp bug: https://launchpad.net/bugs/307069 fixed bzr revid: christophe@tinyerp.com-20081212132416-4kt1xh9nmka7r6a1 --- bin/sql_db.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/bin/sql_db.py b/bin/sql_db.py index a63b2eff205..e88c6b12efb 100644 --- a/bin/sql_db.py +++ b/bin/sql_db.py @@ -67,7 +67,7 @@ class Cursor(object): @wraps(f) def wrapper(self, *args, **kwargs): if not hasattr(self, '_obj'): - raise Exception('Unable to use the cursor after having closing it') + raise psycopg2.ProgrammingError('Unable to use the cursor after having closing it') return f(self, *args, **kwargs) return wrapper @@ -78,6 +78,16 @@ class Cursor(object): self.autocommit(False) self.dbname = pool.dbname + def __del__(self): + if hasattr(self, '_obj'): + # Oops. 'self' has not been closed explicitly. + # The cursor will be deleted by the garbage collector, + # but the database connection is not put back into the connection + # pool, preventing some operation on the database like dropping it. + # This can also lead to a server overload. + log('Cursor not closed explicitly', netsvc.LOG_WARNING) + self.close() + @check def execute(self, query, params=None): if params is None: @@ -136,6 +146,7 @@ class Cursor(object): sqllogs[type].clear() process('from') process('into') + self.count = 0 @check def close(self): From 3548ede420152290bd3a8e9cac714d07f3a55124 Mon Sep 17 00:00:00 2001 From: Jay Vora Date: Fri, 12 Dec 2008 19:14:51 +0530 Subject: [PATCH 117/137] [Correction] UK Account Chart:Standard VAT Rate changed to 15%(Ref:Gegard Geoff) bzr revid: jvo@tinyerp.com-20081212134451-t5ug9xx8m1yfu3mt --- addons/l10n_chart_uk_minimal/account_tax.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/addons/l10n_chart_uk_minimal/account_tax.xml b/addons/l10n_chart_uk_minimal/account_tax.xml index 5adaa4c0ea6..51d5c3f349f 100755 --- a/addons/l10n_chart_uk_minimal/account_tax.xml +++ b/addons/l10n_chart_uk_minimal/account_tax.xml @@ -24,7 +24,7 @@ - Input VAT Rate S (17.5%) + Input VAT Rate S (15%) @@ -41,7 +41,7 @@ - Output VAT Rate S (17.5%) + Output VAT Rate S (15%) @@ -65,7 +65,7 @@ - Taxable Purchases Rated S (17.5%) + Taxable Purchases Rated S (15%) @@ -97,7 +97,7 @@ - Taxable Sales Rated S (17.5%) + Taxable Sales Rated S (15%) @@ -140,7 +140,7 @@ IVAT S - + percent @@ -195,7 +195,7 @@ OVAT S - + percent From 5a38fc48991b4ab9aa8b42938a0b233702fca584 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Fri, 12 Dec 2008 15:14:36 +0100 Subject: [PATCH 118/137] [FIX] fix with detection of dependencies lp bug: https://launchpad.net/bugs/307393 fixed bzr revid: christophe@tinyerp.com-20081212141436-s3n6410mhuddm3ru --- bin/addons/__init__.py | 12 +++++++----- bin/addons/base/module/module.py | 4 ++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/bin/addons/__init__.py b/bin/addons/__init__.py index c1b454df07e..4734b1adc55 100644 --- a/bin/addons/__init__.py +++ b/bin/addons/__init__.py @@ -538,16 +538,18 @@ def load_modules(db, force_demo=False, status=None, update_module=False): modobj = pool.get('ir.module.module') modobj.update_list(cr, 1) - + mods = [k for k in tools.config['init'] if tools.config['init'][k]] if mods: ids = modobj.search(cr, 1, ['&', ('state', '=', 'uninstalled'), ('name', 'in', mods)]) if ids: modobj.button_install(cr, 1, ids) - - ids = modobj.search(cr, 1, ['&', '!', ('name', '=', 'base'), ('state', 'in', ('installed', 'to upgrade'))]) - if ids: - modobj.button_upgrade(cr, 1, ids) + + mods = [k for k in tools.config['update'] if tools.config['update'][k]] + if mods: + ids = modobj.search(cr, 1, ['&', '&',('state', '=', 'installed'), ('name', 'in', mods), '!', ('name', '=', 'base')]) + if ids: + modobj.button_upgrade(cr, 1, ids) cr.execute("select name from ir_module_module where state in ('installed', 'to install', 'to upgrade','to remove')") else: diff --git a/bin/addons/base/module/module.py b/bin/addons/base/module/module.py index 9a5ba75a57d..ef8a5865628 100644 --- a/bin/addons/base/module/module.py +++ b/bin/addons/base/module/module.py @@ -257,7 +257,7 @@ class module(osv.osv): _("Can not upgrade module '%s'. It is not installed.") % (mod.name,)) iids = depobj.search(cr, uid, [('name', '=', mod.name)], context=context) for dep in depobj.browse(cr, uid, iids, context=context): - if dep.module_id.state=='installed': + if dep.module_id.state=='installed' and dep.module_id not in todo: todo.append(dep.module_id) ids = map(lambda x: x.id, todo) @@ -271,7 +271,7 @@ class module(osv.osv): if dep.state == 'uninstalled': ids2 = self.search(cr, uid, [('name','=',dep.name)]) to_install.extend(ids2) - + self.button_install(cr, uid, to_install, context=context) return True From aa900102ec6b4980e3cabb1cca95ccff9cf9e489 Mon Sep 17 00:00:00 2001 From: Husen Daudi Date: Fri, 12 Dec 2008 19:49:53 +0530 Subject: [PATCH 119/137] Improvement bzr revid: hda@tinyerp.com-20081212141953-4ojs8a6i14ldizqh --- bin/osv/fields.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bin/osv/fields.py b/bin/osv/fields.py index b6b5dfa4930..390f6e2d802 100644 --- a/bin/osv/fields.py +++ b/bin/osv/fields.py @@ -656,7 +656,6 @@ class related(function): def _fnct_write(self,obj,cr, uid, ids, field_name, values, args, context=None): if values and field_name: - self._field_get2(cr, uid, obj, context) self._field_get2(cr, uid, obj, context) relation = obj._name res = {} @@ -664,6 +663,7 @@ class related(function): ids=[ids] objlst = obj.browse(cr, uid, ids) for data in objlst: + t_id=None t_data = data relation = obj._name for i in range(len(self.arg)): @@ -678,7 +678,8 @@ class related(function): else: t_id=t_data['id'] t_data = t_data[self.arg[i]] - return obj.pool.get(field_detail['object']).write(cr,uid,t_id,{args[-1]:values}) + if t_id: + obj.pool.get(field_detail['object']).write(cr,uid,t_id,{args[-1]:values}) def _fnct_read(self, obj, cr, uid, ids, field_name, args, context=None): self._field_get2(cr, uid, obj, context) From cb59d883b8809acd898e0703404cf15a25d4cef2 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Sat, 13 Dec 2008 07:01:18 +0100 Subject: [PATCH 120/137] bugfix_cache_speed_improvement_store bzr revid: fp@tinyerp.com-20081213060118-icn54am74m6ntyqw --- bin/addons/base/__terp__.py | 2 +- bin/addons/base/ir/ir_attachment.py | 4 +- bin/addons/base/ir/ir_model.py | 2 +- bin/addons/base/ir/ir_translation.py | 40 ++------- bin/addons/base/module/module.py | 6 +- bin/addons/base/res/res_user.py | 2 +- bin/osv/orm.py | 117 +++++++++++++++----------- bin/osv/osv.py | 119 --------------------------- bin/service/security.py | 10 --- bin/service/web_services.py | 22 +---- bin/tools/misc.py | 32 ++++--- bin/tools/translate.py | 6 +- 12 files changed, 107 insertions(+), 255 deletions(-) diff --git a/bin/addons/base/__terp__.py b/bin/addons/base/__terp__.py index 0411acccfe4..1e2e5f9985d 100644 --- a/bin/addons/base/__terp__.py +++ b/bin/addons/base/__terp__.py @@ -21,7 +21,7 @@ ############################################################################## { "name" : "Base", - "version" : "1.0", + "version" : "1.1", "author" : "Tiny", "website" : "http://www.openerp.com", "category" : "Generic Modules/Base", diff --git a/bin/addons/base/ir/ir_attachment.py b/bin/addons/base/ir/ir_attachment.py index e1a04a5f85a..10ff3275dca 100644 --- a/bin/addons/base/ir/ir_attachment.py +++ b/bin/addons/base/ir/ir_attachment.py @@ -36,9 +36,7 @@ class ir_attachment(osv.osv): for o in objs: if o and o.res_model: ima.check(cr, uid, o.res_model, mode) - - check = tools.cache()(check) - + def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False): ids = super(ir_attachment, self).search(cr, uid, args, offset=offset, diff --git a/bin/addons/base/ir/ir_model.py b/bin/addons/base/ir/ir_model.py index 4d42dd9411c..8df05b6b082 100644 --- a/bin/addons/base/ir/ir_model.py +++ b/bin/addons/base/ir/ir_model.py @@ -435,7 +435,7 @@ class ir_model_data(osv.osv): ids = self.search(cr, uid, [('module','=',module),('name','=', xml_id)]) assert len(ids)==1, '%d reference(s) to %s.%s. You should have one and only one !' % (len(ids), module, xml_id) return ids[0] - _get_id = tools.cache()(_get_id) + _get_id = tools.cache(skiparg=3)(_get_id) def _update_dummy(self,cr, uid, model, module, xml_id=False, store=True): if not xml_id: diff --git a/bin/addons/base/ir/ir_translation.py b/bin/addons/base/ir/ir_translation.py index dac4a550e45..a392a6c3702 100644 --- a/bin/addons/base/ir/ir_translation.py +++ b/bin/addons/base/ir/ir_translation.py @@ -21,7 +21,6 @@ ############################################################################## from osv import fields, osv -from osv.osv import Cacheable import tools TRANSLATION_TYPE = [ @@ -39,11 +38,12 @@ TRANSLATION_TYPE = [ ('constraint', 'Constraint'), ] -class ir_translation(osv.osv, Cacheable): +class ir_translation(osv.osv): _name = "ir.translation" _log_access = False def _get_language(self, cr, uid, context): + print '***', _get_language lang_obj = self.pool.get('res.lang') lang_ids = lang_obj.search(cr, uid, [('translatable', '=', True)], context=context) @@ -81,27 +81,19 @@ class ir_translation(osv.osv, Cacheable): cr.commit() def _get_ids(self, cr, uid, name, tt, lang, ids): - translations, to_fetch = {}, [] - for id in ids: - trans = self.get((lang, name, id)) - if trans is not None: - translations[id] = trans - else: - to_fetch.append(id) - if to_fetch: + translations = {} + if ids: cr.execute('select res_id,value ' \ 'from ir_translation ' \ 'where lang=%s ' \ 'and type=%s ' \ 'and name=%s ' \ - 'and res_id in ('+','.join(map(str, to_fetch))+')', + 'and res_id in ('+','.join(map(str, ids))+')', (lang,tt,name)) for res_id, value in cr.fetchall(): - self.add((lang, tt, name, res_id), value) translations[res_id] = value for res_id in ids: if res_id not in translations: - self.add((lang, tt, name, res_id), False) translations[res_id] = False return translations @@ -122,11 +114,8 @@ class ir_translation(osv.osv, Cacheable): }) return len(ids) + @tools.cache(skiparg=3) def _get_source(self, cr, uid, name, tt, lang, source=None): - trans = self.get((lang, tt, name, source)) - if trans is not None: - return trans - if source: #if isinstance(source, unicode): # source = source.encode('utf8') @@ -145,26 +134,9 @@ class ir_translation(osv.osv, Cacheable): 'and name=%s', (lang, tt, str(name))) res = cr.fetchone() - trad = res and res[0] or '' - self.add((lang, tt, name, source), trad) return trad - def unlink(self, cursor, user, ids, context=None): - self.clear() - return super(ir_translation, self).unlink(cursor, user, ids, - context=context) - - def create(self, cursor, user, vals, context=None): - self.clear() - return super(ir_translation, self).create(cursor, user, vals, - context=context) - - def write(self, cursor, user, ids, vals, context=None): - self.clear() - return super(ir_translation, self).write(cursor, user, ids, vals, - context=context) - ir_translation() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/bin/addons/base/module/module.py b/bin/addons/base/module/module.py index ef8a5865628..2fb77c926f0 100644 --- a/bin/addons/base/module/module.py +++ b/bin/addons/base/module/module.py @@ -169,9 +169,9 @@ class module(osv.osv): ('GPL-3 or any later version', 'GPL-3 or later version'), ('Other proprietary', 'Other proprietary') ], string='License', readonly=True), - 'menus_by_module': fields.function(_get_views, method=True, string='Menus', type='text', multi="meta"), - 'reports_by_module': fields.function(_get_views, method=True, string='Reports', type='text', multi="meta"), - 'views_by_module': fields.function(_get_views, method=True, string='Views', type='text', multi="meta"), + 'menus_by_module': fields.function(_get_views, method=True, string='Menus', type='text', multi="meta", store=True), + 'reports_by_module': fields.function(_get_views, method=True, string='Reports', type='text', multi="meta", store=True), + 'views_by_module': fields.function(_get_views, method=True, string='Views', type='text', multi="meta", store=True), } _defaults = { diff --git a/bin/addons/base/res/res_user.py b/bin/addons/base/res/res_user.py index 518acf57944..e7f3f563234 100644 --- a/bin/addons/base/res/res_user.py +++ b/bin/addons/base/res/res_user.py @@ -152,7 +152,7 @@ class users(osv.osv): 'groups_id': _get_group, } def company_get(self, cr, uid, uid2): - company_id = self.pool.get('res.users').browse(cr, uid, uid).company_id.id + company_id = self.pool.get('res.users').browse(cr, uid, uid2).company_id.id return company_id company_get = tools.cache()(company_get) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index 148626ae26c..ddaf7e337a2 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -727,7 +727,6 @@ class orm_template(object): and getattr(self._columns[f], arg): res[f][arg] = getattr(self._columns[f], arg) - # translate the field label res_trans = translation_obj._get_source(cr, user, self._name + ',' + f, 'field', context.get('lang', False) or 'en_US') if res_trans: @@ -838,13 +837,13 @@ class orm_template(object): # translate view if ('lang' in context) and not result: if node.hasAttribute('string') and node.getAttribute('string'): - trans = tools.translate(cr, self._name, 'view', context['lang'], node.getAttribute('string').encode('utf8')) + trans = self.pool.get('ir.translation')._get_source(cr, user, self._name, 'view', context['lang'], node.getAttribute('string').encode('utf8')) if not trans and ('base_model_name' in context): - trans = tools.translate(cr, context['base_model_name'], 'view', context['lang'], node.getAttribute('string').encode('utf8')) + trans = self.pool.get('ir.translation')._get_source(cr, user, context['base_model_name'], 'view', context['lang'], node.getAttribute('string').encode('utf8')) if trans: node.setAttribute('string', trans) if node.hasAttribute('sum') and node.getAttribute('sum'): - trans = tools.translate(cr, self._name, 'view', context['lang'], node.getAttribute('sum').encode('utf8')) + trans = self.pool.get('ir.translation')._get_source(cr, user, self._name, 'view', context['lang'], node.getAttribute('sum').encode('utf8')) if trans: node.setAttribute('sum', trans) @@ -2005,11 +2004,7 @@ class orm(orm_template): if isinstance(ids, (int, long)): ids = [ids] - fn_list = [] - for fnct in self.pool._store_function.get(self._name, []): - ids2 = filter(None, fnct[2](self,cr, uid, ids, context)) - if ids2: - fn_list.append( (fnct[0], fnct[1], ids2) ) + result_store = self._store_get_values(cr, user, ids, vals.keys(), context) delta = context.get('read_delta', False) if delta and self._log_access: @@ -2057,10 +2052,8 @@ class orm(orm_template): cr.execute('delete from "'+self._table+'" ' \ 'where id in ('+str_d+')', sub_ids) - for object,field,ids in fn_list: - ids = self.pool.get(object).search(cr, uid, [('id','in', ids)], context=context) - if ids: - self.pool.get(object)._store_set_values(cr, uid, ids, field, context) + for order, object, ids, fields in result_store: + self.pool.get(object)._store_set_values(cr, user, ids, fields, context) return True # @@ -2268,20 +2261,14 @@ class orm(orm_template): if 'read_delta' in context: del context['read_delta'] + + result = self._store_get_values(cr, user, ids, vals.keys(), context) + for order, object, ids, fields in result: + self.pool.get(object)._store_set_values(cr, user, ids, fields, context) + wf_service = netsvc.LocalService("workflow") for id in ids: wf_service.trg_write(user, self._name, id, cr) - - for fnct in self.pool._store_function.get(self._name, []): - ok = False - for key in vals.keys(): - if (not fnct[3]) or (key in fnct[3]): - ok = True - if ok: - ids2 = fnct[2](self,cr, user, ids, context) - ids2 = filter(None, ids2) - if ids2: - self.pool.get(fnct[0])._store_set_values(cr, user, ids2, fnct[1], context) return True # @@ -2386,34 +2373,68 @@ class orm(orm_template): cr.execute('update '+self._table+' set parent_right=parent_right+2 where parent_right>%s', (pleft,)) cr.execute('update '+self._table+' set parent_left=%s,parent_right=%s where id=%s', (pleft+1,pleft+2,id_new)) + result = self._store_get_values(cr, user, [id_new], vals.keys(), context) + for order, object, ids, fields in result: + self.pool.get(object)._store_set_values(cr, user, ids, fields, context) + wf_service = netsvc.LocalService("workflow") wf_service.trg_create(user, self._name, id_new, cr) - - for fnct in self.pool._store_function.get(self._name, []): - ids2 = fnct[2](self,cr, user, [id_new], context) - ids2 = filter(None, ids2) - if ids2: - self.pool.get(fnct[0])._store_set_values(cr, user, ids2, fnct[1], context) return id_new - def _store_set_values(self, cr, uid, ids, field, context): - args = {} - result = self._columns[field].get(cr, self, ids, field, uid, context=context) - for id,value in result.items(): - upd0 = [] - upd1 = [] - if self._columns[field]._multi: - value = value[field] - if self._columns[field]._type in ('many2one', 'one2one'): - try: - value = value[0] - except: - pass - upd0.append('"'+field+'"='+self._columns[field]._symbol_set[0]) - upd1.append(self._columns[field]._symbol_set[1](value)) - upd1.append(id) - cr.execute('update "' + self._table + '" set ' + \ - string.join(upd0, ',') + ' where id = %s', upd1) + def _store_get_values(self, cr, uid, ids, fields, context): + result = {} + fncts = self.pool._store_function.get(self._name, []) + for fnct in range(len(fncts)): + result.setdefault(fncts[fnct][0], {}) + ids2 = fncts[fnct][2](self,cr, uid, ids, context) + for id in filter(None, ids2): + result[fncts[fnct][0]].setdefault(id, []) + result[fncts[fnct][0]][id].append(fnct) + result2 = [] + for object in result: + k2 = {} + for id,fnct in result[object].items(): + k2.setdefault(tuple(fnct), []) + k2[tuple(fnct)].append(id) + for fnct,id in k2.items(): + result2.append((fncts[fnct[0]][4],object,id,map(lambda x: fncts[x][1], fnct))) + result2.sort() + return result2 + + def _store_set_values(self, cr, uid, ids, fields, context): + todo = {} + for f in fields: + todo.setdefault(self._columns[f]._multi, []) + todo[self._columns[f]._multi].append(f) + for key,val in todo.items(): + if key: + result = self._columns[val[0]].get(cr, self, ids, val, uid, context=context) + for id,value in result.items(): + upd0 = [] + upd1 = [] + for v in value: + if self._columns[v]._type in ('many2one', 'one2one'): + try: + value[v] = value[v][0] + except: + pass + upd0.append('"'+v+'"='+self._columns[v]._symbol_set[0]) + upd1.append(self._columns[v]._symbol_set[1](value[v])) + upd1.append(id) + cr.execute('update "' + self._table + '" set ' + \ + string.join(upd0, ',') + ' where id = %s', upd1) + + else: + for f in val: + result = self._columns[f].get(cr, self, ids, f, uid, context=context) + for id,value in result.items(): + if self._columns[f]._type in ('many2one', 'one2one'): + try: + value = value[0] + except: + pass + cr.execute('update "' + self._table + '" set ' + \ + '"'+f+'"='+self._columns[f]._symbol_set[0] + ' where id = %s', (value,id)) return True # diff --git a/bin/osv/osv.py b/bin/osv/osv.py index 32fdfd17e6f..1650dbde900 100644 --- a/bin/osv/osv.py +++ b/bin/osv/osv.py @@ -251,122 +251,3 @@ class osv(orm.orm): self.pool = pool orm.orm.__init__(self, cr) - -class Cacheable(object): - - _cache = UpdateableDict() - - def add(self, key, value): - self._cache[key] = value - - def invalidate(self, key): - del self._cache[key] - - def get(self, key): - try: - w = self._cache[key] - return w - except KeyError: - return None - - def clear(self): - self._cache.clear() - self._items = [] - - -def filter_dict(d, fields): - res = {} - for f in fields + ['id']: - if f in d: - res[f] = d[f] - return res - - -class cacheable_osv(osv, Cacheable): - - _relevant = ['lang'] - - def __init__(self): - super(cacheable_osv, self).__init__() - - def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'): - if not fields: - fields = [] - if not context: - context = {} - fields = fields or self._columns.keys() - ctx = [context.get(x, False) for x in self._relevant] - result, tofetch = [], [] - for id in ids: - res = self.get(self._name, id, ctx) - if not res: - tofetch.append(id) - else: - result.append(filter_dict(res, fields)) - - # gen the list of "local" (ie not inherited) fields which are classic or many2one - nfields = filter(lambda x: x[1]._classic_write, self._columns.items()) - # gen the list of inherited fields - inherits = map(lambda x: (x[0], x[1][2]), self._inherit_fields.items()) - # complete the field list with the inherited fields which are classic or many2one - nfields += filter(lambda x: x[1]._classic_write, inherits) - nfields = [x[0] for x in nfields] - - res = super(cacheable_osv, self).read(cr, user, tofetch, nfields, context, load) - for r in res: - self.add((self._name, r['id'], ctx), r) - result.append(filter_dict(r, fields)) - - # Appel de fonction si necessaire - tofetch = [] - for f in fields: - if f not in nfields: - tofetch.append(f) - for f in tofetch: - fvals = self._columns[f].get(cr, self, ids, f, user, context=context) - for r in result: - r[f] = fvals[r['id']] - - # TODO: tri par self._order !! - return result - - def invalidate(self, key): - del self._cache[key[0]][key[1]] - - def write(self, cr, user, ids, values, context=None): - if not context: - context = {} - for id in ids: - self.invalidate((self._name, id)) - return super(cacheable_osv, self).write(cr, user, ids, values, context) - - def unlink(self, cr, user, ids): - self.clear() - return super(cacheable_osv, self).unlink(cr, user, ids) - -#cacheable_osv = osv - - -#class FakePool(object): -# def __init__(self, module): -# self.preferred_module = module - -# def get(self, name): -# localpool = module_objects_dict.get(self.preferred_module, {'dict': {}})['dict'] -# if name in localpool: -# obj = localpool[name] -# else: -# obj = pooler.get_pool(cr.dbname).get(name) -# return obj - -# fake_pool = self -# class fake_class(obj.__class__): -# def __init__(self): -# super(fake_class, self).__init__() -# self.pool = fake_pool - -# return fake_class() - - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: - diff --git a/bin/service/security.py b/bin/service/security.py index 4b6d5055bc1..81c6ef99744 100644 --- a/bin/service/security.py +++ b/bin/service/security.py @@ -35,16 +35,6 @@ def login(db, login, password): else: return False -def logout(db, login, password): - cr = pooler.get_db(db).cursor() - cr.execute('select login from res_users where id=%d'%(login)) - res = cr.fetchone() - cr.close() - if res: - return res[0] - else: - return False - def check_super(passwd): if passwd == tools.config['admin_passwd']: return True diff --git a/bin/service/web_services.py b/bin/service/web_services.py index a0005bd8e78..d6792c54b9f 100644 --- a/bin/service/web_services.py +++ b/bin/service/web_services.py @@ -319,29 +319,11 @@ class common(netsvc.Service): msg = res and 'successful login' or 'bad login or password' logger.notifyChannel("web-service", netsvc.LOG_INFO, "%s from '%s' using database '%s'" % (msg, login, db.lower())) return res or False - + def logout(self, db, login, password): - # FIXME: WTF !!! what is this hardcoding ? - res = security.logout(db, login, password) - service = netsvc.LocalService("object_proxy") - fields = service.execute(db, login, 'res.users', 'fields_get', {}) - try: - if 'current_status' in fields.keys(): - service.execute(db, login, 'res.users', 'write', login, {'current_status':False}) - emp_id = service.execute(db, login, 'hr.employee', 'search',[('user_id','=',login)]) - emp = emp_id[0] - service.execute(db, login, 'hr.attendance', 'create',{'action':'sign_out','employee_id':emp}) - cr = pooler.get_db(db).cursor() - cr.execute("delete from time_sheet_remote_temp where user_id = '%s'"%(res)) - cr.commit() - cr.close() - except: - pass logger = netsvc.Logger() - logger.notifyChannel("web-service", netsvc.LOG_INFO,'Logout=>%s from database %s'%(res,db.lower())) + logger.notifyChannel("web-service", netsvc.LOG_INFO,'Logout %s from database %s'%(login,db)) return True - - def about(self, extended=False): """Return information about the OpenERP Server. diff --git a/bin/tools/misc.py b/bin/tools/misc.py index a5be66067da..8d2a821f5d7 100644 --- a/bin/tools/misc.py +++ b/bin/tools/misc.py @@ -385,7 +385,6 @@ def sms_send(user, password, api_id, text, to): #f = urllib.urlopen("http://api.clickatell.com/http/sendmsg", params) f = urllib.urlopen("http://196.7.150.220/http/sendmsg", params) # FIXME: Use the logger if there is an error - print f.read() return True #--------------------------------------------------------- @@ -537,29 +536,36 @@ def is_hashable(h): # Timeout: 0 = no timeout, otherwise in seconds # class cache(object): - def __init__(self, timeout=10000, skiparg=2): + def __init__(self, timeout=10000, skiparg=2, multi=None): self.timeout = timeout + self.skiparg = skiparg + self.multi = multi self.cache = {} def __call__(self, fn): - arg_names = inspect.getargspec(fn)[0][2:] + arg_names = inspect.getargspec(fn)[0][self.skiparg:] def cached_result(self2, cr=None, *args, **kwargs): if cr is None: self.cache = {} return True + if ('clear_keys' in kwargs): + if (kwargs['clear_keys'] in self.cache): + del self.cache[kwargs['clear_keys']] + return True # Update named arguments with positional argument values - kwargs.update(dict(zip(arg_names, args))) - for k in kwargs: - if isinstance(kwargs[k], (list, dict, set)): - kwargs[k] = tuple(kwargs[k]) - elif not is_hashable(kwargs[k]): - kwargs[k] = repr(kwargs[k]) - kwargs = kwargs.items() - kwargs.sort() + kwargs2 = kwargs.copy() + kwargs2.update(dict(zip(arg_names, args))) + for k in kwargs2: + if isinstance(kwargs2[k], (list, dict, set)): + kwargs2[k] = tuple(kwargs2[k]) + elif not is_hashable(kwargs2[k]): + kwargs2[k] = repr(kwargs2[k]) + kwargs2 = kwargs2.items() + kwargs2.sort() # Work out key as a tuple of ('argname', value) pairs - key = (('dbname', cr.dbname),) + tuple(kwargs) + key = (('dbname', cr.dbname),) + tuple(kwargs2) # Check cache and return cached value if possible if key in self.cache: @@ -571,7 +577,7 @@ class cache(object): # Work out new value, cache it and return it # FIXME Should copy() this value to avoid futur modifications of the cache ? # FIXME What about exceptions ? - result = fn(self2,cr,**dict(kwargs)) + result = fn(self2,cr,*args, **kwargs) self.cache[key] = (result, time.time()) return result diff --git a/bin/tools/translate.py b/bin/tools/translate.py index 90980fd806c..7ed55f9fd94 100644 --- a/bin/tools/translate.py +++ b/bin/tools/translate.py @@ -41,7 +41,7 @@ class UNIX_LINE_TERMINATOR(csv.excel): csv.register_dialect("UNIX", UNIX_LINE_TERMINATOR) # -# TODO: a caching method +# Warning: better use self.pool.get('ir.translation')._get_source if you can # def translate(cr, name, source_type, lang, source=None): if source and name: @@ -61,8 +61,10 @@ class GettextAlias(object): lang = frame.f_locals.get('context', {}).get('lang', False) if not (lang and cr): return source - return translate(cr, None, 'code', lang, source) or source + cr.execute('select value from ir_translation where lang=%s and type=%s and src=%s', (lang, 'code', source)) + res_trans = cr.fetchone() + return res_trans and res_trans[0] or source _ = GettextAlias() From 245bdf043338cd559d7fadf4030b6634f71dbde4 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Sat, 13 Dec 2008 07:05:19 +0100 Subject: [PATCH 121/137] bugfix_speed_improvement bzr revid: fp@tinyerp.com-20081213060519-t79l5dvxcy98pl33 --- addons/account/wizard/wizard_account_chart.py | 7 +---- addons/mrp/mrp.py | 2 +- addons/product/pricelist.py | 22 ++++++---------- addons/sale/sale.py | 26 ++++++++++++++++--- 4 files changed, 33 insertions(+), 24 deletions(-) diff --git a/addons/account/wizard/wizard_account_chart.py b/addons/account/wizard/wizard_account_chart.py index a2edc2fec2f..60608ea7198 100644 --- a/addons/account/wizard/wizard_account_chart.py +++ b/addons/account/wizard/wizard_account_chart.py @@ -59,12 +59,7 @@ class wizard_account_chart(wizard.interface): result = mod_obj._get_id(cr, uid, 'account', 'action_account_tree') id = mod_obj.read(cr, uid, [result], ['res_id'])[0]['res_id'] - result = act_obj.read(cr, uid, [id])[0] - if 'lang' in context: - import tools - trans_name = tools.translate(cr, 'ir.actions.act_window,name', 'model', context['lang'], result['name']) - if trans_name: - result['name'] = trans_name + result = act_obj.read(cr, uid, [id], context=context)[0] result['context'] = str({'fiscalyear': data['form']['fiscalyear'],'target_move':data['form']['target_move']}) if data['form']['fiscalyear']: result['name']+=':'+pooler.get_pool(cr.dbname).get('account.fiscalyear').read(cr,uid,[data['form']['fiscalyear']])[0]['code'] diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index 288d17f4244..5935bc4aca1 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -634,7 +634,7 @@ class mrp_production(osv.osv): } res_final_id = self.pool.get('stock.move').create(cr, uid, data) - self.write(cr, uid, [production.id], {'move_created_ids': [(6, 'WTF', [res_final_id])]}) + self.write(cr, uid, [production.id], {'move_created_ids': [(6, 0, [res_final_id])]}) moves = [] for line in production.product_lines: move_id=False diff --git a/addons/product/pricelist.py b/addons/product/pricelist.py index a8509f1c06f..2ca74463dfd 100644 --- a/addons/product/pricelist.py +++ b/addons/product/pricelist.py @@ -36,14 +36,11 @@ class price_type(osv.osv): sale and purchase prices based on some fields of the product. """ def _price_field_get(self, cr, uid, context={}): - import tools - cr.execute('select name, field_description, model from ir_model_fields where model in (%s,%s) and ttype=%s order by name', ('product.product', 'product.template', 'float')) + mf = self.pool.get('ir.model.fields') + ids = mf.search(cr, uid, [('model','in', (('product.product'),('product.template'))), ('ttype','=','float')], context=context) res = [] - for field in cr.dictfetchall(): - desc = tools.translate(cr, field['model'] + ',' + field['name'], 'field', context.get('lang', False) or 'en_US') - if not desc: - desc = field['field_description'] - res.append((field['name'], desc)) + for field in mf.browse(cr, uid, ids, context=context): + res.append((field.name, field.field_description)) return res def _get_currency(self, cr, uid, ctx): @@ -304,14 +301,11 @@ product_pricelist_version() class product_pricelist_item(osv.osv): def _price_field_get(self, cr, uid, context={}): - cr.execute('select id,name from product_price_type where active') - import tools + pt = self.pool.get('product.price.type') + ids = pt.search(cr, uid, [], context=context) result = [] - for line in cr.fetchall(): - transl_name = tools.translate(cr, 'product.price.type,name', 'model', ('lang' in context) and context['lang'] or 'en_US', line[1]) - if not transl_name: - transl_name = line[1] - result.append((line[0], transl_name)) + for line in pt.browse(cr, uid, ids, context=context): + result.append((line.id, line.name)) result.append((-1, _('Other Pricelist'))) result.append((-2, _('Partner section of the product form'))) diff --git a/addons/sale/sale.py b/addons/sale/sale.py index 494891dd2cd..1889def63f1 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -172,6 +172,12 @@ class sale_order(osv.osv): return [('id', '=', 0)] return [('id', 'in', [x[0] for x in res])] + def _get_order(self, cr, uid, ids, context={}): + result = {} + for line in self.pool.get('sale.order.line').browse(cr, uid, ids, context=context): + result[line.order_id.id] = True + return result.keys() + _columns = { 'name': fields.char('Order Reference', size=64, required=True, select=True), 'shop_id':fields.many2one('sale.shop', 'Shop', required=True, readonly=True, states={'draft':[('readonly',False)]}), @@ -224,9 +230,23 @@ class sale_order(osv.osv): 'note': fields.text('Notes'), 'amount_untaxed': fields.function(_amount_all, method=True, string='Untaxed Amount', - store=True, multi='sums'), - 'amount_tax': fields.function(_amount_all, method=True, string='Taxes', store=True, multi='sums'), - 'amount_total': fields.function(_amount_all, method=True, string='Total', store=True, multi='sums'), + store={ + 'sale.order': (lambda self, cr, uid, ids, c={}: ids, None, 10), + 'sale.order.line': (_get_order, None, 10), + }, + multi='sums'), + 'amount_tax': fields.function(_amount_all, method=True, string='Taxes', + store={ + 'sale.order': (lambda self, cr, uid, ids, c={}: ids, None, 10), + 'sale.order.line': (_get_order, None, 10), + }, + multi='sums'), + 'amount_total': fields.function(_amount_all, method=True, string='Total', + store={ + 'sale.order': (lambda self, cr, uid, ids, c={}: ids, None, 10), + 'sale.order.line': (_get_order, None, 10), + }, + multi='sums'), 'invoice_quantity': fields.selection([('order','Ordered Quantities'),('procurement','Shipped Quantities')], 'Invoice on', help="The sale order will automatically create the invoice proposition (draft invoice). Ordered and delivered quantities may not be the same. You have to choose if you invoice based on ordered or shipped quantities. If the product is a service, shipped quantities means hours spent on the associated tasks.",required=True), 'payment_term' : fields.many2one('account.payment.term', 'Payment Term'), From 862dcf8dcdfcd174d409ba9a8d620d2ed3d1c72a Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Sat, 13 Dec 2008 07:15:46 +0100 Subject: [PATCH 122/137] bugfix bzr revid: fp@tinyerp.com-20081213061546-i2ymf8ku71heox4o --- bin/addons/base/ir/ir_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/addons/base/ir/ir_model.py b/bin/addons/base/ir/ir_model.py index 8df05b6b082..40ce882e280 100644 --- a/bin/addons/base/ir/ir_model.py +++ b/bin/addons/base/ir/ir_model.py @@ -435,7 +435,7 @@ class ir_model_data(osv.osv): ids = self.search(cr, uid, [('module','=',module),('name','=', xml_id)]) assert len(ids)==1, '%d reference(s) to %s.%s. You should have one and only one !' % (len(ids), module, xml_id) return ids[0] - _get_id = tools.cache(skiparg=3)(_get_id) + _get_id = tools.cache(skiparg=2)(_get_id) def _update_dummy(self,cr, uid, model, module, xml_id=False, store=True): if not xml_id: From 940294901da80cf654930eb8525ce53b7296e42f Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Sat, 13 Dec 2008 07:17:48 +0100 Subject: [PATCH 123/137] bugfix bzr revid: fp@tinyerp.com-20081213061748-y446px7er56rcnif --- bin/addons/base/ir/ir_attachment.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/bin/addons/base/ir/ir_attachment.py b/bin/addons/base/ir/ir_attachment.py index 10ff3275dca..fd44da84d72 100644 --- a/bin/addons/base/ir/ir_attachment.py +++ b/bin/addons/base/ir/ir_attachment.py @@ -81,24 +81,12 @@ class ir_attachment(osv.osv): self.pool.get('ir.model.access').check(cr, uid, values['res_model'], 'create') return super(ir_attachment, self).create(cr, uid, values, *args, **kwargs) - def clear_cache(self): - self.check() - def action_get(self, cr, uid, context=None): dataobj = self.pool.get('ir.model.data') data_id = dataobj._get_id(cr, 1, 'base', 'action_attachment') res_id = dataobj.browse(cr, uid, data_id, context).res_id return self.pool.get('ir.actions.act_window').read(cr, uid, res_id, [], context) - def __init__(self, *args, **kwargs): - r = super(ir_attachment, self).__init__(*args, **kwargs) - self.pool.get('ir.model.access').register_cache_clearing_method(self._name, 'clear_cache') - return r - - def __del__(self): - self.pool.get('ir.model.access').unregister_cache_clearing_method(self._name, 'clear_cache') - return super(ir_attachment, self).__del__() - def _get_preview(self, cr, uid, ids, name, arg, context=None): result = {} if context is None: From 98292c4dcc5f4b46ba0bb771a1b9ba8454993d56 Mon Sep 17 00:00:00 2001 From: Mantavya Gajjar Date: Sat, 13 Dec 2008 12:00:50 +0530 Subject: [PATCH 124/137] small change in the server action Other Action => Multi Action bzr revid: mga@tinyerp.com-20081213063050-5z4r2h0i3ko2i6fw --- bin/addons/base/ir/ir.xml | 3 ++- bin/addons/base/ir/ir_actions.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/bin/addons/base/ir/ir.xml b/bin/addons/base/ir/ir.xml index 6cd10d7cc3a..fd3b7345d5a 100644 --- a/bin/addons/base/ir/ir.xml +++ b/bin/addons/base/ir/ir.xml @@ -1194,9 +1194,10 @@ - + + diff --git a/bin/addons/base/ir/ir_actions.py b/bin/addons/base/ir/ir_actions.py index 5ac38dd55b9..fea7c49f6e1 100644 --- a/bin/addons/base/ir/ir_actions.py +++ b/bin/addons/base/ir/ir_actions.py @@ -394,7 +394,7 @@ class actions_server(osv.osv): ('sms','SMS'), ('object_create','Create Object'), ('object_write','Write Object'), - ('other','Others Actions'), + ('other','Multi Actions'), ], 'Action State', required=True, size=32), 'code': fields.text('Python Code'), 'sequence': fields.integer('Sequence'), @@ -409,7 +409,7 @@ class actions_server(osv.osv): 'sms': fields.char('SMS', size=160, translate=True), 'child_ids': fields.many2many('ir.actions.server', 'rel_server_actions', 'server_id', 'action_id', 'Others Actions'), 'usage': fields.char('Action Usage', size=32), - 'type': fields.char('Report Type', size=32, required=True), + 'type': fields.char('Action Type', size=32, required=True), 'srcmodel_id': fields.many2one('ir.model', 'Model', help="In which object you want to create / write the object if its empty refer to the Object field"), 'fields_lines': fields.one2many('ir.server.object.lines', 'server_id', 'Fields Mapping'), 'record_id':fields.many2one('ir.model.fields', 'Record Id', help="privide the field name from where the record id refers, if its empty it will refer to the active id of the object") From f3f97eff55798d25160dd91c92d3aa41e18910ba Mon Sep 17 00:00:00 2001 From: Mantavya Gajjar Date: Sat, 13 Dec 2008 18:12:04 +0530 Subject: [PATCH 125/137] improve the server action bzr revid: mga@tinyerp.com-20081213124204-zces6hdrj9oad8r6 --- bin/addons/base/ir/ir.xml | 4 ++-- bin/addons/base/ir/ir_actions.py | 16 +++++++++++----- bin/osv/orm.py | 4 ++-- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/bin/addons/base/ir/ir.xml b/bin/addons/base/ir/ir.xml index fd3b7345d5a..b27d917fc21 100644 --- a/bin/addons/base/ir/ir.xml +++ b/bin/addons/base/ir/ir.xml @@ -1196,8 +1196,8 @@ - - diff --git a/bin/addons/base/ir/ir_actions.py b/bin/addons/base/ir/ir_actions.py index fea7c49f6e1..d31a13211a5 100644 --- a/bin/addons/base/ir/ir_actions.py +++ b/bin/addons/base/ir/ir_actions.py @@ -431,6 +431,7 @@ class actions_server(osv.osv): def get_email(self, cr, uid, action, context): + logger = netsvc.Logger() obj_pool = self.pool.get(action.model_id.model) id = context.get('active_id') obj = obj_pool.browse(cr, uid, id) @@ -446,12 +447,13 @@ class actions_server(osv.osv): try: obj = getattr(obj, field) except Exception,e : - logger.notifyChannel('Workflow', netsvc.LOG_ERROR, 'Failed to parse : %s' % (match.group())) + logger.notifyChannel('Workflow', netsvc.LOG_ERROR, 'Failed to parse : %s' % (field)) return obj def get_mobile(self, cr, uid, action, context): + logger = netsvc.Logger() obj_pool = self.pool.get(action.model_id.model) id = context.get('active_id') obj = obj_pool.browse(cr, uid, id) @@ -467,7 +469,7 @@ class actions_server(osv.osv): try: obj = getattr(obj, field) except Exception,e : - logger.notifyChannel('Workflow', netsvc.LOG_ERROR, 'Failed to parse : %s' % (match.group())) + logger.notifyChannel('Workflow', netsvc.LOG_ERROR, 'Failed to parse : %s' % (field)) return obj @@ -478,10 +480,14 @@ class actions_server(osv.osv): id = context.get('active_id') obj = obj_pool.browse(cr, uid, id) exp = str(match.group()[2:-2]).strip() - return eval(exp, {'object':obj, 'context': context,'time':time}) - + result = eval(exp, {'object':obj, 'context': context,'time':time}) + if result in (None, False): + return str("--------") + return str(result) + com = re.compile('(\[\[.+?\]\])') message = com.sub(merge, keystr) + return message # Context should contains: @@ -522,7 +528,7 @@ class actions_server(osv.osv): raise osv.except_osv(_('Error'), _("Please specify server option --smtp-from !")) body = self.merge_message(cr, uid, str(action.message), action, context) - if tools.email_send(user, [address], subject, body, debug=False) == True: + if tools.email_send(user, [address], subject, body, debug=False, subtype='html') == True: logger.notifyChannel('email', netsvc.LOG_INFO, 'Email successfully send to : %s' % (address)) else: logger.notifyChannel('email', netsvc.LOG_ERROR, 'Failed to send email to : %s' % (address)) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index ddaf7e337a2..e4071cce80f 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -2004,7 +2004,7 @@ class orm(orm_template): if isinstance(ids, (int, long)): ids = [ids] - result_store = self._store_get_values(cr, user, ids, vals.keys(), context) + result_store = self._store_get_values(cr, uid, ids, None, context) delta = context.get('read_delta', False) if delta and self._log_access: @@ -2053,7 +2053,7 @@ class orm(orm_template): 'where id in ('+str_d+')', sub_ids) for order, object, ids, fields in result_store: - self.pool.get(object)._store_set_values(cr, user, ids, fields, context) + self.pool.get(object)._store_set_values(cr, uid, ids, fields, context) return True # From dbd44cd71abcba9b957f74e56695bcf265e7d519 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Sat, 13 Dec 2008 13:53:14 +0100 Subject: [PATCH 126/137] bugfixes bzr revid: fp@tinyerp.com-20081213125314-t3csvq95lk0nbkk3 --- bin/addons/base/res/partner/partner.py | 4 ++-- bin/osv/orm.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/bin/addons/base/res/partner/partner.py b/bin/addons/base/res/partner/partner.py index 8aef2eb46fd..d17c696677f 100644 --- a/bin/addons/base/res/partner/partner.py +++ b/bin/addons/base/res/partner/partner.py @@ -306,10 +306,10 @@ class res_partner_address(osv.osv): if context.get('contact_display', 'contact')=='partner': res.append((r['id'], r['partner_id'][1])) else: - addr = str(r['name'] or '') + addr = r['name'] or '' if r['name'] and (r['zip'] or r['city']): addr += ', ' - addr += str(r['street'] or '') + ' ' + str(r['zip'] or '') + ' ' + str(r['city'] or '') + addr += (r['street'] or '') + ' ' + (r['zip'] or '') + ' ' + (r['city'] or '') res.append((r['id'], addr.strip() or '/')) return res diff --git a/bin/osv/orm.py b/bin/osv/orm.py index e4071cce80f..b1fbcd93522 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -2005,7 +2005,6 @@ class orm(orm_template): ids = [ids] result_store = self._store_get_values(cr, uid, ids, None, context) - delta = context.get('read_delta', False) if delta and self._log_access: for i in range(0, len(ids), cr.IN_MAX): From 66b98b50689a4bc7bae8c02ffea771683b216b76 Mon Sep 17 00:00:00 2001 From: Fabian Semal Date: Sat, 13 Dec 2008 14:57:39 +0100 Subject: [PATCH 127/137] Bugfix in translation (removed print '***', _get_language) bzr revid: fabian@tinyerp.com-20081213135739-dbjgryn89ugjrqse --- bin/addons/base/ir/ir_translation.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/addons/base/ir/ir_translation.py b/bin/addons/base/ir/ir_translation.py index a392a6c3702..0e9e28ddeed 100644 --- a/bin/addons/base/ir/ir_translation.py +++ b/bin/addons/base/ir/ir_translation.py @@ -43,7 +43,6 @@ class ir_translation(osv.osv): _log_access = False def _get_language(self, cr, uid, context): - print '***', _get_language lang_obj = self.pool.get('res.lang') lang_ids = lang_obj.search(cr, uid, [('translatable', '=', True)], context=context) From 2b5971f125c49c62cb2045f6766a2ff4424a2b76 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Sat, 13 Dec 2008 18:56:49 +0100 Subject: [PATCH 128/137] [FIX] Typo bzr revid: stephane@tinyerp.com-20081213175649-2bqqn1ungl06zhie --- bin/addons/base/ir/ir.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/addons/base/ir/ir.xml b/bin/addons/base/ir/ir.xml index b27d917fc21..263f5428718 100644 --- a/bin/addons/base/ir/ir.xml +++ b/bin/addons/base/ir/ir.xml @@ -1194,7 +1194,7 @@
- +