summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Simonis <christophe@tinyerp.com>2008-07-22 16:24:36 +0200
committerChristophe Simonis <christophe@tinyerp.com>2008-07-22 16:24:36 +0200
commit2dd9723b8b3d38df8c8962300ab67afffa5cdaaa (patch)
tree13dbea91b265af5ad775af16efcdef4ae6ef962c
parentc5c7c2ef07b346b72eb5a48d6e8cc7a433fba2e8 (diff)
convert tabs to 4 spaces
bzr revid: christophe@tinyerp.com-20080722142436-143iu4ryy47w3av0
-rw-r--r--bin/addons/__init__.py542
-rw-r--r--bin/addons/base/__terp__.py80
-rw-r--r--bin/addons/base/ir/ir_actions.py520
-rw-r--r--bin/addons/base/ir/ir_attachment.py22
-rw-r--r--bin/addons/base/ir/ir_board.py16
-rw-r--r--bin/addons/base/ir/ir_cron.py158
-rw-r--r--bin/addons/base/ir/ir_default.py38
-rw-r--r--bin/addons/base/ir/ir_exports.py24
-rw-r--r--bin/addons/base/ir/ir_model.py712
-rw-r--r--bin/addons/base/ir/ir_report_custom.py312
-rw-r--r--bin/addons/base/ir/ir_rule.py396
-rw-r--r--bin/addons/base/ir/ir_sequence.py78
-rw-r--r--bin/addons/base/ir/ir_translation.py228
-rw-r--r--bin/addons/base/ir/ir_ui_menu.py266
-rw-r--r--bin/addons/base/ir/ir_ui_view.py146
-rw-r--r--bin/addons/base/ir/ir_values.py430
-rw-r--r--bin/addons/base/ir/wizard/wizard_menu.py98
-rw-r--r--bin/addons/base/ir/workflow/print_instance.py284
-rw-r--r--[-rwxr-xr-x]bin/addons/base/ir/workflow/pydot/__init__.py0
-rw-r--r--[-rwxr-xr-x]bin/addons/base/ir/workflow/pydot/dot_parser.py572
-rw-r--r--[-rwxr-xr-x]bin/addons/base/ir/workflow/pydot/pydot.py2032
-rw-r--r--[-rwxr-xr-x]bin/addons/base/ir/workflow/pydot/setup.py36
-rw-r--r--bin/addons/base/ir/workflow/workflow.py260
-rw-r--r--bin/addons/base/module/module.py1164
-rw-r--r--bin/addons/base/module/report/ir_module_reference_print.py50
-rw-r--r--bin/addons/base/module/wizard/add_new.py84
-rw-r--r--bin/addons/base/module/wizard/wizard_export_lang.py182
-rw-r--r--bin/addons/base/module/wizard/wizard_import_lang.py78
-rw-r--r--bin/addons/base/module/wizard/wizard_module_import.py120
-rw-r--r--bin/addons/base/module/wizard/wizard_module_lang_install.py86
-rw-r--r--bin/addons/base/module/wizard/wizard_module_upgrade.py186
-rw-r--r--bin/addons/base/module/wizard/wizard_update_module.py118
-rw-r--r--bin/addons/base/res/bank.py44
-rw-r--r--bin/addons/base/res/country.py122
-rw-r--r--bin/addons/base/res/ir_property.py82
-rw-r--r--bin/addons/base/res/partner/crm.py102
-rw-r--r--bin/addons/base/res/partner/partner.py722
-rw-r--r--bin/addons/base/res/partner/wizard/wizard_clear_ids.py22
-rw-r--r--bin/addons/base/res/partner/wizard/wizard_ean_check.py106
-rw-r--r--bin/addons/base/res/partner/wizard/wizard_sms.py62
-rw-r--r--bin/addons/base/res/partner/wizard/wizard_spam.py64
-rw-r--r--bin/addons/base/res/res_company.py288
-rw-r--r--bin/addons/base/res/res_currency.py160
-rw-r--r--bin/addons/base/res/res_lang.py26
-rw-r--r--bin/addons/base/res/res_request.py158
-rw-r--r--bin/addons/base/res/res_user.py402
-rw-r--r--bin/addons/module_graph.py18
-rw-r--r--bin/ir/ir.py14
-rw-r--r--bin/netsvc.py632
-rw-r--r--bin/osv/fields.py1102
-rw-r--r--bin/osv/orm.py5008
-rw-r--r--bin/osv/osv.py560
-rw-r--r--bin/pooler.py96
-rw-r--r--bin/report/common.py4
-rw-r--r--bin/report/custom.py1208
-rw-r--r--bin/report/int_to_text.py64
-rw-r--r--bin/report/interface.py346
-rw-r--r--bin/report/misc.py14
-rw-r--r--bin/report/print_fnc.py8
-rw-r--r--bin/report/print_xml.py570
-rw-r--r--bin/report/printscreen/ps_form.py236
-rw-r--r--bin/report/printscreen/ps_list.py322
-rw-r--r--bin/report/render/__init__.py4
-rw-r--r--bin/report/render/render.py60
-rw-r--r--bin/report/render/rml.py28
-rw-r--r--[-rwxr-xr-x]bin/report/render/rml2html/rml2html.py618
-rw-r--r--bin/report/render/rml2html/utils.py68
-rw-r--r--bin/report/render/rml2pdf/color.py20
-rw-r--r--[-rwxr-xr-x]bin/report/render/rml2pdf/trml2pdf.py1414
-rw-r--r--bin/report/render/rml2pdf/utils.py66
-rw-r--r--bin/report/render/simple.py90
-rw-r--r--bin/report/report_sxw.py1136
-rw-r--r--bin/service/security.py72
-rw-r--r--bin/service/web_services.py850
-rw-r--r--bin/sql_db.py200
-rw-r--r--bin/tiny_socket.py112
-rw-r--r--[-rwxr-xr-x]bin/tinyerp-server.py194
-rw-r--r--bin/tools/amount_to_text.py252
-rw-r--r--bin/tools/config.py404
-rw-r--r--bin/tools/convert.py1400
-rw-r--r--bin/tools/graph.py556
-rw-r--r--bin/tools/import_email.py232
-rw-r--r--bin/tools/misc.py888
-rw-r--r--bin/tools/translate.py910
-rw-r--r--bin/tools/upgrade.py90
-rw-r--r--bin/wizard/__init__.py248
-rw-r--r--bin/workflow/common.py6
-rw-r--r--bin/workflow/instance.py84
-rw-r--r--bin/workflow/wkf_expr.py116
-rw-r--r--bin/workflow/wkf_logs.py4
-rw-r--r--bin/workflow/wkf_service.py134
-rw-r--r--bin/workflow/workitem.py284
-rw-r--r--doc/migrate/3.3.0-3.4.0/post.py46
-rw-r--r--doc/migrate/3.3.0-3.4.0/pre.py64
-rw-r--r--doc/migrate/3.4.0-4.0.0/post-tiny.py18
-rw-r--r--doc/migrate/3.4.0-4.0.0/post.py28
-rw-r--r--doc/migrate/3.4.0-4.0.0/pre-tiny.py58
-rw-r--r--doc/migrate/3.4.0-4.0.0/pre.py68
-rw-r--r--doc/migrate/4.0.0-4.2.0/pre.py130
-rw-r--r--doc/migrate/4.0.0-4.2.0/tiny/pre-tiny.py94
-rw-r--r--doc/migrate/4.2.0-4.4.0/pre.py36
-rw-r--r--[-rwxr-xr-x]doc/tests/check_profile_l10n_all.py114
-rw-r--r--[-rwxr-xr-x]setup.py0
-rw-r--r--win32/TinyERPServerService.py28
104 files changed, 16552 insertions, 16552 deletions
diff --git a/bin/addons/__init__.py b/bin/addons/__init__.py
index cefd6859e6c..a28c87d1c34 100644
--- a/bin/addons/__init__.py
+++ b/bin/addons/__init__.py
@@ -45,310 +45,310 @@ 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
+_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
sys.path.insert(1, _ad)
if ad != _ad:
- sys.path.insert(1, ad)
+ sys.path.insert(1, ad)
class Graph(dict):
- def addNode(self, name, deps):
- max_depth, father = 0, None
- for n in [Node(x, self) for x in deps]:
- if n.depth >= max_depth:
- father = n
- max_depth = n.depth
- if father:
- father.addChild(name)
- else:
- Node(name, self)
-
- def __iter__(self):
- level = 0
- done = Set(self.keys())
- while done:
- level_modules = [(name, module) for name, module in self.items() if module.depth==level]
- for name, module in level_modules:
- done.remove(name)
- yield module
- level += 1
+ def addNode(self, name, deps):
+ max_depth, father = 0, None
+ for n in [Node(x, self) for x in deps]:
+ if n.depth >= max_depth:
+ father = n
+ max_depth = n.depth
+ if father:
+ father.addChild(name)
+ else:
+ Node(name, self)
+
+ def __iter__(self):
+ level = 0
+ done = Set(self.keys())
+ while done:
+ level_modules = [(name, module) for name, module in self.items() if module.depth==level]
+ for name, module in level_modules:
+ done.remove(name)
+ yield module
+ level += 1
class Singleton(object):
- def __new__(cls, name, graph):
- if name in graph:
- inst = graph[name]
- else:
- inst = object.__new__(cls)
- inst.name = name
- graph[name] = inst
- return inst
+ def __new__(cls, name, graph):
+ if name in graph:
+ inst = graph[name]
+ else:
+ inst = object.__new__(cls)
+ inst.name = name
+ graph[name] = inst
+ return inst
class Node(Singleton):
- def __init__(self, name, graph):
- self.graph = graph
- if not hasattr(self, 'childs'):
- self.childs = []
- if not hasattr(self, 'depth'):
- self.depth = 0
-
- def addChild(self, name):
- node = Node(name, self.graph)
- node.depth = self.depth + 1
- if node not in self.childs:
- self.childs.append(node)
- for attr in ('init', 'update', 'demo'):
- if hasattr(self, attr):
- setattr(node, attr, True)
- self.childs.sort(lambda x,y: cmp(x.name, y.name))
-
- def hasChild(self, name):
- return Node(name, self.graph) in self.childs or \
- bool([c for c in self.childs if c.hasChild(name)])
-
- def __setattr__(self, name, value):
- super(Singleton, self).__setattr__(name, value)
- if name in ('init', 'update', 'demo'):
- tools.config[name][self.name] = 1
- for child in self.childs:
- setattr(child, name, value)
- if name == 'depth':
- for child in self.childs:
- setattr(child, name, value + 1)
-
- def __iter__(self):
- return itertools.chain(iter(self.childs), *map(iter, self.childs))
-
- def __str__(self):
- return self._pprint()
-
- def _pprint(self, depth=0):
- s = '%s\n' % self.name
- for c in self.childs:
- s += '%s`-> %s' % (' ' * depth, c._pprint(depth+1))
- return s
+ def __init__(self, name, graph):
+ self.graph = graph
+ if not hasattr(self, 'childs'):
+ self.childs = []
+ if not hasattr(self, 'depth'):
+ self.depth = 0
+
+ def addChild(self, name):
+ node = Node(name, self.graph)
+ node.depth = self.depth + 1
+ if node not in self.childs:
+ self.childs.append(node)
+ for attr in ('init', 'update', 'demo'):
+ if hasattr(self, attr):
+ setattr(node, attr, True)
+ self.childs.sort(lambda x,y: cmp(x.name, y.name))
+
+ def hasChild(self, name):
+ return Node(name, self.graph) in self.childs or \
+ bool([c for c in self.childs if c.hasChild(name)])
+
+ def __setattr__(self, name, value):
+ super(Singleton, self).__setattr__(name, value)
+ if name in ('init', 'update', 'demo'):
+ tools.config[name][self.name] = 1
+ for child in self.childs:
+ setattr(child, name, value)
+ if name == 'depth':
+ for child in self.childs:
+ setattr(child, name, value + 1)
+
+ def __iter__(self):
+ return itertools.chain(iter(self.childs), *map(iter, self.childs))
+
+ def __str__(self):
+ return self._pprint()
+
+ def _pprint(self, depth=0):
+ s = '%s\n' % self.name
+ for c in self.childs:
+ s += '%s`-> %s' % (' ' * depth, c._pprint(depth+1))
+ return s
def get_module_path(module):
- """Return the path of the given module.
- """
+ """Return the path of the given module.
+ """
- if os.path.exists(opj(ad, module)) or os.path.exists(opj(ad, '%s.zip' % module)):
- return opj(ad, module)
+ if os.path.exists(opj(ad, module)) or os.path.exists(opj(ad, '%s.zip' % module)):
+ return opj(ad, module)
- if os.path.exists(opj(_ad, module)) or os.path.exists(opj(_ad, '%s.zip' % module)):
- return opj(_ad, module)
+ if os.path.exists(opj(_ad, module)) or os.path.exists(opj(_ad, '%s.zip' % module)):
+ return opj(_ad, module)
- raise IOError, 'Module not found : %s' % module
+ raise IOError, 'Module not found : %s' % module
def get_module_resource(module, *args):
- """Return the full path of a resource of the given module.
+ """Return the full path of a resource of the given module.
- @param module: the module
- @param args: the resource path components
+ @param module: the module
+ @param args: the resource path components
- @return: absolute path to the resource
- """
- return opj(get_module_path(module), *args)
+ @return: absolute path to the resource
+ """
+ return opj(get_module_path(module), *args)
def get_modules():
- """Returns the list of module names
- """
+ """Returns the list of module names
+ """
- module_list = os.listdir(ad)
- module_names = [os.path.basename(m) for m in module_list]
- module_list += [m for m in os.listdir(_ad) if m not in module_names]
+ module_list = os.listdir(ad)
+ module_names = [os.path.basename(m) for m in module_list]
+ module_list += [m for m in os.listdir(_ad) if m not in module_names]
- return module_list
+ return module_list
def create_graph(module_list, force=None):
- if not force:
- force=[]
- graph = Graph()
- packages = []
-
- for module in module_list:
- if module[-4:]=='.zip':
- module = module[:-4]
- mod_path = get_module_path(module)
- terp_file = get_module_resource(module, '__terp__.py')
- if os.path.isfile(terp_file) or zipfile.is_zipfile(mod_path):
- try:
- info = eval(tools.file_open(terp_file).read())
- except:
- 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))
-
- current,later = Set([p for p, dep, data in packages]), Set()
- while packages and current > later:
- package, deps, datas = 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):
- if not package in current:
- packages.pop(0)
- continue
- later.clear()
- current.remove(package)
- graph.addNode(package, deps)
- node = Node(package, graph)
- node.datas = datas
- 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.pop(0)
-
- for package in later:
- logger.notifyChannel('init', netsvc.LOG_ERROR, 'addon:%s:Unmet dependency' % package)
-
- return graph
+ if not force:
+ force=[]
+ graph = Graph()
+ packages = []
+
+ for module in module_list:
+ if module[-4:]=='.zip':
+ module = module[:-4]
+ mod_path = get_module_path(module)
+ terp_file = get_module_resource(module, '__terp__.py')
+ if os.path.isfile(terp_file) or zipfile.is_zipfile(mod_path):
+ try:
+ info = eval(tools.file_open(terp_file).read())
+ except:
+ 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))
+
+ current,later = Set([p for p, dep, data in packages]), Set()
+ while packages and current > later:
+ package, deps, datas = 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):
+ if not package in current:
+ packages.pop(0)
+ continue
+ later.clear()
+ current.remove(package)
+ graph.addNode(package, deps)
+ node = Node(package, graph)
+ node.datas = datas
+ 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.pop(0)
+
+ for package in later:
+ logger.notifyChannel('init', netsvc.LOG_ERROR, 'addon:%s:Unmet dependency' % package)
+
+ 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)
- for obj in obj_list:
- if hasattr(obj, 'init'):
- obj.init(cr)
- obj._auto_init(cr, {'module': module_name})
- cr.commit()
+ pool = pooler.get_pool(cr.dbname)
+ 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)
+ obj._auto_init(cr, {'module': module_name})
+ cr.commit()
def load_module_graph(cr, graph, status=None, **kwargs):
- # **kwargs is passed directly to convert_xml_import
- if not status:
- status={}
-
- status = status.copy()
- package_todo = []
- statusi = 0
- for package in graph:
- status['progress'] = (float(statusi)+0.1)/len(graph)
- m = package.name
- logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s' % m)
- sys.stdout.flush()
- pool = pooler.get_pool(cr.dbname)
- modules = pool.instanciate(m, cr)
- cr.execute('select state, demo from ir_module_module where name=%s', (m,))
- (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'):
- init_module_objects(cr, m, modules)
- for kind in ('init', 'update'):
- for filename in package.datas.get('%s_xml' % kind, []):
- mode = 'update'
- if hasattr(package, 'init') or package_state=='to install':
- mode = 'init'
- logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:loading %s' % (m, filename))
- name, ext = os.path.splitext(filename)
- if ext == '.csv':
- tools.convert_csv_import(cr, m, os.path.basename(filename), tools.file_open(opj(m, filename)).read(), idref, mode=mode)
- elif ext == '.sql':
- queries = tools.file_open(opj(m, filename)).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'):
- status['progress'] = (float(statusi)+0.75)/len(graph)
- for xml in package.datas.get('demo_xml', []):
- name, ext = os.path.splitext(xml)
- logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:loading %s' % (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)
- else:
- tools.convert_xml_import(cr, m, tools.file_open(opj(m, xml)), idref, noupdate=True, **kwargs)
- cr.execute('update ir_module_module set demo=%s where name=%s', (True, package.name))
- package_todo.append(package.name)
- cr.execute("update ir_module_module set state='installed' where state in ('to upgrade', 'to install') and name=%s", (package.name,))
- cr.commit()
- statusi+=1
-
- pool = pooler.get_pool(cr.dbname)
- cr.execute('select * from ir_model where state=%s', ('manual',))
- for model in cr.dictfetchall():
- pool.get('ir.model').instanciate(cr, 1, model['model'], {})
-
- pool.get('ir.model.data')._process_end(cr, 1, package_todo)
- cr.commit()
+ # **kwargs is passed directly to convert_xml_import
+ if not status:
+ status={}
+
+ status = status.copy()
+ package_todo = []
+ statusi = 0
+ for package in graph:
+ status['progress'] = (float(statusi)+0.1)/len(graph)
+ m = package.name
+ logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s' % m)
+ sys.stdout.flush()
+ pool = pooler.get_pool(cr.dbname)
+ modules = pool.instanciate(m, cr)
+ cr.execute('select state, demo from ir_module_module where name=%s', (m,))
+ (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'):
+ init_module_objects(cr, m, modules)
+ for kind in ('init', 'update'):
+ for filename in package.datas.get('%s_xml' % kind, []):
+ mode = 'update'
+ if hasattr(package, 'init') or package_state=='to install':
+ mode = 'init'
+ logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:loading %s' % (m, filename))
+ name, ext = os.path.splitext(filename)
+ if ext == '.csv':
+ tools.convert_csv_import(cr, m, os.path.basename(filename), tools.file_open(opj(m, filename)).read(), idref, mode=mode)
+ elif ext == '.sql':
+ queries = tools.file_open(opj(m, filename)).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'):
+ status['progress'] = (float(statusi)+0.75)/len(graph)
+ for xml in package.datas.get('demo_xml', []):
+ name, ext = os.path.splitext(xml)
+ logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:loading %s' % (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)
+ else:
+ tools.convert_xml_import(cr, m, tools.file_open(opj(m, xml)), idref, noupdate=True, **kwargs)
+ cr.execute('update ir_module_module set demo=%s where name=%s', (True, package.name))
+ package_todo.append(package.name)
+ cr.execute("update ir_module_module set state='installed' where state in ('to upgrade', 'to install') and name=%s", (package.name,))
+ cr.commit()
+ statusi+=1
+
+ pool = pooler.get_pool(cr.dbname)
+ cr.execute('select * from ir_model where state=%s', ('manual',))
+ for model in cr.dictfetchall():
+ pool.get('ir.model').instanciate(cr, 1, model['model'], {})
+
+ pool.get('ir.model.data')._process_end(cr, 1, package_todo)
+ cr.commit()
def register_classes():
- module_list = get_modules()
- for package in create_graph(module_list):
- m = package.name
- logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:registering classes' % m)
- sys.stdout.flush()
-
- mod_path = get_module_path(m)
- if not os.path.isfile(mod_path+'.zip'):
- # XXX must restrict to only addons paths
- imp.load_module(m, *imp.find_module(m))
- else:
- import zipimport
- try:
- zimp = zipimport.zipimporter(mod_path+'.zip')
- zimp.load_module(m)
- except zipimport.ZipImportError:
- logger.notifyChannel('init', netsvc.LOG_ERROR, 'Couldn\'t find module %s' % m)
+ module_list = get_modules()
+ for package in create_graph(module_list):
+ m = package.name
+ logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:registering classes' % m)
+ sys.stdout.flush()
+
+ mod_path = get_module_path(m)
+ if not os.path.isfile(mod_path+'.zip'):
+ # XXX must restrict to only addons paths
+ imp.load_module(m, *imp.find_module(m))
+ else:
+ import zipimport
+ try:
+ zimp = zipimport.zipimporter(mod_path+'.zip')
+ zimp.load_module(m)
+ except zipimport.ZipImportError:
+ logger.notifyChannel('init', netsvc.LOG_ERROR, 'Couldn\'t find module %s' % m)
def load_modules(db, force_demo=False, status=None, update_module=False):
- if not status:
- status={}
- cr = db.cursor()
- force = []
- if force_demo:
- force.append('demo')
- if update_module:
- 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()
- load_module_graph(cr, graph, status, report=report)
- if report.get_report():
- logger.notifyChannel('init', netsvc.LOG_INFO, 'assert:%s' % report)
-
- for kind in ('init', 'demo', 'update'):
- tools.config[kind]={}
-
- cr.commit()
- if update_module:
- cr.execute("select id,name from ir_module_module where state in ('to remove')")
- for mod_id, mod_name in cr.fetchall():
- pool = pooler.get_pool(cr.dbname)
- cr.execute('select model,res_id from ir_model_data where not noupdate and module=%s order by id desc', (mod_name,))
- for rmod,rid in cr.fetchall():
- #
- # TO BE Improved:
- # I can not use the class_pool has _table could be defined in __init__
- # and I can not use the pool has the module could not be loaded in the pool
- #
- uid = 1
- pool.get(rmod).unlink(cr, uid, [rid])
- cr.commit()
- #
- # TODO: remove menu without actions of childs
- #
- cr.execute('''delete from
- ir_ui_menu
- where
- (id not in (select parent_id from ir_ui_menu where parent_id is not null))
- and
- (id not in (select res_id from ir_values where model='ir.ui.menu'))
- and
- (id not in (select res_id from ir_model_data where model='ir.ui.menu'))''')
-
- cr.execute("update ir_module_module set state=%s where state in ('to remove')", ('uninstalled', ))
- cr.commit()
- pooler.restart_pool(cr.dbname)
- cr.close()
+ if not status:
+ status={}
+ cr = db.cursor()
+ force = []
+ if force_demo:
+ force.append('demo')
+ if update_module:
+ 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()
+ load_module_graph(cr, graph, status, report=report)
+ if report.get_report():
+ logger.notifyChannel('init', netsvc.LOG_INFO, 'assert:%s' % report)
+
+ for kind in ('init', 'demo', 'update'):
+ tools.config[kind]={}
+
+ cr.commit()
+ if update_module:
+ cr.execute("select id,name from ir_module_module where state in ('to remove')")
+ for mod_id, mod_name in cr.fetchall():
+ pool = pooler.get_pool(cr.dbname)
+ cr.execute('select model,res_id from ir_model_data where not noupdate and module=%s order by id desc', (mod_name,))
+ for rmod,rid in cr.fetchall():
+ #
+ # TO BE Improved:
+ # I can not use the class_pool has _table could be defined in __init__
+ # and I can not use the pool has the module could not be loaded in the pool
+ #
+ uid = 1
+ pool.get(rmod).unlink(cr, uid, [rid])
+ cr.commit()
+ #
+ # TODO: remove menu without actions of childs
+ #
+ cr.execute('''delete from
+ ir_ui_menu
+ where
+ (id not in (select parent_id from ir_ui_menu where parent_id is not null))
+ and
+ (id not in (select res_id from ir_values where model='ir.ui.menu'))
+ and
+ (id not in (select res_id from ir_model_data where model='ir.ui.menu'))''')
+
+ cr.execute("update ir_module_module set state=%s where state in ('to remove')", ('uninstalled', ))
+ cr.commit()
+ pooler.restart_pool(cr.dbname)
+ cr.close()
diff --git a/bin/addons/base/__terp__.py b/bin/addons/base/__terp__.py
index 0de434c7e31..8903596f5db 100644
--- a/bin/addons/base/__terp__.py
+++ b/bin/addons/base/__terp__.py
@@ -26,44 +26,44 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
###############################################################################
{
- "name" : "Base",
- "version" : "1.0",
- "author" : "Tiny",
- "website" : "http://tinyerp.com",
- "category" : "Generic Modules/Base",
- "description": "The kernel of Tiny ERP, needed for all installation.",
- "depends" : [],
- "init_xml" : [
- "base_data.xml",
- "base_menu.xml",
- ],
- "demo_xml" : [
- "base_demo.xml",
- "res/partner/partner_demo.xml",
- "res/partner/crm_demo.xml",
- ],
- "update_xml" : [
- "base_update.xml",
- "ir/wizard/wizard_menu_view.xml",
- "ir/ir.xml",
- "ir/workflow/workflow_view.xml",
- "module/module_data.xml",
- "module/module_wizard.xml",
- "module/module_view.xml",
- "module/module_report.xml",
- "res/res_request_view.xml",
- "res/res_lang_view.xml",
- "res/partner/partner_report.xml",
- "res/partner/partner_view.xml",
- "res/partner/partner_wizard.xml",
- "res/bank_view.xml",
- "res/country_view.xml",
- "res/res_currency_view.xml",
- "res/partner/crm_view.xml",
- "res/partner/partner_data.xml",
- "res/ir_property_view.xml",
- "base_security.xml",
- ],
- "active": True,
- "installable": True,
+ "name" : "Base",
+ "version" : "1.0",
+ "author" : "Tiny",
+ "website" : "http://tinyerp.com",
+ "category" : "Generic Modules/Base",
+ "description": "The kernel of Tiny ERP, needed for all installation.",
+ "depends" : [],
+ "init_xml" : [
+ "base_data.xml",
+ "base_menu.xml",
+ ],
+ "demo_xml" : [
+ "base_demo.xml",
+ "res/partner/partner_demo.xml",
+ "res/partner/crm_demo.xml",
+ ],
+ "update_xml" : [
+ "base_update.xml",
+ "ir/wizard/wizard_menu_view.xml",
+ "ir/ir.xml",
+ "ir/workflow/workflow_view.xml",
+ "module/module_data.xml",
+ "module/module_wizard.xml",
+ "module/module_view.xml",
+ "module/module_report.xml",
+ "res/res_request_view.xml",
+ "res/res_lang_view.xml",
+ "res/partner/partner_report.xml",
+ "res/partner/partner_view.xml",
+ "res/partner/partner_wizard.xml",
+ "res/bank_view.xml",
+ "res/country_view.xml",
+ "res/res_currency_view.xml",
+ "res/partner/crm_view.xml",
+ "res/partner/partner_data.xml",
+ "res/ir_property_view.xml",
+ "base_security.xml",
+ ],
+ "active": True,
+ "installable": True,
}
diff --git a/bin/addons/base/ir/ir_actions.py b/bin/addons/base/ir/ir_actions.py
index a4a7ae71d1c..9e5f6435408 100644
--- a/bin/addons/base/ir/ir_actions.py
+++ b/bin/addons/base/ir/ir_actions.py
@@ -32,263 +32,263 @@ import tools
import time
class actions(osv.osv):
- _name = 'ir.actions.actions'
- _table = 'ir_actions'
- _columns = {
- '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,
- }
+ _name = 'ir.actions.actions'
+ _table = 'ir_actions'
+ _columns = {
+ '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,
+ }
actions()
class report_custom(osv.osv):
- _name = 'ir.actions.report.custom'
- _table = 'ir_act_report_custom'
- _sequence = 'ir_actions_id_seq'
- _columns = {
- 'name': fields.char('Report Name', size=64, required=True, translate=True),
- 'type': fields.char('Report Type', size=32, required=True),
- 'model':fields.char('Model', size=64, required=True),
- 'report_id': fields.integer('Report Ref.', required=True),
- 'usage': fields.char('Action Usage', size=32),
- 'multi': fields.boolean('On multiple doc.', help="If set to true, the action will not be displayed on the right toolbar of a form views.")
- }
- _defaults = {
- 'multi': lambda *a: False,
- 'type': lambda *a: 'ir.actions.report.custom',
- }
+ _name = 'ir.actions.report.custom'
+ _table = 'ir_act_report_custom'
+ _sequence = 'ir_actions_id_seq'
+ _columns = {
+ 'name': fields.char('Report Name', size=64, required=True, translate=True),
+ 'type': fields.char('Report Type', size=32, required=True),
+ 'model':fields.char('Model', size=64, required=True),
+ 'report_id': fields.integer('Report Ref.', required=True),
+ 'usage': fields.char('Action Usage', size=32),
+ 'multi': fields.boolean('On multiple doc.', help="If set to true, the action will not be displayed on the right toolbar of a form views.")
+ }
+ _defaults = {
+ 'multi': lambda *a: False,
+ 'type': lambda *a: 'ir.actions.report.custom',
+ }
report_custom()
class report_xml(osv.osv):
- def _report_content(self, cursor, user, ids, name, arg, context=None):
- res = {}
- for report in self.browse(cursor, user, ids, context=context):
- data = report[name + '_data']
- if not data and report[name[:-8]]:
- try:
- fp = tools.file_open(report[name[:-8]], mode='rb')
- data = fp.read()
- except:
- data = False
- res[report.id] = data
- return res
+ def _report_content(self, cursor, user, ids, name, arg, context=None):
+ res = {}
+ for report in self.browse(cursor, user, ids, context=context):
+ data = report[name + '_data']
+ if not data and report[name[:-8]]:
+ try:
+ fp = tools.file_open(report[name[:-8]], mode='rb')
+ data = fp.read()
+ except:
+ data = False
+ res[report.id] = data
+ return res
- def _report_content_inv(self, cursor, user, id, name, value, arg, context=None):
- self.write(cursor, user, id, {name+'_data': value}, context=context)
+ def _report_content_inv(self, cursor, user, id, name, value, arg, context=None):
+ self.write(cursor, user, id, {name+'_data': value}, context=context)
- def _report_sxw(self, cursor, user, ids, name, arg, context=None):
- res = {}
- for report in self.browse(cursor, user, ids, context=context):
- if report.report_rml:
- res[report.id] = report.report_rml.replace('.rml', '.sxw')
- else:
- res[report.id] = False
- return res
+ def _report_sxw(self, cursor, user, ids, name, arg, context=None):
+ res = {}
+ for report in self.browse(cursor, user, ids, context=context):
+ if report.report_rml:
+ res[report.id] = report.report_rml.replace('.rml', '.sxw')
+ else:
+ res[report.id] = False
+ return res
- _name = 'ir.actions.report.xml'
- _table = 'ir_act_report_xml'
- _sequence = 'ir_actions_id_seq'
- _columns = {
- 'name': fields.char('Name', size=64, required=True, translate=True),
- 'type': fields.char('Report Type', size=32, required=True),
- 'model': fields.char('Model', size=64, required=True),
- 'report_name': fields.char('Internal Name', size=64, required=True),
- 'report_xsl': fields.char('XSL path', size=256),
- 'report_xml': fields.char('XML path', size=256),
- 'report_rml': fields.char('RML path', size=256,
- help="The .rml path of the file or NULL if the content is in report_rml_content"),
- 'report_sxw': fields.function(_report_sxw, method=True, type='char',
- string='SXW path'),
- 'report_sxw_content_data': fields.binary('SXW content'),
- 'report_rml_content_data': fields.binary('RML content'),
- 'report_sxw_content': fields.function(_report_content,
- fnct_inv=_report_content_inv, method=True,
- type='binary', string='SXW content',),
- 'report_rml_content': fields.function(_report_content,
- fnct_inv=_report_content_inv, method=True,
- type='binary', string='RML content'),
- 'auto': fields.boolean('Automatic XSL:RML', required=True),
- 'usage': fields.char('Action Usage', size=32),
- 'header': fields.boolean('Add RML header',
- help="Add or not the coporate RML header"),
- 'multi': fields.boolean('On multiple doc.',
- help="If set to true, the action will not be displayed on the right toolbar of a form views."),
- 'report_type': fields.selection([
- ('pdf', 'pdf'),
- ('html', 'html'),
- ('raw', 'raw'),
- ('sxw', 'sxw'),
- ], string='Type', required=True),
- 'groups_id': fields.many2many('res.groups', 'res_groups_report_rel', 'uid', 'gid', 'Groups')
-
- }
- _defaults = {
- 'type': lambda *a: 'ir.actions.report.xml',
- 'multi': lambda *a: False,
- 'auto': lambda *a: True,
- 'header': lambda *a: True,
- 'report_sxw_content': lambda *a: False,
- 'report_type': lambda *a: 'pdf',
- }
+ _name = 'ir.actions.report.xml'
+ _table = 'ir_act_report_xml'
+ _sequence = 'ir_actions_id_seq'
+ _columns = {
+ 'name': fields.char('Name', size=64, required=True, translate=True),
+ 'type': fields.char('Report Type', size=32, required=True),
+ 'model': fields.char('Model', size=64, required=True),
+ 'report_name': fields.char('Internal Name', size=64, required=True),
+ 'report_xsl': fields.char('XSL path', size=256),
+ 'report_xml': fields.char('XML path', size=256),
+ 'report_rml': fields.char('RML path', size=256,
+ help="The .rml path of the file or NULL if the content is in report_rml_content"),
+ 'report_sxw': fields.function(_report_sxw, method=True, type='char',
+ string='SXW path'),
+ 'report_sxw_content_data': fields.binary('SXW content'),
+ 'report_rml_content_data': fields.binary('RML content'),
+ 'report_sxw_content': fields.function(_report_content,
+ fnct_inv=_report_content_inv, method=True,
+ type='binary', string='SXW content',),
+ 'report_rml_content': fields.function(_report_content,
+ fnct_inv=_report_content_inv, method=True,
+ type='binary', string='RML content'),
+ 'auto': fields.boolean('Automatic XSL:RML', required=True),
+ 'usage': fields.char('Action Usage', size=32),
+ 'header': fields.boolean('Add RML header',
+ help="Add or not the coporate RML header"),
+ 'multi': fields.boolean('On multiple doc.',
+ help="If set to true, the action will not be displayed on the right toolbar of a form views."),
+ 'report_type': fields.selection([
+ ('pdf', 'pdf'),
+ ('html', 'html'),
+ ('raw', 'raw'),
+ ('sxw', 'sxw'),
+ ], string='Type', required=True),
+ 'groups_id': fields.many2many('res.groups', 'res_groups_report_rel', 'uid', 'gid', 'Groups')
+
+ }
+ _defaults = {
+ 'type': lambda *a: 'ir.actions.report.xml',
+ 'multi': lambda *a: False,
+ 'auto': lambda *a: True,
+ 'header': lambda *a: True,
+ 'report_sxw_content': lambda *a: False,
+ 'report_type': lambda *a: 'pdf',
+ }
report_xml()
class act_window(osv.osv):
- _name = 'ir.actions.act_window'
- _table = 'ir_act_window'
- _sequence = 'ir_actions_id_seq'
+ _name = 'ir.actions.act_window'
+ _table = 'ir_act_window'
+ _sequence = 'ir_actions_id_seq'
- def _views_get_fnc(self, cr, uid, ids, name, arg, context={}):
- res={}
- for act in self.browse(cr, uid, ids):
- res[act.id]=[(view.view_id.id, view.view_mode) for view in act.view_ids]
- if (not act.view_ids):
- modes = act.view_mode.split(',')
- find = False
- if act.view_id.id:
- res[act.id].append((act.view_id.id, act.view_id.type))
- for t in modes:
- if act.view_id and (t == act.view_id.type) and not find:
- find = True
- continue
- res[act.id].append((False, t))
+ def _views_get_fnc(self, cr, uid, ids, name, arg, context={}):
+ res={}
+ for act in self.browse(cr, uid, ids):
+ res[act.id]=[(view.view_id.id, view.view_mode) for view in act.view_ids]
+ if (not act.view_ids):
+ modes = act.view_mode.split(',')
+ find = False
+ if act.view_id.id:
+ res[act.id].append((act.view_id.id, act.view_id.type))
+ for t in modes:
+ if act.view_id and (t == act.view_id.type) and not find:
+ find = True
+ continue
+ res[act.id].append((False, t))
- if 'calendar' not in modes:
- mobj = self.pool.get(act.res_model)
- if mobj._date_name in mobj._columns:
- res[act.id].append((False, 'calendar'))
- return res
+ if 'calendar' not in modes:
+ mobj = self.pool.get(act.res_model)
+ if mobj._date_name in mobj._columns:
+ res[act.id].append((False, 'calendar'))
+ return res
- _columns = {
- 'name': fields.char('Action Name', size=64, translate=True),
- 'type': fields.char('Action Type', size=32, required=True),
- 'view_id': fields.many2one('ir.ui.view', 'View Ref.', ondelete='cascade'),
- 'domain': fields.char('Domain Value', size=250),
- 'context': fields.char('Context Value', size=250),
- 'res_model': fields.char('Model', size=64),
- 'src_model': fields.char('Source model', size=64),
- 'target': fields.selection([('current','Current Window'),('new','New Window')], 'Target Window'),
- 'view_type': fields.selection((('tree','Tree'),('form','Form')),string='Type of view'),
- 'view_mode': fields.char('Mode of view', size=250),
- 'usage': fields.char('Action Usage', size=32),
- 'view_ids': fields.one2many('ir.actions.act_window.view', 'act_window_id', 'Views'),
- 'views': fields.function(_views_get_fnc, method=True, type='binary', string='Views'),
- 'limit': fields.integer('Limit', help='Default limit for the list view'),
- 'auto_refresh': fields.integer('Auto-Refresh',
- help='Add an auto-refresh on the view'),
- }
- _defaults = {
- 'type': lambda *a: 'ir.actions.act_window',
- 'view_type': lambda *a: 'form',
- 'view_mode': lambda *a: 'tree,form',
- 'context': lambda *a: '{}',
- 'limit': lambda *a: 80,
- 'target': lambda *a: 'current',
- 'auto_refresh': lambda *a: 0,
- }
+ _columns = {
+ 'name': fields.char('Action Name', size=64, translate=True),
+ 'type': fields.char('Action Type', size=32, required=True),
+ 'view_id': fields.many2one('ir.ui.view', 'View Ref.', ondelete='cascade'),
+ 'domain': fields.char('Domain Value', size=250),
+ 'context': fields.char('Context Value', size=250),
+ 'res_model': fields.char('Model', size=64),
+ 'src_model': fields.char('Source model', size=64),
+ 'target': fields.selection([('current','Current Window'),('new','New Window')], 'Target Window'),
+ 'view_type': fields.selection((('tree','Tree'),('form','Form')),string='Type of view'),
+ 'view_mode': fields.char('Mode of view', size=250),
+ 'usage': fields.char('Action Usage', size=32),
+ 'view_ids': fields.one2many('ir.actions.act_window.view', 'act_window_id', 'Views'),
+ 'views': fields.function(_views_get_fnc, method=True, type='binary', string='Views'),
+ 'limit': fields.integer('Limit', help='Default limit for the list view'),
+ 'auto_refresh': fields.integer('Auto-Refresh',
+ help='Add an auto-refresh on the view'),
+ }
+ _defaults = {
+ 'type': lambda *a: 'ir.actions.act_window',
+ 'view_type': lambda *a: 'form',
+ 'view_mode': lambda *a: 'tree,form',
+ 'context': lambda *a: '{}',
+ 'limit': lambda *a: 80,
+ 'target': lambda *a: 'current',
+ 'auto_refresh': lambda *a: 0,
+ }
act_window()
class act_window_view(osv.osv):
- _name = 'ir.actions.act_window.view'
- _table = 'ir_act_window_view'
- _rec_name = 'view_id'
- _columns = {
- 'sequence': fields.integer('Sequence'),
- 'view_id': fields.many2one('ir.ui.view', 'View'),
- 'view_mode': fields.selection((
- ('tree', 'Tree'),
- ('form', 'Form'),
- ('graph', 'Graph'),
- ('calendar', 'Calendar')), string='Type of view', required=True),
- 'act_window_id': fields.many2one('ir.actions.act_window', 'Action', ondelete='cascade'),
- 'multi': fields.boolean('On multiple doc.',
- help="If set to true, the action will not be displayed on the right toolbar of a form views."),
- }
- _defaults = {
- 'multi': lambda *a: False,
- }
- _order = 'sequence'
+ _name = 'ir.actions.act_window.view'
+ _table = 'ir_act_window_view'
+ _rec_name = 'view_id'
+ _columns = {
+ 'sequence': fields.integer('Sequence'),
+ 'view_id': fields.many2one('ir.ui.view', 'View'),
+ 'view_mode': fields.selection((
+ ('tree', 'Tree'),
+ ('form', 'Form'),
+ ('graph', 'Graph'),
+ ('calendar', 'Calendar')), string='Type of view', required=True),
+ 'act_window_id': fields.many2one('ir.actions.act_window', 'Action', ondelete='cascade'),
+ 'multi': fields.boolean('On multiple doc.',
+ help="If set to true, the action will not be displayed on the right toolbar of a form views."),
+ }
+ _defaults = {
+ 'multi': lambda *a: False,
+ }
+ _order = 'sequence'
act_window_view()
class act_wizard(osv.osv):
- _name = 'ir.actions.wizard'
- _table = 'ir_act_wizard'
- _sequence = 'ir_actions_id_seq'
- _columns = {
- 'name': fields.char('Wizard info', size=64, required=True, translate=True),
- 'type': fields.char('Action type', size=32, required=True),
- 'wiz_name': fields.char('Wizard name', size=64, required=True),
- 'multi': fields.boolean('Action on multiple doc.', help="If set to true, the wizard will not be displayed on the right toolbar of a form views."),
- 'groups_id': fields.many2many('res.groups', 'res_groups_wizard_rel', 'uid', 'gid', 'Groups')
- }
- _defaults = {
- 'type': lambda *a: 'ir.actions.wizard',
- 'multi': lambda *a: False,
- }
+ _name = 'ir.actions.wizard'
+ _table = 'ir_act_wizard'
+ _sequence = 'ir_actions_id_seq'
+ _columns = {
+ 'name': fields.char('Wizard info', size=64, required=True, translate=True),
+ 'type': fields.char('Action type', size=32, required=True),
+ 'wiz_name': fields.char('Wizard name', size=64, required=True),
+ 'multi': fields.boolean('Action on multiple doc.', help="If set to true, the wizard will not be displayed on the right toolbar of a form views."),
+ 'groups_id': fields.many2many('res.groups', 'res_groups_wizard_rel', 'uid', 'gid', 'Groups')
+ }
+ _defaults = {
+ 'type': lambda *a: 'ir.actions.wizard',
+ 'multi': lambda *a: False,
+ }
act_wizard()
class act_url(osv.osv):
- _name = 'ir.actions.url'
- _table = 'ir_act_url'
- _sequence = 'ir_actions_id_seq'
- _columns = {
- 'name': fields.char('Action Name', size=64, translate=True),
- 'type': fields.char('Action Type', size=32, required=True),
- 'url': fields.text('Action Url',required=True),
- 'target': fields.selection((
- ('new', 'New Window'),
- ('self', 'This Window')),
- 'Action Target', required=True
- )
- }
- _defaults = {
- 'type': lambda *a: 'ir.actions.act_url',
- 'target': lambda *a: 'new'
- }
+ _name = 'ir.actions.url'
+ _table = 'ir_act_url'
+ _sequence = 'ir_actions_id_seq'
+ _columns = {
+ 'name': fields.char('Action Name', size=64, translate=True),
+ 'type': fields.char('Action Type', size=32, required=True),
+ 'url': fields.text('Action Url',required=True),
+ 'target': fields.selection((
+ ('new', 'New Window'),
+ ('self', 'This Window')),
+ 'Action Target', required=True
+ )
+ }
+ _defaults = {
+ 'type': lambda *a: 'ir.actions.act_url',
+ 'target': lambda *a: 'new'
+ }
act_url()
#
# Actions that are run on the server side
#
class actions_server(osv.osv):
- _name = 'ir.actions.server'
- _table = 'ir_act_server'
- _sequence = 'ir_actions_id_seq'
- _columns = {
- 'name': fields.char('Action Name', required=True, size=64),
- 'state': fields.selection([
- ('python','Python Code'),
- ('dummy','Dummy'),
- ('trigger','Trigger'),
- ('email','Email'),
- ('sms','SMS'),
- ('object_create','Create Object'),
- ('object_write','Write Object'),
- ('client_action','Client Action'),
- ('other','Others Actions'),
- ], 'Action State', required=True, size=32),
- 'code': fields.text('Python Code'),
- 'sequence': fields.integer('Sequence'),
- 'model_id': fields.many2one('ir.model', 'Model', required=True),
- 'trigger_name': fields.char('Trigger Name', size=128),
- 'trigger_object': fields.char('Trigger Object', size=128),
- 'trigger_object_id': fields.char('Trigger Object ID', size=128),
- 'message': fields.text('Message', translate=True),
- 'address': fields.char('Email Address', size=128),
- '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),
- }
- _defaults = {
- 'state': lambda *a: 'dummy',
- 'type': lambda *a: 'ir.actions.server',
- 'sequence': lambda *a: 0,
- 'code': lambda *a: """# You can use the following variables
+ _name = 'ir.actions.server'
+ _table = 'ir_act_server'
+ _sequence = 'ir_actions_id_seq'
+ _columns = {
+ 'name': fields.char('Action Name', required=True, size=64),
+ 'state': fields.selection([
+ ('python','Python Code'),
+ ('dummy','Dummy'),
+ ('trigger','Trigger'),
+ ('email','Email'),
+ ('sms','SMS'),
+ ('object_create','Create Object'),
+ ('object_write','Write Object'),
+ ('client_action','Client Action'),
+ ('other','Others Actions'),
+ ], 'Action State', required=True, size=32),
+ 'code': fields.text('Python Code'),
+ 'sequence': fields.integer('Sequence'),
+ 'model_id': fields.many2one('ir.model', 'Model', required=True),
+ 'trigger_name': fields.char('Trigger Name', size=128),
+ 'trigger_object': fields.char('Trigger Object', size=128),
+ 'trigger_object_id': fields.char('Trigger Object ID', size=128),
+ 'message': fields.text('Message', translate=True),
+ 'address': fields.char('Email Address', size=128),
+ '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),
+ }
+ _defaults = {
+ 'state': lambda *a: 'dummy',
+ 'type': lambda *a: 'ir.actions.server',
+ 'sequence': lambda *a: 0,
+ 'code': lambda *a: """# You can use the following variables
# - object
# - object2
# - time
@@ -297,43 +297,43 @@ class actions_server(osv.osv):
# - ids
# If you plan to return an action, assign: action = {...}
"""
- }
- #
- # Context should contains:
- # ids : original ids
- # id : current id of the object
- # OUT:
- # False : Finnished correctly
- # ACTION_ID : Action to launch
- def run(self, cr, uid, ids, context={}):
- for action in self.browse(cr, uid, ids, context):
- if action.state=='python':
- localdict = {
- 'self': self.pool.get(action.model_id.model),
- 'context': context,
- 'time': time,
- 'ids': ids,
- 'cr': cr,
- 'uid': uid
- }
- print action.code
- exec action.code in localdict
- print localdict.keys()
- if 'action' in localdict:
- return localdict['action']
- return False
+ }
+ #
+ # Context should contains:
+ # ids : original ids
+ # id : current id of the object
+ # OUT:
+ # False : Finnished correctly
+ # ACTION_ID : Action to launch
+ def run(self, cr, uid, ids, context={}):
+ for action in self.browse(cr, uid, ids, context):
+ if action.state=='python':
+ localdict = {
+ 'self': self.pool.get(action.model_id.model),
+ 'context': context,
+ 'time': time,
+ 'ids': ids,
+ 'cr': cr,
+ 'uid': uid
+ }
+ print action.code
+ exec action.code in localdict
+ print localdict.keys()
+ if 'action' in localdict:
+ return localdict['action']
+ return False
actions_server()
class act_window_close(osv.osv):
- _name = 'ir.actions.act_window_close'
- _table = 'ir_actions'
- _sequence = 'ir_actions_id_seq'
- _columns = {
- 'name': fields.char('Action Name', size=64, translate=True),
- 'type': fields.char('Action Type', size=32, required=True),
- }
- _defaults = {
- 'type': lambda *a: 'ir.actions.act_window_close',
- }
+ _name = 'ir.actions.act_window_close'
+ _table = 'ir_actions'
+ _sequence = 'ir_actions_id_seq'
+ _columns = {
+ 'name': fields.char('Action Name', size=64, translate=True),
+ 'type': fields.char('Action Type', size=32, required=True),
+ }
+ _defaults = {
+ 'type': lambda *a: 'ir.actions.act_window_close',
+ }
act_window_close()
diff --git a/bin/addons/base/ir/ir_attachment.py b/bin/addons/base/ir/ir_attachment.py
index 4c505462473..f4e931826b1 100644
--- a/bin/addons/base/ir/ir_attachment.py
+++ b/bin/addons/base/ir/ir_attachment.py
@@ -30,16 +30,16 @@
from osv import fields,osv
class ir_attachment(osv.osv):
- _name = 'ir.attachment'
- _columns = {
- 'name': fields.char('Attachment Name',size=64, required=True),
- 'datas': fields.binary('Data'),
- 'datas_fname': fields.char('Data Filename',size=64),
- 'description': fields.text('Description'),
- # Not required due to the document module !
- 'res_model': fields.char('Resource Model',size=64, readonly=True),
- 'res_id': fields.integer('Resource ID', readonly=True),
- 'link': fields.char('Link', size=256)
- }
+ _name = 'ir.attachment'
+ _columns = {
+ 'name': fields.char('Attachment Name',size=64, required=True),
+ 'datas': fields.binary('Data'),
+ 'datas_fname': fields.char('Data Filename',size=64),
+ 'description': fields.text('Description'),
+ # Not required due to the document module !
+ 'res_model': fields.char('Resource Model',size=64, readonly=True),
+ 'res_id': fields.integer('Resource ID', readonly=True),
+ 'link': fields.char('Link', size=256)
+ }
ir_attachment()
diff --git a/bin/addons/base/ir/ir_board.py b/bin/addons/base/ir/ir_board.py
index 380e7c183a6..f8bf28a4fe1 100644
--- a/bin/addons/base/ir/ir_board.py
+++ b/bin/addons/base/ir/ir_board.py
@@ -30,12 +30,12 @@
from osv import fields,osv
class board(osv.osv):
- _name = 'ir.board'
- def create(self, cr, user, vals, context={}):
- return False
- def copy(self, cr, uid, id, default=None, context={}):
- return False
- _columns = {
- 'name': fields.char('Board', size=64),
- }
+ _name = 'ir.board'
+ def create(self, cr, user, vals, context={}):
+ return False
+ def copy(self, cr, uid, id, default=None, context={}):
+ return False
+ _columns = {
+ 'name': fields.char('Board', size=64),
+ }
board()
diff --git a/bin/addons/base/ir/ir_cron.py b/bin/addons/base/ir/ir_cron.py
index 1f7376b8b28..d04251ae4d3 100644
--- a/bin/addons/base/ir/ir_cron.py
+++ b/bin/addons/base/ir/ir_cron.py
@@ -28,13 +28,13 @@
##############################################################################
#
# SPEC: Execute "model.function(*eval(args))" periodically
-# date : date to execute the job or NULL if directly
-# delete_after: delete the ir.cron entry after execution
-# interval_* : period
-# max_repeat : number of execution or NULL if endlessly
+# date : date to execute the job or NULL if directly
+# delete_after: delete the ir.cron entry after execution
+# interval_* : period
+# max_repeat : number of execution or NULL if endlessly
#
# TODO:
-# Error treatment: exception, request, ... -> send request to uid
+# Error treatment: exception, request, ... -> send request to uid
#
from mx import DateTime
@@ -47,85 +47,85 @@ from osv import fields,osv
next_wait = 60
_intervalTypes = {
- 'work_days': lambda interval: DateTime.RelativeDateTime(days=interval),
- 'days': lambda interval: DateTime.RelativeDateTime(days=interval),
- 'hours': lambda interval: DateTime.RelativeDateTime(hours=interval),
- 'weeks': lambda interval: DateTime.RelativeDateTime(days=7*interval),
- 'months': lambda interval: DateTime.RelativeDateTime(months=interval),
- 'minutes': lambda interval: DateTime.RelativeDateTime(minutes=interval),
+ 'work_days': lambda interval: DateTime.RelativeDateTime(days=interval),
+ 'days': lambda interval: DateTime.RelativeDateTime(days=interval),
+ 'hours': lambda interval: DateTime.RelativeDateTime(hours=interval),
+ 'weeks': lambda interval: DateTime.RelativeDateTime(days=7*interval),
+ 'months': lambda interval: DateTime.RelativeDateTime(months=interval),
+ 'minutes': lambda interval: DateTime.RelativeDateTime(minutes=interval),
}
class ir_cron(osv.osv, netsvc.Agent):
- _name = "ir.cron"
- _columns = {
- 'name': fields.char('Name', size=60, required=True),
- 'user_id': fields.many2one('res.users', 'User', required=True),
- 'active': fields.boolean('Active'),
- 'interval_number': fields.integer('Interval Number'),
- 'interval_type': fields.selection( [('minutes', 'Minutes'),
- ('hours', 'Hours'), ('work_days','Work Days'), ('days', 'Days'),('weeks', 'Weeks'), ('months', 'Months')], 'Interval Unit'),
- 'numbercall': fields.integer('Number of calls', help='Number of time the function is called,\na negative number indicates that the function will always be called'),
- 'doall' : fields.boolean('Repeat missed'),
- 'nextcall' : fields.datetime('Next call date', required=True),
- 'model': fields.char('Model', size=64),
- 'function': fields.char('Function', size=64),
- 'args': fields.text('Arguments'),
- 'priority': fields.integer('Priority', help='0=Very Urgent\n10=Not urgent')
- }
+ _name = "ir.cron"
+ _columns = {
+ 'name': fields.char('Name', size=60, required=True),
+ 'user_id': fields.many2one('res.users', 'User', required=True),
+ 'active': fields.boolean('Active'),
+ 'interval_number': fields.integer('Interval Number'),
+ 'interval_type': fields.selection( [('minutes', 'Minutes'),
+ ('hours', 'Hours'), ('work_days','Work Days'), ('days', 'Days'),('weeks', 'Weeks'), ('months', 'Months')], 'Interval Unit'),
+ 'numbercall': fields.integer('Number of calls', help='Number of time the function is called,\na negative number indicates that the function will always be called'),
+ 'doall' : fields.boolean('Repeat missed'),
+ 'nextcall' : fields.datetime('Next call date', required=True),
+ 'model': fields.char('Model', size=64),
+ 'function': fields.char('Function', size=64),
+ 'args': fields.text('Arguments'),
+ 'priority': fields.integer('Priority', help='0=Very Urgent\n10=Not urgent')
+ }
- _defaults = {
- 'nextcall' : lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
- 'priority' : lambda *a: 5,
- 'user_id' : lambda obj,cr,uid,context: uid,
- 'interval_number' : lambda *a: 1,
- 'interval_type' : lambda *a: 'months',
- 'numbercall' : lambda *a: 1,
- 'active' : lambda *a: 1,
- 'doall' : lambda *a: 1
- }
+ _defaults = {
+ 'nextcall' : lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
+ 'priority' : lambda *a: 5,
+ 'user_id' : lambda obj,cr,uid,context: uid,
+ 'interval_number' : lambda *a: 1,
+ 'interval_type' : lambda *a: 'months',
+ 'numbercall' : lambda *a: 1,
+ 'active' : lambda *a: 1,
+ 'doall' : lambda *a: 1
+ }
- def _callback(self, cr, uid, model, func, args):
- args = (args or []) and eval(args)
- m=self.pool.get(model)
- if m and hasattr(m, func):
- f = getattr(m, func)
- f(cr, uid, *args)
+ def _callback(self, cr, uid, model, func, args):
+ args = (args or []) and eval(args)
+ m=self.pool.get(model)
+ if m and hasattr(m, func):
+ f = getattr(m, func)
+ f(cr, uid, *args)
- def _poolJobs(self, db_name, check=False):
- now = DateTime.now()
- #FIXME: multidb. Solution: a l'instanciation d'une nouvelle connection bd (ds pooler) fo que j'instancie
- # un nouveau pooljob avec comme parametre la bd
- try:
- cr = pooler.get_db(db_name).cursor()
- except:
- return False
+ def _poolJobs(self, db_name, check=False):
+ now = DateTime.now()
+ #FIXME: multidb. Solution: a l'instanciation d'une nouvelle connection bd (ds pooler) fo que j'instancie
+ # un nouveau pooljob avec comme parametre la bd
+ try:
+ cr = pooler.get_db(db_name).cursor()
+ except:
+ return False
- try:
- cr.execute('select * from ir_cron where numbercall<>0 and active and nextcall<=now() order by priority')
- for job in cr.dictfetchall():
- nextcall = DateTime.strptime(job['nextcall'], '%Y-%m-%d %H:%M:%S')
- numbercall = job['numbercall']
-
- ok = False
- while nextcall<now and numbercall:
- if numbercall > 0:
- numbercall -= 1
- if not ok or job['doall']:
- self._callback(cr, job['user_id'], job['model'], job['function'], job['args'])
- if numbercall:
- nextcall += _intervalTypes[job['interval_type']](job['interval_number'])
- ok = True
- 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.commit()
- finally:
- cr.close()
- #
- # Can be improved to do at the min(min(nextcalls), time()+next_wait)
- # But is this an improvement ?
- #
- if not check:
- self.setAlarm(self._poolJobs, int(time.time())+next_wait, [db_name])
+ try:
+ cr.execute('select * from ir_cron where numbercall<>0 and active and nextcall<=now() order by priority')
+ for job in cr.dictfetchall():
+ nextcall = DateTime.strptime(job['nextcall'], '%Y-%m-%d %H:%M:%S')
+ numbercall = job['numbercall']
+
+ ok = False
+ while nextcall<now and numbercall:
+ if numbercall > 0:
+ numbercall -= 1
+ if not ok or job['doall']:
+ self._callback(cr, job['user_id'], job['model'], job['function'], job['args'])
+ if numbercall:
+ nextcall += _intervalTypes[job['interval_type']](job['interval_number'])
+ ok = True
+ 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.commit()
+ finally:
+ cr.close()
+ #
+ # Can be improved to do at the min(min(nextcalls), time()+next_wait)
+ # But is this an improvement ?
+ #
+ if not check:
+ self.setAlarm(self._poolJobs, int(time.time())+next_wait, [db_name])
ir_cron()
diff --git a/bin/addons/base/ir/ir_default.py b/bin/addons/base/ir/ir_default.py
index bec15da4573..dccb410f7ce 100644
--- a/bin/addons/base/ir/ir_default.py
+++ b/bin/addons/base/ir/ir_default.py
@@ -30,26 +30,26 @@
from osv import fields,osv
class ir_default(osv.osv):
- _name = 'ir.default'
- _columns = {
- 'field_tbl': fields.char('Model',size=64),
- 'field_name': fields.char('Model field',size=64),
- 'value': fields.char('Default Value',size=64),
- 'uid': fields.many2one('res.users', 'Users'),
- 'page': fields.char('View',size=64),
- 'ref_table': fields.char('Table Ref.',size=64),
- 'ref_id': fields.integer('ID Ref.',size=64),
- 'company_id': fields.many2one('res.company','Company')
- }
+ _name = 'ir.default'
+ _columns = {
+ 'field_tbl': fields.char('Model',size=64),
+ 'field_name': fields.char('Model field',size=64),
+ 'value': fields.char('Default Value',size=64),
+ 'uid': fields.many2one('res.users', 'Users'),
+ 'page': fields.char('View',size=64),
+ 'ref_table': fields.char('Table Ref.',size=64),
+ 'ref_id': fields.integer('ID Ref.',size=64),
+ 'company_id': fields.many2one('res.company','Company')
+ }
- def _get_company_id(self, cr, uid, context={}):
- res = self.pool.get('res.users').read(cr, uid, [uid], ['company_id'], context=context)
- if res and res[0]['company_id']:
- return res[0]['company_id'][0]
- return False
+ def _get_company_id(self, cr, uid, context={}):
+ res = self.pool.get('res.users').read(cr, uid, [uid], ['company_id'], context=context)
+ if res and res[0]['company_id']:
+ return res[0]['company_id'][0]
+ return False
- _defaults = {
- 'company_id': _get_company_id,
- }
+ _defaults = {
+ 'company_id': _get_company_id,
+ }
ir_default()
diff --git a/bin/addons/base/ir/ir_exports.py b/bin/addons/base/ir/ir_exports.py
index c5329ab5191..5b2cb625d3d 100644
--- a/bin/addons/base/ir/ir_exports.py
+++ b/bin/addons/base/ir/ir_exports.py
@@ -31,20 +31,20 @@ from osv import fields,osv
class ir_exports(osv.osv):
- _name = "ir.exports"
- _columns = {
- 'name': fields.char('Export name', size=128),
- 'resource': fields.char('Resource', size=128),
- 'export_fields': fields.one2many('ir.exports.line', 'export_id',
- 'Export Id'),
- }
+ _name = "ir.exports"
+ _columns = {
+ 'name': fields.char('Export name', size=128),
+ 'resource': fields.char('Resource', size=128),
+ 'export_fields': fields.one2many('ir.exports.line', 'export_id',
+ 'Export Id'),
+ }
ir_exports()
class ir_exports_line(osv.osv):
- _name = 'ir.exports.line'
- _columns = {
- 'name': fields.char('Field name', size=64),
- 'export_id': fields.many2one('ir.exports', 'Exportation', select=True, ondelete='cascade'),
- }
+ _name = 'ir.exports.line'
+ _columns = {
+ 'name': fields.char('Field name', size=64),
+ 'export_id': fields.many2one('ir.exports', 'Exportation', select=True, ondelete='cascade'),
+ }
ir_exports_line()
diff --git a/bin/addons/base/ir/ir_model.py b/bin/addons/base/ir/ir_model.py
index 0c6bfc7edb1..5d971e079e7 100644
--- a/bin/addons/base/ir/ir_model.py
+++ b/bin/addons/base/ir/ir_model.py
@@ -37,395 +37,395 @@ import tools
import pooler
def _get_fields_type(self, cr, uid, context=None):
- cr.execute('select distinct ttype,ttype from ir_model_fields')
- return cr.fetchall()
+ cr.execute('select distinct ttype,ttype from ir_model_fields')
+ return cr.fetchall()
class ir_model(osv.osv):
- _name = 'ir.model'
- _description = "Objects"
- _rec_name = 'name'
- _columns = {
- 'name': fields.char('Model Name', size=64, translate=True, required=True),
- 'model': fields.char('Object Name', size=64, required=True, search=1),
- 'info': fields.text('Information'),
- 'field_id': fields.one2many('ir.model.fields', 'model_id', 'Fields', required=True),
- 'state': fields.selection([('manual','Custom Object'),('base','Base Field')],'Manualy Created',readonly=1),
- }
- _defaults = {
- 'model': lambda *a: 'x_',
- 'state': lambda self,cr,uid,ctx={}: (ctx and ctx.get('manual',False)) and 'manual' or 'base',
- }
-
- def _check_model_name(self, cr, uid, ids):
- for model in self.browse(cr, uid, ids):
- if model.state=='manual':
- if not model.model.startswith('x_'):
- return False
- if not re.match('^[a-z_A-Z0-9]+$',model.model):
- return False
- return True
+ _name = 'ir.model'
+ _description = "Objects"
+ _rec_name = 'name'
+ _columns = {
+ 'name': fields.char('Model Name', size=64, translate=True, required=True),
+ 'model': fields.char('Object Name', size=64, required=True, search=1),
+ 'info': fields.text('Information'),
+ 'field_id': fields.one2many('ir.model.fields', 'model_id', 'Fields', required=True),
+ 'state': fields.selection([('manual','Custom Object'),('base','Base Field')],'Manualy Created',readonly=1),
+ }
+ _defaults = {
+ 'model': lambda *a: 'x_',
+ 'state': lambda self,cr,uid,ctx={}: (ctx and ctx.get('manual',False)) and 'manual' or 'base',
+ }
+
+ def _check_model_name(self, cr, uid, ids):
+ for model in self.browse(cr, uid, ids):
+ if model.state=='manual':
+ if not model.model.startswith('x_'):
+ return False
+ if not re.match('^[a-z_A-Z0-9]+$',model.model):
+ return False
+ return True
- _constraints = [
- (_check_model_name, 'The model name must start with x_ and not contain any special character !', ['model']),
- ]
- def unlink(self, cr, user, ids, context=None):
- for model in self.browse(cr, user, ids, context):
- if model.state <> 'manual':
- raise except_orm(_('Error'), _("You can not remove the model '%s' !") %(field.name,))
- res = super(ir_model, self).unlink(cr, user, ids, context)
- pooler.restart_pool(cr.dbname)
- return res
+ _constraints = [
+ (_check_model_name, 'The model name must start with x_ and not contain any special character !', ['model']),
+ ]
+ def unlink(self, cr, user, ids, context=None):
+ for model in self.browse(cr, user, ids, context):
+ if model.state <> 'manual':
+ raise except_orm(_('Error'), _("You can not remove the model '%s' !") %(field.name,))
+ res = super(ir_model, self).unlink(cr, user, ids, context)
+ pooler.restart_pool(cr.dbname)
+ return res
- def create(self, cr, user, vals, context=None):
- if context and context.get('manual',False):
- vals['state']='manual'
- res = super(ir_model,self).create(cr, user, vals, context)
- if vals.get('state','base')=='manual':
- pooler.restart_pool(cr.dbname)
- return res
+ def create(self, cr, user, vals, context=None):
+ if context and context.get('manual',False):
+ vals['state']='manual'
+ res = super(ir_model,self).create(cr, user, vals, context)
+ if vals.get('state','base')=='manual':
+ pooler.restart_pool(cr.dbname)
+ return res
- def instanciate(self, cr, user, model, context={}):
- class x_custom_model(osv.osv):
- pass
- x_custom_model._name = model
- x_custom_model._module = False
- x_custom_model.createInstance(self.pool, '', cr)
- if 'x_name' in x_custom_model._columns:
- x_custom_model._rec_name = 'x_name'
- else:
- x_custom_model._rec_name = x_custom_model._columns.keys()[0]
+ def instanciate(self, cr, user, model, context={}):
+ class x_custom_model(osv.osv):
+ pass
+ x_custom_model._name = model
+ x_custom_model._module = False
+ x_custom_model.createInstance(self.pool, '', cr)
+ if 'x_name' in x_custom_model._columns:
+ x_custom_model._rec_name = 'x_name'
+ else:
+ x_custom_model._rec_name = x_custom_model._columns.keys()[0]
ir_model()
class ir_model_fields(osv.osv):
- _name = 'ir.model.fields'
- _description = "Fields"
- _columns = {
- 'name': fields.char('Name', required=True, size=64, select=1),
- 'model': fields.char('Object Name', size=64, required=True),
- 'relation': fields.char('Model Relation', size=64),
- 'model_id': fields.many2one('ir.model', 'Model id', required=True, select=True, ondelete='cascade'),
- 'field_description': fields.char('Field Label', required=True, size=256),
- 'relate': fields.boolean('Click and Relate'),
+ _name = 'ir.model.fields'
+ _description = "Fields"
+ _columns = {
+ 'name': fields.char('Name', required=True, size=64, select=1),
+ 'model': fields.char('Object Name', size=64, required=True),
+ 'relation': fields.char('Model Relation', size=64),
+ 'model_id': fields.many2one('ir.model', 'Model id', required=True, select=True, ondelete='cascade'),
+ 'field_description': fields.char('Field Label', required=True, size=256),
+ 'relate': fields.boolean('Click and Relate'),
- 'ttype': fields.selection(_get_fields_type, 'Field Type',size=64, required=True),
- 'selection': fields.char('Field Selection',size=128),
- 'required': fields.boolean('Required'),
- 'readonly': fields.boolean('Readonly'),
- 'select_level': fields.selection([('0','Not Searchable'),('1','Always Searchable'),('2','Advanced Search')],'Searchable', required=True),
- 'translate': fields.boolean('Translate'),
- 'size': fields.integer('Size'),
- 'state': fields.selection([('manual','Custom Field'),('base','Base Field')],'Manualy Created'),
- 'on_delete': fields.selection([('cascade','Cascade'),('set null','Set NULL')], 'On delete', help='On delete property for many2one fields'),
- 'domain': fields.char('Domain', size=256),
+ 'ttype': fields.selection(_get_fields_type, 'Field Type',size=64, required=True),
+ 'selection': fields.char('Field Selection',size=128),
+ 'required': fields.boolean('Required'),
+ 'readonly': fields.boolean('Readonly'),
+ 'select_level': fields.selection([('0','Not Searchable'),('1','Always Searchable'),('2','Advanced Search')],'Searchable', required=True),
+ 'translate': fields.boolean('Translate'),
+ 'size': fields.integer('Size'),
+ 'state': fields.selection([('manual','Custom Field'),('base','Base Field')],'Manualy Created'),
+ 'on_delete': fields.selection([('cascade','Cascade'),('set null','Set NULL')], 'On delete', help='On delete property for many2one fields'),
+ 'domain': fields.char('Domain', size=256),
- 'groups': fields.many2many('res.groups', 'ir_model_fields_group_rel', 'field_id', 'group_id', 'Groups'),
- 'group_name': fields.char('Group Name', size=128),
- 'view_load': fields.boolean('View Auto-Load'),
- }
- _defaults = {
- 'relate': lambda *a: 0,
- 'view_load': lambda *a: 0,
- 'selection': lambda *a: "[]",
- 'domain': lambda *a: "[]",
- 'name': lambda *a: 'x_',
- 'state': lambda self,cr,uid,ctx={}: (ctx and ctx.get('manual',False)) and 'manual' or 'base',
- 'on_delete': lambda *a: 'set null',
- 'select_level': lambda *a: '0',
- 'size': lambda *a: 64,
- 'field_description': lambda *a: '',
- }
- _order = "id"
- def unlink(self, cr, user, ids, context=None):
- for field in self.browse(cr, user, ids, context):
- if field.state <> 'manual':
- raise except_orm(_('Error'), _("You can not remove the field '%s' !") %(field.name,))
- #
- # MAY BE ADD A ALTER TABLE DROP ?
- #
- return super(ir_model_fields, self).unlink(cr, user, ids, context)
+ 'groups': fields.many2many('res.groups', 'ir_model_fields_group_rel', 'field_id', 'group_id', 'Groups'),
+ 'group_name': fields.char('Group Name', size=128),
+ 'view_load': fields.boolean('View Auto-Load'),
+ }
+ _defaults = {
+ 'relate': lambda *a: 0,
+ 'view_load': lambda *a: 0,
+ 'selection': lambda *a: "[]",
+ 'domain': lambda *a: "[]",
+ 'name': lambda *a: 'x_',
+ 'state': lambda self,cr,uid,ctx={}: (ctx and ctx.get('manual',False)) and 'manual' or 'base',
+ 'on_delete': lambda *a: 'set null',
+ 'select_level': lambda *a: '0',
+ 'size': lambda *a: 64,
+ 'field_description': lambda *a: '',
+ }
+ _order = "id"
+ def unlink(self, cr, user, ids, context=None):
+ for field in self.browse(cr, user, ids, context):
+ if field.state <> 'manual':
+ raise except_orm(_('Error'), _("You can not remove the field '%s' !") %(field.name,))
+ #
+ # MAY BE ADD A ALTER TABLE DROP ?
+ #
+ return super(ir_model_fields, self).unlink(cr, user, ids, context)
- def create(self, cr, user, vals, context=None):
- if 'model_id' in vals:
- model_data=self.pool.get('ir.model').read(cr,user,vals['model_id'])
- vals['model']=model_data['model']
- if context and context.get('manual',False):
- vals['state']='manual'
- res = super(ir_model_fields,self).create(cr, user, vals, context)
- if vals.get('state','base')=='manual':
- if not vals['name'].startswith('x_'):
- raise except_orm(_('Error'), _("Custom fields must have a name that starts with 'x_' !"))
- if self.pool.get(vals['model']):
- self.pool.get(vals['model']).__init__(self.pool, cr)
- self.pool.get(vals['model'])._auto_init(cr,{})
- return res
+ def create(self, cr, user, vals, context=None):
+ if 'model_id' in vals:
+ model_data=self.pool.get('ir.model').read(cr,user,vals['model_id'])
+ vals['model']=model_data['model']
+ if context and context.get('manual',False):
+ vals['state']='manual'
+ res = super(ir_model_fields,self).create(cr, user, vals, context)
+ if vals.get('state','base')=='manual':
+ if not vals['name'].startswith('x_'):
+ raise except_orm(_('Error'), _("Custom fields must have a name that starts with 'x_' !"))
+ if self.pool.get(vals['model']):
+ self.pool.get(vals['model']).__init__(self.pool, cr)
+ self.pool.get(vals['model'])._auto_init(cr,{})
+ return res
ir_model_fields()
class ir_model_access(osv.osv):
- _name = 'ir.model.access'
- _columns = {
- 'name': fields.char('Name', size=64, required=True),
- 'model_id': fields.many2one('ir.model', 'Model', required=True),
- 'group_id': fields.many2one('res.groups', 'Group'),
- 'perm_read': fields.boolean('Read Access'),
- 'perm_write': fields.boolean('Write Access'),
- 'perm_create': fields.boolean('Create Access'),
- 'perm_unlink': fields.boolean('Delete Permission'),
- }
-
- def check_groups(self, cr, uid, group):
- res = False
- grouparr = group.split('.')
- if grouparr:
- cr.execute("select * from res_groups_users_rel where uid=" + str(uid) + " and gid in(select res_id from ir_model_data where module='%s' and name='%s')" % (grouparr[0], grouparr[1]))
- r = cr.fetchall()
- if not r:
- res = False
- else:
- res = True
- else:
- res = False
- return res
-
- def check(self, cr, uid, model_name, mode='read',raise_exception=True):
- assert mode in ['read','write','create','unlink'], 'Invalid access mode for security'
- if uid == 1:
- return True # TODO: check security: don't allow xml-rpc request with uid == 1
+ _name = 'ir.model.access'
+ _columns = {
+ 'name': fields.char('Name', size=64, required=True),
+ 'model_id': fields.many2one('ir.model', 'Model', required=True),
+ 'group_id': fields.many2one('res.groups', 'Group'),
+ 'perm_read': fields.boolean('Read Access'),
+ 'perm_write': fields.boolean('Write Access'),
+ 'perm_create': fields.boolean('Create Access'),
+ 'perm_unlink': fields.boolean('Delete Permission'),
+ }
+
+ def check_groups(self, cr, uid, group):
+ res = False
+ grouparr = group.split('.')
+ if grouparr:
+ cr.execute("select * from res_groups_users_rel where uid=" + str(uid) + " and gid in(select res_id from ir_model_data where module='%s' and name='%s')" % (grouparr[0], grouparr[1]))
+ r = cr.fetchall()
+ if not r:
+ res = False
+ else:
+ res = True
+ else:
+ res = False
+ return res
+
+ def check(self, cr, uid, model_name, mode='read',raise_exception=True):
+ assert mode in ['read','write','create','unlink'], 'Invalid access mode for security'
+ if uid == 1:
+ return True # TODO: check security: don't allow xml-rpc request with uid == 1
- cr.execute('SELECT MAX(CASE WHEN perm_'+mode+' THEN 1 else 0 END) '
- 'FROM ir_model_access a '
- 'JOIN ir_model m '
- 'ON (a.model_id=m.id) '
- 'JOIN res_groups_users_rel gu '
- 'ON (gu.gid = a.group_id) '
- 'WHERE m.model = %s AND gu.uid = %s', (model_name, uid,))
- r = cr.fetchall()
- if r[0][0] == None:
- cr.execute('SELECT MAX(CASE WHEN perm_'+mode+' THEN 1 else 0 END) '
- 'FROM ir_model_access a '
- 'JOIN ir_model m '
- 'ON (a.model_id = m.id) '
- 'WHERE a.group_id IS NULL AND m.model = %s', (model_name,))
- r= cr.fetchall()
- if r[0][0] == None:
- return False # by default, the user had no access
+ cr.execute('SELECT MAX(CASE WHEN perm_'+mode+' THEN 1 else 0 END) '
+ 'FROM ir_model_access a '
+ 'JOIN ir_model m '
+ 'ON (a.model_id=m.id) '
+ 'JOIN res_groups_users_rel gu '
+ 'ON (gu.gid = a.group_id) '
+ 'WHERE m.model = %s AND gu.uid = %s', (model_name, uid,))
+ r = cr.fetchall()
+ if r[0][0] == None:
+ cr.execute('SELECT MAX(CASE WHEN perm_'+mode+' THEN 1 else 0 END) '
+ 'FROM ir_model_access a '
+ 'JOIN ir_model m '
+ 'ON (a.model_id = m.id) '
+ 'WHERE a.group_id IS NULL AND m.model = %s', (model_name,))
+ r= cr.fetchall()
+ if r[0][0] == None:
+ return False # by default, the user had no access
- if not r[0][0]:
- if raise_exception:
- msgs = {
- 'read': _('You can not read this document! (%s)'),
- 'write': _('You can not write in this document! (%s)'),
- 'create': _('You can not create this kind of document! (%s)'),
- 'unlink': _('You can not delete this document! (%s)'),
- }
- # due to the assert at the begin of the function, we will never have a KeyError
- raise except_orm(_('AccessError'), msgs[mode] % model_name )
- return r[0][0]
+ if not r[0][0]:
+ if raise_exception:
+ msgs = {
+ 'read': _('You can not read this document! (%s)'),
+ 'write': _('You can not write in this document! (%s)'),
+ 'create': _('You can not create this kind of document! (%s)'),
+ 'unlink': _('You can not delete this document! (%s)'),
+ }
+ # due to the assert at the begin of the function, we will never have a KeyError
+ raise except_orm(_('AccessError'), msgs[mode] % model_name )
+ return r[0][0]
- check = tools.cache()(check)
+ check = tools.cache()(check)
- #
- # Methods to clean the cache on the Check Method.
- #
- def write(self, cr, uid, *args, **argv):
- res = super(ir_model_access, self).write(cr, uid, *args, **argv)
- self.check()
- return res
- def create(self, cr, uid, *args, **argv):
- res = super(ir_model_access, self).create(cr, uid, *args, **argv)
- self.check()
- return res
- def unlink(self, cr, uid, *args, **argv):
- res = super(ir_model_access, self).unlink(cr, uid, *args, **argv)
- self.check()
- return res
+ #
+ # Methods to clean the cache on the Check Method.
+ #
+ def write(self, cr, uid, *args, **argv):
+ res = super(ir_model_access, self).write(cr, uid, *args, **argv)
+ self.check()
+ return res
+ def create(self, cr, uid, *args, **argv):
+ res = super(ir_model_access, self).create(cr, uid, *args, **argv)
+ self.check()
+ return res
+ def unlink(self, cr, uid, *args, **argv):
+ res = super(ir_model_access, self).unlink(cr, uid, *args, **argv)
+ self.check()
+ return res
ir_model_access()
class ir_model_data(osv.osv):
- _name = 'ir.model.data'
- _columns = {
- 'name': fields.char('XML Identifier', required=True, size=64),
- 'model': fields.char('Model', required=True, size=64),
- 'module': fields.char('Module', required=True, size=64),
- 'res_id': fields.integer('Resource ID'),
- 'noupdate': fields.boolean('Non Updatable'),
- 'date_update': fields.datetime('Update Date'),
- 'date_init': fields.datetime('Init Date')
- }
- _defaults = {
- 'date_init': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
- 'date_update': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
- 'noupdate': lambda *a: False
- }
+ _name = 'ir.model.data'
+ _columns = {
+ 'name': fields.char('XML Identifier', required=True, size=64),
+ 'model': fields.char('Model', required=True, size=64),
+ 'module': fields.char('Module', required=True, size=64),
+ 'res_id': fields.integer('Resource ID'),
+ 'noupdate': fields.boolean('Non Updatable'),
+ 'date_update': fields.datetime('Update Date'),
+ 'date_init': fields.datetime('Init Date')
+ }
+ _defaults = {
+ 'date_init': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
+ 'date_update': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
+ 'noupdate': lambda *a: False
+ }
- def __init__(self, pool, cr):
- osv.osv.__init__(self, pool, cr)
- self.loads = {}
- self.doinit = True
- self.unlink_mark = {}
+ def __init__(self, pool, cr):
+ osv.osv.__init__(self, pool, cr)
+ self.loads = {}
+ self.doinit = True
+ self.unlink_mark = {}
- def _get_id(self,cr, uid, module, xml_id):
- ids = self.search(cr, uid, [('module','=',module),('name','=', xml_id)])
- assert len(ids)==1, '%d reference(s) to %s. You should have only one !' % (len(ids),xml_id)
- return ids[0]
- _get_id = tools.cache()(_get_id)
+ def _get_id(self,cr, uid, module, xml_id):
+ ids = self.search(cr, uid, [('module','=',module),('name','=', xml_id)])
+ assert len(ids)==1, '%d reference(s) to %s. You should have only one !' % (len(ids),xml_id)
+ return ids[0]
+ _get_id = tools.cache()(_get_id)
- def _update_dummy(self,cr, uid, model, module, xml_id=False, store=True):
- if not xml_id:
- return False
- try:
- id = self.read(cr, uid, [self._get_id(cr, uid, module, xml_id)], ['res_id'])[0]['res_id']
- self.loads[(module,xml_id)] = (model,id)
- except:
- id = False
- return id
+ def _update_dummy(self,cr, uid, model, module, xml_id=False, store=True):
+ if not xml_id:
+ return False
+ try:
+ id = self.read(cr, uid, [self._get_id(cr, uid, module, xml_id)], ['res_id'])[0]['res_id']
+ self.loads[(module,xml_id)] = (model,id)
+ except:
+ id = False
+ return id
- def _update(self,cr, uid, model, module, values, xml_id=False, store=True, noupdate=False, mode='init', res_id=False):
- warning = True
- model_obj = self.pool.get(model)
- context = {}
- if xml_id and ('.' in xml_id):
- assert len(xml_id.split('.'))==2, _('"%s" contains too many dots. XML ids should not contain dots ! These are used to refer to other modules data, as in module.reference_id') % (xml_id)
- warning = False
- module, xml_id = xml_id.split('.')
- if (not xml_id) and (not self.doinit):
- return False
- action_id = False
- if xml_id:
- 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,))
- result3 = cr.fetchone()
- if not result3:
- cr.execute('delete from ir_model_data where id=%d', (action_id2,))
- else:
- res_id,action_id = res_id2,action_id2
+ def _update(self,cr, uid, model, module, values, xml_id=False, store=True, noupdate=False, mode='init', res_id=False):
+ warning = True
+ model_obj = self.pool.get(model)
+ context = {}
+ if xml_id and ('.' in xml_id):
+ assert len(xml_id.split('.'))==2, _('"%s" contains too many dots. XML ids should not contain dots ! These are used to refer to other modules data, as in module.reference_id') % (xml_id)
+ warning = False
+ module, xml_id = xml_id.split('.')
+ if (not xml_id) and (not self.doinit):
+ return False
+ action_id = False
+ if xml_id:
+ 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,))
+ result3 = cr.fetchone()
+ if not result3:
+ cr.execute('delete from ir_model_data where id=%d', (action_id2,))
+ else:
+ res_id,action_id = res_id2,action_id2
- if action_id and res_id:
- model_obj.write(cr, uid, [res_id], values)
- self.write(cr, uid, [action_id], {
- 'date_update': time.strftime('%Y-%m-%d %H:%M:%S'),
- })
- elif res_id:
- model_obj.write(cr, uid, [res_id], values)
- if xml_id:
- self.create(cr, uid, {
- 'name': xml_id,
- 'model': model,
- 'module':module,
- 'res_id':res_id,
- 'noupdate': noupdate,
- })
- if model_obj._inherits:
- for table in model_obj._inherits:
- inherit_id = model_obj.browse(cr, uid,
- res_id)[model_obj._inherits[table]]
- self.create(cr, uid, {
- 'name': xml_id + '_' + table.replace('.', '_'),
- 'model': table,
- 'module': module,
- 'res_id': inherit_id,
- 'noupdate': noupdate,
- })
- else:
- if mode=='init' or (mode=='update' and xml_id):
- res_id = model_obj.create(cr, uid, values)
- if xml_id:
- self.create(cr, uid, {
- 'name': xml_id,
- 'model': model,
- 'module': module,
- 'res_id': res_id,
- 'noupdate': noupdate
- })
- if model_obj._inherits:
- for table in model_obj._inherits:
- inherit_id = model_obj.browse(cr, uid,
- res_id)[model_obj._inherits[table]]
- self.create(cr, uid, {
- 'name': xml_id + '_' + table.replace('.', '_'),
- 'model': table,
- 'module': module,
- 'res_id': inherit_id,
- 'noupdate': noupdate,
- })
- if xml_id:
- if res_id:
- self.loads[(module, xml_id)] = (model, res_id)
- if model_obj._inherits:
- for table in model_obj._inherits:
- inherit_field = model_obj._inherits[table]
- inherit_id = model_obj.read(cr, uid, res_id,
- [inherit_field])[inherit_field]
- self.loads[(module, xml_id + '_' + \
- table.replace('.', '_'))] = (table, inherit_id)
- return res_id
+ if action_id and res_id:
+ model_obj.write(cr, uid, [res_id], values)
+ self.write(cr, uid, [action_id], {
+ 'date_update': time.strftime('%Y-%m-%d %H:%M:%S'),
+ })
+ elif res_id:
+ model_obj.write(cr, uid, [res_id], values)
+ if xml_id:
+ self.create(cr, uid, {
+ 'name': xml_id,
+ 'model': model,
+ 'module':module,
+ 'res_id':res_id,
+ 'noupdate': noupdate,
+ })
+ if model_obj._inherits:
+ for table in model_obj._inherits:
+ inherit_id = model_obj.browse(cr, uid,
+ res_id)[model_obj._inherits[table]]
+ self.create(cr, uid, {
+ 'name': xml_id + '_' + table.replace('.', '_'),
+ 'model': table,
+ 'module': module,
+ 'res_id': inherit_id,
+ 'noupdate': noupdate,
+ })
+ else:
+ if mode=='init' or (mode=='update' and xml_id):
+ res_id = model_obj.create(cr, uid, values)
+ if xml_id:
+ self.create(cr, uid, {
+ 'name': xml_id,
+ 'model': model,
+ 'module': module,
+ 'res_id': res_id,
+ 'noupdate': noupdate
+ })
+ if model_obj._inherits:
+ for table in model_obj._inherits:
+ inherit_id = model_obj.browse(cr, uid,
+ res_id)[model_obj._inherits[table]]
+ self.create(cr, uid, {
+ 'name': xml_id + '_' + table.replace('.', '_'),
+ 'model': table,
+ 'module': module,
+ 'res_id': inherit_id,
+ 'noupdate': noupdate,
+ })
+ if xml_id:
+ if res_id:
+ self.loads[(module, xml_id)] = (model, res_id)
+ if model_obj._inherits:
+ for table in model_obj._inherits:
+ inherit_field = model_obj._inherits[table]
+ inherit_id = model_obj.read(cr, uid, res_id,
+ [inherit_field])[inherit_field]
+ self.loads[(module, xml_id + '_' + \
+ table.replace('.', '_'))] = (table, inherit_id)
+ return res_id
- def _unlink(self, cr, uid, model, ids, direct=False):
- #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))
- return True
+ def _unlink(self, cr, uid, model, ids, direct=False):
+ #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))
+ return True
- def ir_set(self, cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=None, xml_id=False):
- obj = self.pool.get('ir.values')
- if type(models[0])==type([]) or type(models[0])==type(()):
- model,res_id = models[0]
- else:
- res_id=None
- model = models[0]
+ def ir_set(self, cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=None, xml_id=False):
+ obj = self.pool.get('ir.values')
+ if type(models[0])==type([]) or type(models[0])==type(()):
+ model,res_id = models[0]
+ else:
+ res_id=None
+ model = models[0]
- if res_id:
- where = ' and res_id=%d' % (res_id,)
- else:
- where = ' and (res_id is null)'
+ if res_id:
+ where = ' and res_id=%d' % (res_id,)
+ else:
+ where = ' and (res_id is null)'
- if key2:
- where += ' and key2=\'%s\'' % (key2,)
- else:
- where += ' and (key2 is null)'
+ if key2:
+ where += ' and key2=\'%s\'' % (key2,)
+ else:
+ where += ' and (key2 is null)'
- cr.execute('select * from ir_values where model=%s and key=%s and name=%s'+where,(model, key, name))
- res = cr.fetchone()
- if not res:
- res = ir.ir_set(cr, uid, key, key2, name, models, value, replace, isobject, meta)
- elif xml_id:
- cr.execute('UPDATE ir_values set value=%s WHERE model=%s and key=%s and name=%s'+where,(value, model, key, name))
- return True
+ cr.execute('select * from ir_values where model=%s and key=%s and name=%s'+where,(model, key, name))
+ res = cr.fetchone()
+ if not res:
+ res = ir.ir_set(cr, uid, key, key2, name, models, value, replace, isobject, meta)
+ elif xml_id:
+ cr.execute('UPDATE ir_values set value=%s WHERE model=%s and key=%s and name=%s'+where,(value, model, key, name))
+ return True
- def _process_end(self, cr, uid, modules):
- if not modules:
- return True
- module_str = ["'%s'" % m for m in modules]
- cr.execute('select id,name,model,res_id,module from ir_model_data where module in ('+','.join(module_str)+') and not noupdate')
- wkf_todo = []
- for (id, name, model, res_id,module) in cr.fetchall():
- 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,))
- 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,))
+ def _process_end(self, cr, uid, modules):
+ if not modules:
+ return True
+ module_str = ["'%s'" % m for m in modules]
+ cr.execute('select id,name,model,res_id,module from ir_model_data where module in ('+','.join(module_str)+') and not noupdate')
+ wkf_todo = []
+ for (id, name, model, res_id,module) in cr.fetchall():
+ 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,))
+ 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,))
- for model,id in wkf_todo:
- wf_service = netsvc.LocalService("workflow")
- wf_service.trg_write(uid, model, id, cr)
+ for model,id in wkf_todo:
+ wf_service = netsvc.LocalService("workflow")
+ wf_service.trg_write(uid, model, id, cr)
- cr.commit()
- for (model,id) in self.unlink_mark.keys():
- if self.pool.get(model):
- logger = netsvc.Logger()
- logger.notifyChannel('init', netsvc.LOG_INFO, 'Deleting %s@%s' % (id, model))
- try:
- self.pool.get(model).unlink(cr, uid, [id])
- if self.unlink_mark[(model,id)]:
- self.unlink(cr, uid, [self.unlink_mark[(model,id)]])
- cr.execute('DELETE FROM ir_values WHERE value=%s', (model+','+str(id),))
- cr.commit()
- except:
- logger.notifyChannel('init', netsvc.LOG_ERROR, 'Could not delete id: %d of model %s\tThere should be some relation that points to this resource\tYou should manually fix this and restart --update=module' % (id, model))
- return True
+ cr.commit()
+ for (model,id) in self.unlink_mark.keys():
+ if self.pool.get(model):
+ logger = netsvc.Logger()
+ logger.notifyChannel('init', netsvc.LOG_INFO, 'Deleting %s@%s' % (id, model))
+ try:
+ self.pool.get(model).unlink(cr, uid, [id])
+ if self.unlink_mark[(model,id)]:
+ self.unlink(cr, uid, [self.unlink_mark[(model,id)]])
+ cr.execute('DELETE FROM ir_values WHERE value=%s', (model+','+str(id),))
+ cr.commit()
+ except:
+ logger.notifyChannel('init', netsvc.LOG_ERROR, 'Could not delete id: %d of model %s\tThere should be some relation that points to this resource\tYou should manually fix this and restart --update=module' % (id, model))
+ return True
ir_model_data()
diff --git a/bin/addons/base/ir/ir_report_custom.py b/bin/addons/base/ir/ir_report_custom.py
index af413f54e41..cc8b3acc7e5 100644
--- a/bin/addons/base/ir/ir_report_custom.py
+++ b/bin/addons/base/ir/ir_report_custom.py
@@ -34,176 +34,176 @@ import report.custom
from tools.translate import _
class report_custom(osv.osv):
- _name = 'ir.report.custom'
- _columns = {
- 'name': fields.char('Report Name', size=64, required=True, translate=True),
- 'model_id': fields.many2one('ir.model','Model', required=True, change_default=True),
- 'type': fields.selection([('table','Tabular'),('pie','Pie Chart'),('bar','Bar Chart'),('line','Line Plot')], "Report Type", size=64, required='True'),
- 'title': fields.char("Report title", size=64, required='True', translate=True),
- 'print_format': fields.selection((('A4','a4'),('A5','a5')), 'Print format', required=True),
- 'print_orientation': fields.selection((('landscape','Landscape'),('portrait','Portrait')), 'Print orientation', required=True, size=16),
- 'repeat_header': fields.boolean('Repeat Header'),
- 'footer': fields.char('Report Footer', size=64, required=True),
- 'sortby': fields.char('Sorted By', size=64),
- 'fields_child0': fields.one2many('ir.report.custom.fields', 'report_id','Fields', required=True),
- 'field_parent': fields.many2one('ir.model.fields','Child Field'),
- 'state': fields.selection([('unsubscribed','Unsubscribed'),('subscribed','Subscribed')], 'State', size=64),
- 'frequency': fields.selection([('Y','Yearly'),('M','Monthly'),('D','Daily')], 'Frequency', size=64),
- 'limitt': fields.char('Limit', size=9),
- 'menu_id': fields.many2one('ir.ui.menu', 'Menu')
- }
- _defaults = {
- 'print_format': lambda *a: 'A4',
- 'print_orientation': lambda *a: 'portrait',
- 'state': lambda *a: 'unsubscribed',
- 'type': lambda *a: 'table',
- 'footer': lambda *a: 'Generated by Tiny ERP'
- }
-
- def onchange_model_id(self, cr, uid, ids, model_id):
- if not(model_id):
- return {}
- return {'domain': {'field_parent': [('model_id','=',model_id)]}}
+ _name = 'ir.report.custom'
+ _columns = {
+ 'name': fields.char('Report Name', size=64, required=True, translate=True),
+ 'model_id': fields.many2one('ir.model','Model', required=True, change_default=True),
+ 'type': fields.selection([('table','Tabular'),('pie','Pie Chart'),('bar','Bar Chart'),('line','Line Plot')], "Report Type", size=64, required='True'),
+ 'title': fields.char("Report title", size=64, required='True', translate=True),
+ 'print_format': fields.selection((('A4','a4'),('A5','a5')), 'Print format', required=True),
+ 'print_orientation': fields.selection((('landscape','Landscape'),('portrait','Portrait')), 'Print orientation', required=True, size=16),
+ 'repeat_header': fields.boolean('Repeat Header'),
+ 'footer': fields.char('Report Footer', size=64, required=True),
+ 'sortby': fields.char('Sorted By', size=64),
+ 'fields_child0': fields.one2many('ir.report.custom.fields', 'report_id','Fields', required=True),
+ 'field_parent': fields.many2one('ir.model.fields','Child Field'),
+ 'state': fields.selection([('unsubscribed','Unsubscribed'),('subscribed','Subscribed')], 'State', size=64),
+ 'frequency': fields.selection([('Y','Yearly'),('M','Monthly'),('D','Daily')], 'Frequency', size=64),
+ 'limitt': fields.char('Limit', size=9),
+ 'menu_id': fields.many2one('ir.ui.menu', 'Menu')
+ }
+ _defaults = {
+ 'print_format': lambda *a: 'A4',
+ 'print_orientation': lambda *a: 'portrait',
+ 'state': lambda *a: 'unsubscribed',
+ 'type': lambda *a: 'table',
+ 'footer': lambda *a: 'Generated by Tiny ERP'
+ }
+
+ def onchange_model_id(self, cr, uid, ids, model_id):
+ if not(model_id):
+ return {}
+ return {'domain': {'field_parent': [('model_id','=',model_id)]}}
- def unsubscribe(self, cr, uid, ids, context={}):
+ def unsubscribe(self, cr, uid, ids, context={}):
#TODO: should delete the ir.actions.report.custom for these reports and do an ir_del
- self.write(cr, uid, ids, {'state':'unsubscribed'})
- return True
+ self.write(cr, uid, ids, {'state':'unsubscribed'})
+ return True
- def subscribe(self, cr, uid, ids, context={}):
- for report in self.browse(cr, uid, ids):
- report.fields_child0.sort(lambda x,y : x.sequence - y.sequence)
-
- # required on field0 does not seem to work( cause we use o2m_l ?)
- if not report.fields_child0:
- raise osv.except_osv(_('Invalid operation'), _('Enter at least one field !'))
-
- if report.type in ['pie', 'bar', 'line'] and report.field_parent:
- raise osv.except_osv(_('Invalid operation'), _('Tree can only be used in tabular reports'))
-
- # Otherwise it won't build a good tree. See level.pop in custom.py.
- if report.type == 'table' and report.field_parent and report.fields_child0 and not report.fields_child0[0].groupby:
- raise osv.except_osv('Invalid operation :', 'When creating tree (field child) report, data must be group by the first field')
+ def subscribe(self, cr, uid, ids, context={}):
+ for report in self.browse(cr, uid, ids):
+ report.fields_child0.sort(lambda x,y : x.sequence - y.sequence)
+
+ # required on field0 does not seem to work( cause we use o2m_l ?)
+ if not report.fields_child0:
+ raise osv.except_osv(_('Invalid operation'), _('Enter at least one field !'))
+
+ if report.type in ['pie', 'bar', 'line'] and report.field_parent:
+ raise osv.except_osv(_('Invalid operation'), _('Tree can only be used in tabular reports'))
+
+ # Otherwise it won't build a good tree. See level.pop in custom.py.
+ if report.type == 'table' and report.field_parent and report.fields_child0 and not report.fields_child0[0].groupby:
+ raise osv.except_osv('Invalid operation :', 'When creating tree (field child) report, data must be group by the first field')
- if report.type == 'pie':
- if len(report.fields_child0) != 2:
- raise osv.except_osv(_('Invalid operation'), _('Pie charts need exactly two fields'))
- else:
- c_f = {}
- for i in range(2):
- c_f[i] = []
- tmp = report.fields_child0[i]
- for j in range(3):
- c_f[i].append((not isinstance(eval('tmp.field_child'+str(j)), browse_null) and eval('tmp.field_child'+str(j)+'.ttype')) or None)
- if not reduce(lambda x,y : x or y, map(lambda x: x in ['integer', 'float'], c_f[1])):
- raise osv.except_osv(_('Invalid operation'), _('Second field should be figures'))
-
- if report.type == 'bar':
- if len(report.fields_child0) < 2:
- raise osv.except_osv(_('Invalid operation'), _('Bar charts need at least two fields'))
- else:
- c_f = {}
- for i in range(len(report.fields_child0)):
- c_f[i] = []
- tmp = report.fields_child0[i]
- for j in range(3):
- c_f[i].append((not isinstance(eval('tmp.field_child'+str(j)), browse_null) and eval('tmp.field_child'+str(j)+'.ttype')) or None)
+ if report.type == 'pie':
+ if len(report.fields_child0) != 2:
+ raise osv.except_osv(_('Invalid operation'), _('Pie charts need exactly two fields'))
+ else:
+ c_f = {}
+ for i in range(2):
+ c_f[i] = []
+ tmp = report.fields_child0[i]
+ for j in range(3):
+ c_f[i].append((not isinstance(eval('tmp.field_child'+str(j)), browse_null) and eval('tmp.field_child'+str(j)+'.ttype')) or None)
+ if not reduce(lambda x,y : x or y, map(lambda x: x in ['integer', 'float'], c_f[1])):
+ raise osv.except_osv(_('Invalid operation'), _('Second field should be figures'))
+
+ if report.type == 'bar':
+ if len(report.fields_child0) < 2:
+ raise osv.except_osv(_('Invalid operation'), _('Bar charts need at least two fields'))
+ else:
+ c_f = {}
+ for i in range(len(report.fields_child0)):
+ c_f[i] = []
+ tmp = report.fields_child0[i]
+ for j in range(3):
+ c_f[i].append((not isinstance(eval('tmp.field_child'+str(j)), browse_null) and eval('tmp.field_child'+str(j)+'.ttype')) or None)
- if i == 0:
- pass
- else:
- if not reduce(lambda x,y : x or y, map(lambda x: x in ['integer', 'float'], c_f[i])):
- raise osv.except_osv(_('Invalid operation'), _('Field %d should be a figure') %(i,))
+ if i == 0:
+ pass
+ else:
+ if not reduce(lambda x,y : x or y, map(lambda x: x in ['integer', 'float'], c_f[i])):
+ raise osv.except_osv(_('Invalid operation'), _('Field %d should be a figure') %(i,))
- if report.state=='subscribed':
- continue
+ if report.state=='subscribed':
+ continue
- name = report.name
- model = report.model_id.model
+ name = report.name
+ model = report.model_id.model
- action_def = {'report_id':report.id, 'type':'ir.actions.report.custom', 'model':model, 'name':name}
- id = self.pool.get('ir.actions.report.custom').create(cr, uid, action_def)
- m_id = report.menu_id.id
- action = "ir.actions.report.custom,%d" % (id,)
- if not report.menu_id:
- ir.ir_set(cr, uid, 'action', 'client_print_multi', name, [(model, False)], action, False, True)
- else:
- ir.ir_set(cr, uid, 'action', 'tree_but_open', 'Menuitem', [('ir.ui.menu', int(m_id))], action, False, True)
+ action_def = {'report_id':report.id, 'type':'ir.actions.report.custom', 'model':model, 'name':name}
+ id = self.pool.get('ir.actions.report.custom').create(cr, uid, action_def)
+ m_id = report.menu_id.id
+ action = "ir.actions.report.custom,%d" % (id,)
+ if not report.menu_id:
+ ir.ir_set(cr, uid, 'action', 'client_print_multi', name, [(model, False)], action, False, True)
+ else:
+ ir.ir_set(cr, uid, 'action', 'tree_but_open', 'Menuitem', [('ir.ui.menu', int(m_id))], action, False, True)
- self.write(cr, uid, [report.id], {'state':'subscribed'}, context)
- return True
+ self.write(cr, uid, [report.id], {'state':'subscribed'}, context)
+ return True
report_custom()
class report_custom_fields(osv.osv):
- _name = 'ir.report.custom.fields'
- _columns = {
- 'name': fields.char('Name', size=64, required=True),
- 'report_id': fields.many2one('ir.report.custom', 'Report Ref', select=True),
- 'field_child0': fields.many2one('ir.model.fields', 'field child0', required=True),
- 'fc0_operande': fields.many2one('ir.model.fields', 'Constraint'),
- 'fc0_condition': fields.char('Condition', size=64),
- 'fc0_op': fields.selection((('>','>'),('<','<'),('==','='),('in','in'),('gety,==','(year)=')), 'Relation'),
- 'field_child1': fields.many2one('ir.model.fields', 'field child1'),
- 'fc1_operande': fields.many2one('ir.model.fields', 'Constraint'),
- 'fc1_condition': fields.char('condition', size=64),
- 'fc1_op': fields.selection((('>','>'),('<','<'),('==','='),('in','in'),('gety,==','(year)=')), 'Relation'),
- 'field_child2': fields.many2one('ir.model.fields', 'field child2'),
- 'fc2_operande': fields.many2one('ir.model.fields', 'Constraint'),
- 'fc2_condition': fields.char('condition', size=64),
- 'fc2_op': fields.selection((('>','>'),('<','<'),('==','='),('in','in'),('gety,==','(year)=')), 'Relation'),
- 'field_child3': fields.many2one('ir.model.fields', 'field child3'),
- 'fc3_operande': fields.many2one('ir.model.fields', 'Constraint'),
- 'fc3_condition': fields.char('condition', size=64),
- 'fc3_op': fields.selection((('>','>'),('<','<'),('==','='),('in','in'),('gety,==','(year)=')), 'Relation'),
- 'alignment': fields.selection((('left','left'),('right','right'),('center','center')), 'Alignment', required=True),
- 'sequence': fields.integer('Sequence', required=True),
- 'width': fields.integer('Fixed Width'),
- 'operation': fields.selection((('none', 'None'),('calc_sum','Calculate Sum'),('calc_avg','Calculate Average'),('calc_count','Calculate Count'),('calc_max', 'Get Max'))),
- 'groupby' : fields.boolean('Group by'),
- 'bgcolor': fields.char('Background Color', size=64),
- 'fontcolor': fields.char('Font color', size=64),
- 'cumulate': fields.boolean('Cumulate')
- }
- _defaults = {
- 'alignment': lambda *a: 'left',
- 'bgcolor': lambda *a: 'white',
- 'fontcolor': lambda *a: 'black',
- 'operation': lambda *a: 'none',
- }
- _order = "sequence"
+ _name = 'ir.report.custom.fields'
+ _columns = {
+ 'name': fields.char('Name', size=64, required=True),
+ 'report_id': fields.many2one('ir.report.custom', 'Report Ref', select=True),
+ 'field_child0': fields.many2one('ir.model.fields', 'field child0', required=True),
+ 'fc0_operande': fields.many2one('ir.model.fields', 'Constraint'),
+ 'fc0_condition': fields.char('Condition', size=64),
+ 'fc0_op': fields.selection((('>','>'),('<','<'),('==','='),('in','in'),('gety,==','(year)=')), 'Relation'),
+ 'field_child1': fields.many2one('ir.model.fields', 'field child1'),
+ 'fc1_operande': fields.many2one('ir.model.fields', 'Constraint'),
+ 'fc1_condition': fields.char('condition', size=64),
+ 'fc1_op': fields.selection((('>','>'),('<','<'),('==','='),('in','in'),('gety,==','(year)=')), 'Relation'),
+ 'field_child2': fields.many2one('ir.model.fields', 'field child2'),
+ 'fc2_operande': fields.many2one('ir.model.fields', 'Constraint'),
+ 'fc2_condition': fields.char('condition', size=64),
+ 'fc2_op': fields.selection((('>','>'),('<','<'),('==','='),('in','in'),('gety,==','(year)=')), 'Relation'),
+ 'field_child3': fields.many2one('ir.model.fields', 'field child3'),
+ 'fc3_operande': fields.many2one('ir.model.fields', 'Constraint'),
+ 'fc3_condition': fields.char('condition', size=64),
+ 'fc3_op': fields.selection((('>','>'),('<','<'),('==','='),('in','in'),('gety,==','(year)=')), 'Relation'),
+ 'alignment': fields.selection((('left','left'),('right','right'),('center','center')), 'Alignment', required=True),
+ 'sequence': fields.integer('Sequence', required=True),
+ 'width': fields.integer('Fixed Width'),
+ 'operation': fields.selection((('none', 'None'),('calc_sum','Calculate Sum'),('calc_avg','Calculate Average'),('calc_count','Calculate Count'),('calc_max', 'Get Max'))),
+ 'groupby' : fields.boolean('Group by'),
+ 'bgcolor': fields.char('Background Color', size=64),
+ 'fontcolor': fields.char('Font color', size=64),
+ 'cumulate': fields.boolean('Cumulate')
+ }
+ _defaults = {
+ 'alignment': lambda *a: 'left',
+ 'bgcolor': lambda *a: 'white',
+ 'fontcolor': lambda *a: 'black',
+ 'operation': lambda *a: 'none',
+ }
+ _order = "sequence"
- def onchange_any_field_child(self, cr, uid, ids, field_id, level):
- if not(field_id):
- return {}
- next_level_field_name = 'field_child%d' % (level+1)
- next_level_operande = 'fc%d_operande' % (level+1)
- field = self.pool.get('ir.model.fields').browse(cr, uid, [field_id])[0]
- res = self.pool.get(field.model).fields_get(cr, uid, field.name)
- if res[field.name].has_key('relation'):
- cr.execute('select id from ir_model where model=%s', (res[field.name]['relation'],))
- (id,) = cr.fetchone() or (False,)
- if id:
- return {
- 'domain': {
- next_level_field_name: [('model_id', '=', id)],
- next_level_operande: [('model_id', '=', id)]
- },
- 'required': {
- next_level_field_name: True
- }
- }
- else:
- print _("Warning: using a relation field which uses an unknown object") #TODO use the logger
- return {'required': {next_level_field_name: True}}
- else:
- return {'domain': {next_level_field_name: []}}
-
- def get_field_child_onchange_method(level):
- return lambda self, cr, uid, ids, field_id: self.onchange_any_field_child(cr, uid, ids, field_id, level)
+ def onchange_any_field_child(self, cr, uid, ids, field_id, level):
+ if not(field_id):
+ return {}
+ next_level_field_name = 'field_child%d' % (level+1)
+ next_level_operande = 'fc%d_operande' % (level+1)
+ field = self.pool.get('ir.model.fields').browse(cr, uid, [field_id])[0]
+ res = self.pool.get(field.model).fields_get(cr, uid, field.name)
+ if res[field.name].has_key('relation'):
+ cr.execute('select id from ir_model where model=%s', (res[field.name]['relation'],))
+ (id,) = cr.fetchone() or (False,)
+ if id:
+ return {
+ 'domain': {
+ next_level_field_name: [('model_id', '=', id)],
+ next_level_operande: [('model_id', '=', id)]
+ },
+ 'required': {
+ next_level_field_name: True
+ }
+ }
+ else:
+ print _("Warning: using a relation field which uses an unknown object") #TODO use the logger
+ return {'required': {next_level_field_name: True}}
+ else:
+ return {'domain': {next_level_field_name: []}}
+
+ def get_field_child_onchange_method(level):
+ return lambda self, cr, uid, ids, field_id: self.onchange_any_field_child(cr, uid, ids, field_id, level)
- onchange_field_child0 = get_field_child_onchange_method(0)
- onchange_field_child1 = get_field_child_onchange_method(1)
- onchange_field_child2 = get_field_child_onchange_method(2)
+ onchange_field_child0 = get_field_child_onchange_method(0)
+ onchange_field_child1 = get_field_child_onchange_method(1)
+ onchange_field_child2 = get_field_child_onchange_method(2)
report_custom_fields()
diff --git a/bin/addons/base/ir/ir_rule.py b/bin/addons/base/ir/ir_rule.py
index 6f76133341d..bdd5312f291 100644
--- a/bin/addons/base/ir/ir_rule.py
+++ b/bin/addons/base/ir/ir_rule.py
@@ -33,208 +33,208 @@ import tools
class ir_rule_group(osv.osv):
- _name = 'ir.rule.group'
-
- _columns = {
- 'name': fields.char('Name', size=128, select=1),
- 'model_id': fields.many2one('ir.model', 'Model',select=1, required=True),
- 'global': fields.boolean('Global', select=1, help="Make the rule global or it needs to be put on a group or user"),
- 'rules': fields.one2many('ir.rule', 'rule_group', 'Tests', help="The rule is satisfied if at least one test is True"),
- 'groups': fields.many2many('res.groups', 'group_rule_group_rel', 'rule_group_id', 'group_id', 'Groups'),
- 'users': fields.many2many('res.users', 'user_rule_group_rel', 'rule_group_id', 'user_id', 'Users'),
- }
-
- _order = 'model_id, global DESC'
-
- _defaults={
- 'global': lambda *a: True,
- }
-
- def unlink(self, cr, uid, ids, context=None):
- res = super(ir_rule_group, self).unlink(cr, uid, ids, context=context)
- # Restart the cache on the domain_get method of ir.rule
- self.pool.get('ir.rule').domain_get()
- return res
-
- def create(self, cr, user, vals, context=None):
- res = super(ir_rule_group, self).create(cr, user, vals, context=context)
- # Restart the cache on the domain_get method of ir.rule
- self.pool.get('ir.rule').domain_get()
- return res
-
- def write(self, cr, uid, ids, vals, context=None):
- if not context:
- context={}
- res = super(ir_rule_group, self).write(cr, uid, ids, vals, context=context)
- # Restart the cache on the domain_get method of ir.rule
- self.pool.get('ir.rule').domain_get()
- return res
+ _name = 'ir.rule.group'
+
+ _columns = {
+ 'name': fields.char('Name', size=128, select=1),
+ 'model_id': fields.many2one('ir.model', 'Model',select=1, required=True),
+ 'global': fields.boolean('Global', select=1, help="Make the rule global or it needs to be put on a group or user"),
+ 'rules': fields.one2many('ir.rule', 'rule_group', 'Tests', help="The rule is satisfied if at least one test is True"),
+ 'groups': fields.many2many('res.groups', 'group_rule_group_rel', 'rule_group_id', 'group_id', 'Groups'),
+ 'users': fields.many2many('res.users', 'user_rule_group_rel', 'rule_group_id', 'user_id', 'Users'),
+ }
+
+ _order = 'model_id, global DESC'
+
+ _defaults={
+ 'global': lambda *a: True,
+ }
+
+ def unlink(self, cr, uid, ids, context=None):
+ res = super(ir_rule_group, self).unlink(cr, uid, ids, context=context)
+ # Restart the cache on the domain_get method of ir.rule
+ self.pool.get('ir.rule').domain_get()
+ return res
+
+ def create(self, cr, user, vals, context=None):
+ res = super(ir_rule_group, self).create(cr, user, vals, context=context)
+ # Restart the cache on the domain_get method of ir.rule
+ self.pool.get('ir.rule').domain_get()
+ return res
+
+ def write(self, cr, uid, ids, vals, context=None):
+ if not context:
+ context={}
+ res = super(ir_rule_group, self).write(cr, uid, ids, vals, context=context)
+ # Restart the cache on the domain_get method of ir.rule
+ self.pool.get('ir.rule').domain_get()
+ return res
ir_rule_group()
class ir_rule(osv.osv):
- _name = 'ir.rule'
- _rec_name = 'field_id'
-
- def _operand(self,cr,uid,context):
-
- def get(object, level=3, recur=None, root_tech='', root=''):
- res = []
- if not recur:
- recur = []
- fields = self.pool.get(object).fields_get(cr,uid)
- key = fields.keys()
- key.sort()
- for k in key:
-
- if fields[k]['type'] in ('many2one'):
- res.append((root_tech+'.'+k+'.id',
- root+'/'+fields[k]['string']))
-
- elif fields[k]['type'] in ('many2many', 'one2many'):
- res.append(('\',\'.join(map(lambda x: str(x.id), '+root_tech+'.'+k+'))',
- root+'/'+fields[k]['string']))
-
- else:
- res.append((root_tech+'.'+k,
- root+'/'+fields[k]['string']))
-
- if (fields[k]['type'] in recur) and (level>0):
- res.extend(get(fields[k]['relation'], level-1,
- recur, root_tech+'.'+k, root+'/'+fields[k]['string']))
-
- return res
-
- res = [("False", "False"), ("True", "True"), ("user.id", "User")]
- res += get('res.users', level=1,
- recur=['many2one'], root_tech='user', root='User')
- return res
-
- def _domain_force_get(self, cr, uid, ids, field_name, arg, context={}):
- res = {}
- for rule in self.browse(cr, uid, ids, context):
- if rule.domain_force:
- res[rule.id] = eval(rule.domain_force, {'user': self.pool.get('res.users').browse(cr, 1, uid),
- 'time':time})
- else:
- if rule.operator in ('in', 'child_of'):
- dom = eval("[('%s', '%s', [%s])]" % (rule.field_id.name, rule.operator,
- rule.operand), {'user': self.pool.get('res.users').browse(cr, 1, uid),
- 'time':time})
- else:
- dom = eval("[('%s', '%s', %s)]" % (rule.field_id.name, rule.operator,
- rule.operand), {'user': self.pool.get('res.users').browse(cr, 1, uid),
- 'time':time})
- res[rule.id] = dom
- return res
-
- _columns = {
- 'field_id': fields.many2one('ir.model.fields', 'Field',domain= "[('model_id','=', parent.model_id)]", select=1, required=True),
- 'operator':fields.selection((('=', '='), ('<>', '<>'), ('<=', '<='), ('>=', '>='), ('in', 'in'), ('child_of', 'child_of')), 'Operator', required=True),
- 'operand':fields.selection(_operand,'Operand', size=64, required=True),
- 'rule_group': fields.many2one('ir.rule.group', 'Group', select=2, required=True, ondelete="cascade"),
- 'domain_force': fields.char('Force Domain', size=250),
- 'domain': fields.function(_domain_force_get, method=True, string='Domain', type='char', size=250)
- }
-
- def onchange_all(self, cr, uid, ids, field_id, operator, operand):
- if not (field_id or operator or operand):
- return {}
-
- def domain_get(self, cr, uid, model_name):
- # root user above constraint
- if uid == 1:
- return '', []
-
- cr.execute("""SELECT r.id FROM
- ir_rule r
- JOIN (ir_rule_group g
- JOIN ir_model m ON (g.model_id = m.id))
- ON (g.id = r.rule_group)
- 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))
- ids = map(lambda x:x[0], cr.fetchall())
- if not ids:
- return '', []
- obj = self.pool.get(model_name)
- add = []
- add_str = []
- sub = []
- sub_str = []
- clause={}
- clause_global={}
- for rule in self.browse(cr, uid, ids):
- dom = rule.domain
- if rule.rule_group['global']:
- clause_global.setdefault(rule.rule_group.id, [])
- clause_global[rule.rule_group.id].append(obj._where_calc(cr, uid, dom, active_test=False))
- else:
- clause.setdefault(rule.rule_group.id, [])
- clause[rule.rule_group.id].append(obj._where_calc(cr, uid, dom, active_test=False))
-
- def _query(clause, test):
- query = ''
- val = []
- for g in clause.values():
- if not g:
- continue
- if len(query):
- query += ' '+test+' '
- query += '('
- first = True
- for c in g:
- if not first:
- query += ' AND '
- first = False
- query += '('
- first2 = True
- for clause in c[0]:
- if not first2:
- query += ' AND '
- first2 = False
- query += clause
- query += ')'
- val += c[1]
- query += ')'
- return query, val
-
- query, val = _query(clause, 'OR')
- query_global, val_global = _query(clause_global, 'OR')
- if query_global:
- if query:
- query = '('+query+') OR '+query_global
- val.extend(val_global)
- else:
- query = query_global
- val = val_global
-
-
- if query:
- query = '('+query+')'
- return query, val
- domain_get = tools.cache()(domain_get)
-
- def unlink(self, cr, uid, ids, context=None):
- res = super(ir_rule, self).unlink(cr, uid, ids, context=context)
- # Restart the cache on the domain_get method of ir.rule
- self.domain_get()
- return res
-
- def create(self, cr, user, vals, context=None):
- res = super(ir_rule, self).create(cr, user, vals, context=context)
- # Restart the cache on the domain_get method of ir.rule
- self.domain_get()
- return res
-
- def write(self, cr, uid, ids, vals, context=None):
- if not context:
- context={}
- res = super(ir_rule, self).write(cr, uid, ids, vals, context=context)
- # Restart the cache on the domain_get method
- self.domain_get()
- return res
+ _name = 'ir.rule'
+ _rec_name = 'field_id'
+
+ def _operand(self,cr,uid,context):
+
+ def get(object, level=3, recur=None, root_tech='', root=''):
+ res = []
+ if not recur:
+ recur = []
+ fields = self.pool.get(object).fields_get(cr,uid)
+ key = fields.keys()
+ key.sort()
+ for k in key:
+
+ if fields[k]['type'] in ('many2one'):
+ res.append((root_tech+'.'+k+'.id',
+ root+'/'+fields[k]['string']))
+
+ elif fields[k]['type'] in ('many2many', 'one2many'):
+ res.append(('\',\'.join(map(lambda x: str(x.id), '+root_tech+'.'+k+'))',
+ root+'/'+fields[k]['string']))
+
+ else:
+ res.append((root_tech+'.'+k,
+ root+'/'+fields[k]['string']))
+
+ if (fields[k]['type'] in recur) and (level>0):
+ res.extend(get(fields[k]['relation'], level-1,
+ recur, root_tech+'.'+k, root+'/'+fields[k]['string']))
+
+ return res
+
+ res = [("False", "False"), ("True", "True"), ("user.id", "User")]
+ res += get('res.users', level=1,
+ recur=['many2one'], root_tech='user', root='User')
+ return res
+
+ def _domain_force_get(self, cr, uid, ids, field_name, arg, context={}):
+ res = {}
+ for rule in self.browse(cr, uid, ids, context):
+ if rule.domain_force:
+ res[rule.id] = eval(rule.domain_force, {'user': self.pool.get('res.users').browse(cr, 1, uid),
+ 'time':time})
+ else:
+ if rule.operator in ('in', 'child_of'):
+ dom = eval("[('%s', '%s', [%s])]" % (rule.field_id.name, rule.operator,
+ rule.operand), {'user': self.pool.get('res.users').browse(cr, 1, uid),
+ 'time':time})
+ else:
+ dom = eval("[('%s', '%s', %s)]" % (rule.field_id.name, rule.operator,
+ rule.operand), {'user': self.pool.get('res.users').browse(cr, 1, uid),
+ 'time':time})
+ res[rule.id] = dom
+ return res
+
+ _columns = {
+ 'field_id': fields.many2one('ir.model.fields', 'Field',domain= "[('model_id','=', parent.model_id)]", select=1, required=True),
+ 'operator':fields.selection((('=', '='), ('<>', '<>'), ('<=', '<='), ('>=', '>='), ('in', 'in'), ('child_of', 'child_of')), 'Operator', required=True),
+ 'operand':fields.selection(_operand,'Operand', size=64, required=True),
+ 'rule_group': fields.many2one('ir.rule.group', 'Group', select=2, required=True, ondelete="cascade"),
+ 'domain_force': fields.char('Force Domain', size=250),
+ 'domain': fields.function(_domain_force_get, method=True, string='Domain', type='char', size=250)
+ }
+
+ def onchange_all(self, cr, uid, ids, field_id, operator, operand):
+ if not (field_id or operator or operand):
+ return {}
+
+ def domain_get(self, cr, uid, model_name):
+ # root user above constraint
+ if uid == 1:
+ return '', []
+
+ cr.execute("""SELECT r.id FROM
+ ir_rule r
+ JOIN (ir_rule_group g
+ JOIN ir_model m ON (g.model_id = m.id))
+ ON (g.id = r.rule_group)
+ 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))
+ ids = map(lambda x:x[0], cr.fetchall())
+ if not ids:
+ return '', []
+ obj = self.pool.get(model_name)
+ add = []
+ add_str = []
+ sub = []
+ sub_str = []
+ clause={}
+ clause_global={}
+ for rule in self.browse(cr, uid, ids):
+ dom = rule.domain
+ if rule.rule_group['global']:
+ clause_global.setdefault(rule.rule_group.id, [])
+ clause_global[rule.rule_group.id].append(obj._where_calc(cr, uid, dom, active_test=False))
+ else:
+ clause.setdefault(rule.rule_group.id, [])
+ clause[rule.rule_group.id].append(obj._where_calc(cr, uid, dom, active_test=False))
+
+ def _query(clause, test):
+ query = ''
+ val = []
+ for g in clause.values():
+ if not g:
+ continue
+ if len(query):
+ query += ' '+test+' '
+ query += '('
+ first = True
+ for c in g:
+ if not first:
+ query += ' AND '
+ first = False
+ query += '('
+ first2 = True
+ for clause in c[0]:
+ if not first2:
+ query += ' AND '
+ first2 = False
+ query += clause
+ query += ')'
+ val += c[1]
+ query += ')'
+ return query, val
+
+ query, val = _query(clause, 'OR')
+ query_global, val_global = _query(clause_global, 'OR')
+ if query_global:
+ if query:
+ query = '('+query+') OR '+query_global
+ val.extend(val_global)
+ else:
+ query = query_global
+ val = val_global
+
+
+ if query:
+ query = '('+query+')'
+ return query, val
+ domain_get = tools.cache()(domain_get)
+
+ def unlink(self, cr, uid, ids, context=None):
+ res = super(ir_rule, self).unlink(cr, uid, ids, context=context)
+ # Restart the cache on the domain_get method of ir.rule
+ self.domain_get()
+ return res
+
+ def create(self, cr, user, vals, context=None):
+ res = super(ir_rule, self).create(cr, user, vals, context=context)
+ # Restart the cache on the domain_get method of ir.rule
+ self.domain_get()
+ return res
+
+ def write(self, cr, uid, ids, vals, context=None):
+ if not context:
+ context={}
+ res = super(ir_rule, self).write(cr, uid, ids, vals, context=context)
+ # Restart the cache on the domain_get method
+ self.domain_get()
+ return res
ir_rule()
diff --git a/bin/addons/base/ir/ir_sequence.py b/bin/addons/base/ir/ir_sequence.py
index c8941f5c324..7eff555ab10 100644
--- a/bin/addons/base/ir/ir_sequence.py
+++ b/bin/addons/base/ir/ir_sequence.py
@@ -31,52 +31,52 @@ import time
from osv import fields,osv
class ir_sequence_type(osv.osv):
- _name = 'ir.sequence.type'
- _columns = {
- 'name': fields.char('Sequence Name',size=64, required=True),
- 'code': fields.char('Sequence Code',size=32, required=True),
- }
+ _name = 'ir.sequence.type'
+ _columns = {
+ 'name': fields.char('Sequence Name',size=64, required=True),
+ 'code': fields.char('Sequence Code',size=32, required=True),
+ }
ir_sequence_type()
def _code_get(self, cr, uid, context={}):
- cr.execute('select code, name from ir_sequence_type')
- return cr.fetchall()
+ cr.execute('select code, name from ir_sequence_type')
+ return cr.fetchall()
class ir_sequence(osv.osv):
- _name = 'ir.sequence'
- _columns = {
- 'name': fields.char('Sequence Name',size=64, required=True),
- 'code': fields.selection(_code_get, 'Sequence Code',size=64, required=True),
- 'active': fields.boolean('Active'),
- 'prefix': fields.char('Prefix',size=64),
- 'suffix': fields.char('Suffix',size=64),
- 'number_next': fields.integer('Next Number', required=True),
- 'number_increment': fields.integer('Increment Number', required=True),
- 'padding' : fields.integer('Number padding', required=True),
- }
- _defaults = {
- 'active': lambda *a: True,
- 'number_increment': lambda *a: 1,
- 'number_next': lambda *a: 1,
- 'padding' : lambda *a : 0,
- }
+ _name = 'ir.sequence'
+ _columns = {
+ 'name': fields.char('Sequence Name',size=64, required=True),
+ 'code': fields.selection(_code_get, 'Sequence Code',size=64, required=True),
+ 'active': fields.boolean('Active'),
+ 'prefix': fields.char('Prefix',size=64),
+ 'suffix': fields.char('Suffix',size=64),
+ 'number_next': fields.integer('Next Number', required=True),
+ 'number_increment': fields.integer('Increment Number', required=True),
+ 'padding' : fields.integer('Number padding', required=True),
+ }
+ _defaults = {
+ 'active': lambda *a: True,
+ 'number_increment': lambda *a: 1,
+ 'number_next': lambda *a: 1,
+ 'padding' : lambda *a : 0,
+ }
- def _process(self, s):
- return (s or '') % {'year':time.strftime('%Y'), 'month': time.strftime('%m'), 'day':time.strftime('%d')}
+ def _process(self, s):
+ return (s or '') % {'year':time.strftime('%Y'), 'month': time.strftime('%m'), 'day':time.strftime('%d')}
- def get_id(self, cr, uid, sequence_id, test='id=%d'):
- cr.execute('lock table ir_sequence')
- cr.execute('select id,number_next,number_increment,prefix,suffix,padding from ir_sequence where '+test+' and active=True', (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'],))
- if res['number_next']:
- return self._process(res['prefix']) + '%%0%sd' % res['padding'] % res['number_next'] + self._process(res['suffix'])
- else:
- return self._process(res['prefix']) + self._process(res['suffix'])
- return False
+ def get_id(self, cr, uid, sequence_id, test='id=%d'):
+ cr.execute('lock table ir_sequence')
+ cr.execute('select id,number_next,number_increment,prefix,suffix,padding from ir_sequence where '+test+' and active=True', (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'],))
+ if res['number_next']:
+ return self._process(res['prefix']) + '%%0%sd' % res['padding'] % res['number_next'] + self._process(res['suffix'])
+ else:
+ return self._process(res['prefix']) + self._process(res['suffix'])
+ return False
- def get(self, cr, uid, code):
- return self.get_id(cr, uid, code, test='code=%s')
+ def get(self, cr, uid, code):
+ return self.get_id(cr, uid, code, test='code=%s')
ir_sequence()
diff --git a/bin/addons/base/ir/ir_translation.py b/bin/addons/base/ir/ir_translation.py
index ac87f08d76a..bda2654b033 100644
--- a/bin/addons/base/ir/ir_translation.py
+++ b/bin/addons/base/ir/ir_translation.py
@@ -32,131 +32,131 @@ from osv.osv import Cacheable
import tools
TRANSLATION_TYPE = [
- ('field', 'Field'),
- ('model', 'Model'),
- ('rml', 'RML'),
- ('selection', 'Selection'),
- ('view', 'View'),
- ('wizard_button', 'Wizard Button'),
- ('wizard_field', 'Wizard Field'),
- ('wizard_view', 'Wizard View'),
- ('xsl', 'XSL'),
- ('help', 'Help'),
- ('code', 'Code'),
- ('constraint', 'Constraint'),
+ ('field', 'Field'),
+ ('model', 'Model'),
+ ('rml', 'RML'),
+ ('selection', 'Selection'),
+ ('view', 'View'),
+ ('wizard_button', 'Wizard Button'),
+ ('wizard_field', 'Wizard Field'),
+ ('wizard_view', 'Wizard View'),
+ ('xsl', 'XSL'),
+ ('help', 'Help'),
+ ('code', 'Code'),
+ ('constraint', 'Constraint'),
]
class ir_translation(osv.osv, Cacheable):
- _name = "ir.translation"
- _log_access = False
+ _name = "ir.translation"
+ _log_access = False
- def _get_language(self, cr, uid, context):
- lang_obj = self.pool.get('res.lang')
- lang_ids = lang_obj.search(cr, uid, [('translatable', '=', True)],
- context=context)
- langs = lang_obj.browse(cr, uid, lang_ids, context=context)
- res = [(lang.code, lang.name) for lang in langs]
- for lang_dict in tools.scan_languages():
- if lang_dict not in res:
- res.append(lang_dict)
- return res
+ def _get_language(self, cr, uid, context):
+ lang_obj = self.pool.get('res.lang')
+ lang_ids = lang_obj.search(cr, uid, [('translatable', '=', True)],
+ context=context)
+ langs = lang_obj.browse(cr, uid, lang_ids, context=context)
+ res = [(lang.code, lang.name) for lang in langs]
+ for lang_dict in tools.scan_languages():
+ if lang_dict not in res:
+ res.append(lang_dict)
+ return res
- _columns = {
- 'name': fields.char('Field Name', size=128, required=True),
- 'res_id': fields.integer('Resource ID'),
- 'lang': fields.selection(_get_language, string='Language', size=5),
- 'type': fields.selection(TRANSLATION_TYPE, string='Type', size=16),
- 'src': fields.text('Source'),
- 'value': fields.text('Translation Value'),
- }
- _sql = """
- create index ir_translation_ltn on ir_translation (lang,type,name);
- create index ir_translation_res_id on ir_translation (res_id);
- """
+ _columns = {
+ 'name': fields.char('Field Name', size=128, required=True),
+ 'res_id': fields.integer('Resource ID'),
+ 'lang': fields.selection(_get_language, string='Language', size=5),
+ 'type': fields.selection(TRANSLATION_TYPE, string='Type', size=16),
+ 'src': fields.text('Source'),
+ 'value': fields.text('Translation Value'),
+ }
+ _sql = """
+ create index ir_translation_ltn on ir_translation (lang,type,name);
+ create index ir_translation_res_id on ir_translation (res_id);
+ """
- 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:
- 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))+')',
- (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
+ 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:
+ 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))+')',
+ (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
- def _set_ids(self, cr, uid, name, tt, lang, ids, value):
- cr.execute('delete from ir_translation ' \
- 'where lang=%s ' \
- 'and type=%s ' \
- 'and name=%s ' \
- 'and res_id in ('+','.join(map(str,ids))+')',
- (lang,tt,name))
- for id in ids:
- self.create(cr, uid, {
- 'lang':lang,
- 'type':tt,
- 'name':name,
- 'res_id':id,
- 'value':value,
- })
- return len(ids)
+ def _set_ids(self, cr, uid, name, tt, lang, ids, value):
+ cr.execute('delete from ir_translation ' \
+ 'where lang=%s ' \
+ 'and type=%s ' \
+ 'and name=%s ' \
+ 'and res_id in ('+','.join(map(str,ids))+')',
+ (lang,tt,name))
+ for id in ids:
+ self.create(cr, uid, {
+ 'lang':lang,
+ 'type':tt,
+ 'name':name,
+ 'res_id':id,
+ 'value':value,
+ })
+ return len(ids)
- 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
+ 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')
- cr.execute('select value ' \
- 'from ir_translation ' \
- 'where lang=%s ' \
- 'and type=%s ' \
- 'and name=%s ' \
- 'and src=%s',
- (lang, tt, str(name), source))
- else:
- cr.execute('select value ' \
- 'from ir_translation ' \
- 'where lang=%s ' \
- 'and type=%s ' \
- '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
+ if source:
+ #if isinstance(source, unicode):
+ # source = source.encode('utf8')
+ cr.execute('select value ' \
+ 'from ir_translation ' \
+ 'where lang=%s ' \
+ 'and type=%s ' \
+ 'and name=%s ' \
+ 'and src=%s',
+ (lang, tt, str(name), source))
+ else:
+ cr.execute('select value ' \
+ 'from ir_translation ' \
+ 'where lang=%s ' \
+ 'and type=%s ' \
+ '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(cusor, user, ids,
- context=context)
+ def unlink(self, cursor, user, ids, context=None):
+ self.clear()
+ return super(ir_translation, self).unlink(cusor, 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 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)
+ 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()
diff --git a/bin/addons/base/ir/ir_ui_menu.py b/bin/addons/base/ir/ir_ui_menu.py
index 13445bb8df9..2fa9268776c 100644
--- a/bin/addons/base/ir/ir_ui_menu.py
+++ b/bin/addons/base/ir/ir_ui_menu.py
@@ -32,12 +32,12 @@ from osv.orm import browse_null, browse_record
import re
def one_in(setA, setB):
- """Check the presence of an element of setA in setB
- """
- for x in setA:
- if x in setB:
- return True
- return False
+ """Check the presence of an element of setA in setB
+ """
+ for x in setA:
+ if x in setB:
+ return True
+ return False
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',
@@ -68,143 +68,143 @@ icons = map(lambda x: (x,x), ['STOCK_ABOUT', 'STOCK_ADD', 'STOCK_APPLY', 'STOCK_
])
class many2many_unique(fields.many2many):
- def set(self, cr, obj, id, name, values, user=None, context=None):
- if not values:
- return
- val = values[:]
- 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]))
- if cr.fetchall():
- val.remove(act)
- return super(many2many_unique, self).set(cr, obj, id, name, val, user=user,
- context=context)
+ def set(self, cr, obj, id, name, values, user=None, context=None):
+ if not values:
+ return
+ val = values[:]
+ 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]))
+ if cr.fetchall():
+ val.remove(act)
+ return super(many2many_unique, self).set(cr, obj, id, name, val, user=user,
+ context=context)
class ir_ui_menu(osv.osv):
- _name = 'ir.ui.menu'
- def search(self, cr, uid, args, offset=0, limit=2000, order=None,
- context=None, count=False):
- if context is None:
- context = {}
- ids = osv.orm.orm.search(self, cr, uid, args, offset, limit, order,
- context=context)
- if uid==1:
- return ids
- user_groups = self.pool.get('res.users').read(cr, uid, [uid])[0]['groups_id']
- result = []
- for menu in self.browse(cr, uid, ids):
- if not len(menu.groups_id):
- result.append(menu.id)
- continue
- for g in menu.groups_id:
- if g.id in user_groups:
- result.append(menu.id)
- break
- return result
+ _name = 'ir.ui.menu'
+ def search(self, cr, uid, args, offset=0, limit=2000, order=None,
+ context=None, count=False):
+ if context is None:
+ context = {}
+ ids = osv.orm.orm.search(self, cr, uid, args, offset, limit, order,
+ context=context)
+ if uid==1:
+ return ids
+ user_groups = self.pool.get('res.users').read(cr, uid, [uid])[0]['groups_id']
+ result = []
+ for menu in self.browse(cr, uid, ids):
+ if not len(menu.groups_id):
+ result.append(menu.id)
+ continue
+ for g in menu.groups_id:
+ if g.id in user_groups:
+ result.append(menu.id)
+ break
+ return result
- def _get_full_name(self, cr, uid, ids, name, args, context):
- res = {}
- for m in self.browse(cr, uid, ids, context=context):
- res[m.id] = self._get_one_full_name(m)
- return res
+ def _get_full_name(self, cr, uid, ids, name, args, context):
+ res = {}
+ for m in self.browse(cr, uid, ids, context=context):
+ res[m.id] = self._get_one_full_name(m)
+ return res
- def _get_one_full_name(self, menu, level=6):
- if level<=0:
- return '...'
- if menu.parent_id:
- parent_path = self._get_one_full_name(menu.parent_id, level-1) + "/"
- else:
- parent_path = ''
- return parent_path + menu.name
+ def _get_one_full_name(self, menu, level=6):
+ if level<=0:
+ return '...'
+ if menu.parent_id:
+ parent_path = self._get_one_full_name(menu.parent_id, level-1) + "/"
+ else:
+ parent_path = ''
+ return parent_path + menu.name
- def copy(self, cr, uid, id, default=None, context=None):
- ir_values_obj = self.pool.get('ir.values')
- res = super(ir_ui_menu, self).copy(cr, uid, id, context=context)
- datas=self.read(cr,uid,[res],['name'])[0]
- rex=re.compile('\([0-9]+\)')
- concat=rex.findall(datas['name'])
- if concat:
- next_num=eval(concat[0])+1
- datas['name']=rex.sub(('(%d)'%next_num),datas['name'])
- else:
- datas['name']=datas['name']+'(1)'
- self.write(cr,uid,[res],{'name':datas['name']})
- ids = ir_values_obj.search(cr, uid, [
- ('model', '=', 'ir.ui.menu'),
- ('res_id', '=', id),
- ])
- for iv in ir_values_obj.browse(cr, uid, ids):
- new_id = ir_values_obj.copy(cr, uid, iv.id,
- default={'res_id': res}, context=context)
- return res
+ def copy(self, cr, uid, id, default=None, context=None):
+ ir_values_obj = self.pool.get('ir.values')
+ res = super(ir_ui_menu, self).copy(cr, uid, id, context=context)
+ datas=self.read(cr,uid,[res],['name'])[0]
+ rex=re.compile('\([0-9]+\)')
+ concat=rex.findall(datas['name'])
+ if concat:
+ next_num=eval(concat[0])+1
+ datas['name']=rex.sub(('(%d)'%next_num),datas['name'])
+ else:
+ datas['name']=datas['name']+'(1)'
+ self.write(cr,uid,[res],{'name':datas['name']})
+ ids = ir_values_obj.search(cr, uid, [
+ ('model', '=', 'ir.ui.menu'),
+ ('res_id', '=', id),
+ ])
+ for iv in ir_values_obj.browse(cr, uid, ids):
+ new_id = ir_values_obj.copy(cr, uid, iv.id,
+ default={'res_id': res}, context=context)
+ return res
- def _action(self, cursor, user, ids, name, arg, context=None):
- res = {}
- values_obj = self.pool.get('ir.values')
- value_ids = values_obj.search(cursor, user, [
- ('model', '=', self._name), ('key', '=', 'action'),
- ('key2', '=', 'tree_but_open'), ('res_id', 'in', ids)],
- context=context)
- values_action = {}
- for value in values_obj.browse(cursor, user, value_ids,
- context=context):
- values_action[value.res_id] = value.value
- for menu_id in ids:
- res[menu_id] = values_action.get(menu_id, False)
- return res
+ def _action(self, cursor, user, ids, name, arg, context=None):
+ res = {}
+ values_obj = self.pool.get('ir.values')
+ value_ids = values_obj.search(cursor, user, [
+ ('model', '=', self._name), ('key', '=', 'action'),
+ ('key2', '=', 'tree_but_open'), ('res_id', 'in', ids)],
+ context=context)
+ values_action = {}
+ for value in values_obj.browse(cursor, user, value_ids,
+ context=context):
+ values_action[value.res_id] = value.value
+ for menu_id in ids:
+ res[menu_id] = values_action.get(menu_id, False)
+ return res
- def _action_inv(self, cursor, user, menu_id, name, value, arg, context=None):
- if context is None:
- context = {}
- ctx = context.copy()
- if 'read_delta' in ctx:
- del ctx['read_delta']
- values_obj = self.pool.get('ir.values')
- values_ids = values_obj.search(cursor, user, [
- ('model', '=', self._name), ('key', '=', 'action'),
- ('key2', '=', 'tree_but_open'), ('res_id', '=', menu_id)],
- context=context)
- if values_ids:
- values_obj.write(cursor, user, values_ids[0], {'value': value},
- context=ctx)
- else:
- values_obj.create(cursor, user, {
- 'name': 'Menuitem',
- 'model': self._name,
- 'value': value,
- 'object': True,
- 'key': 'action',
- 'key2': 'tree_but_open',
- 'res_id': menu_id,
- }, context=ctx)
+ def _action_inv(self, cursor, user, menu_id, name, value, arg, context=None):
+ if context is None:
+ context = {}
+ ctx = context.copy()
+ if 'read_delta' in ctx:
+ del ctx['read_delta']
+ values_obj = self.pool.get('ir.values')
+ values_ids = values_obj.search(cursor, user, [
+ ('model', '=', self._name), ('key', '=', 'action'),
+ ('key2', '=', 'tree_but_open'), ('res_id', '=', menu_id)],
+ context=context)
+ if values_ids:
+ values_obj.write(cursor, user, values_ids[0], {'value': value},
+ context=ctx)
+ else:
+ values_obj.create(cursor, user, {
+ 'name': 'Menuitem',
+ 'model': self._name,
+ 'value': value,
+ 'object': True,
+ 'key': 'action',
+ 'key2': 'tree_but_open',
+ 'res_id': menu_id,
+ }, context=ctx)
- _columns = {
- 'name': fields.char('Menu', size=64, required=True, translate=True),
- 'sequence': fields.integer('Sequence'),
- 'child_id' : fields.one2many('ir.ui.menu', 'parent_id','Child ids'),
- 'parent_id': fields.many2one('ir.ui.menu', 'Parent Menu', select=True),
- 'groups_id': many2many_unique('res.groups', 'ir_ui_menu_group_rel',
- 'menu_id', 'gid', 'Groups'),
- 'complete_name': fields.function(_get_full_name, method=True,
- string='Complete Name', type='char', size=128),
- 'icon': fields.selection(icons, 'Icon', size=64),
- 'action': fields.function(_action, fnct_inv=_action_inv,
- method=True, type='reference', string='Action',
- selection=[
- ('ir.actions.report.custom', 'ir.actions.report.custom'),
- ('ir.actions.report.xml', 'ir.actions.report.xml'),
- ('ir.actions.act_window', 'ir.actions.act_window'),
- ('ir.actions.wizard', 'ir.actions.wizard'),
+ _columns = {
+ 'name': fields.char('Menu', size=64, required=True, translate=True),
+ 'sequence': fields.integer('Sequence'),
+ 'child_id' : fields.one2many('ir.ui.menu', 'parent_id','Child ids'),
+ 'parent_id': fields.many2one('ir.ui.menu', 'Parent Menu', select=True),
+ 'groups_id': many2many_unique('res.groups', 'ir_ui_menu_group_rel',
+ 'menu_id', 'gid', 'Groups'),
+ 'complete_name': fields.function(_get_full_name, method=True,
+ string='Complete Name', type='char', size=128),
+ 'icon': fields.selection(icons, 'Icon', size=64),
+ 'action': fields.function(_action, fnct_inv=_action_inv,
+ method=True, type='reference', string='Action',
+ selection=[
+ ('ir.actions.report.custom', 'ir.actions.report.custom'),
+ ('ir.actions.report.xml', 'ir.actions.report.xml'),
+ ('ir.actions.act_window', 'ir.actions.act_window'),
+ ('ir.actions.wizard', 'ir.actions.wizard'),
('ir.actions.url', 'ir.actions.act_url'),
- ]),
- }
- _defaults = {
- 'icon' : lambda *a: 'STOCK_OPEN',
- 'sequence' : lambda *a: 10
- }
- _order = "sequence,id"
+ ]),
+ }
+ _defaults = {
+ 'icon' : lambda *a: 'STOCK_OPEN',
+ 'sequence' : lambda *a: 10
+ }
+ _order = "sequence,id"
ir_ui_menu()
diff --git a/bin/addons/base/ir/ir_ui_view.py b/bin/addons/base/ir/ir_ui_view.py
index 2ab5fa16895..75d93f04d3a 100644
--- a/bin/addons/base/ir/ir_ui_view.py
+++ b/bin/addons/base/ir/ir_ui_view.py
@@ -34,89 +34,89 @@ import netsvc
import os
def _check_xml(self, cr, uid, ids, context={}):
- for view in self.browse(cr, uid, ids, context):
- eview = etree.fromstring(view.arch)
- frng = tools.file_open(os.path.join('base','rng',view.type+'.rng'))
- 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, relaxng.error_log.last_error)
- print view.arch
- return False
- return True
+ for view in self.browse(cr, uid, ids, context):
+ eview = etree.fromstring(view.arch)
+ frng = tools.file_open(os.path.join('base','rng',view.type+'.rng'))
+ 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, relaxng.error_log.last_error)
+ print view.arch
+ return False
+ return True
class view(osv.osv):
- _name = 'ir.ui.view'
- _columns = {
- 'name': fields.char('View Name',size=64, required=True),
- 'model': fields.char('Model', size=64, required=True),
- 'priority': fields.integer('Priority', required=True),
- 'type': fields.selection((
- ('tree','Tree'),
- ('form','Form'),
- ('graph', 'Graph'),
- ('calendar', 'Calendar')), 'View Type', required=True),
- 'arch': fields.text('View Architecture', required=True),
- 'inherit_id': fields.many2one('ir.ui.view', 'Inherited View'),
- 'field_parent': fields.char('Childs Field',size=64),
- }
- _defaults = {
- 'arch': lambda *a: '<?xml version="1.0"?>\n<tree title="Unknwown">\n\t<field name="name"/>\n</tree>',
- 'priority': lambda *a: 16
- }
- _order = "priority"
- _constraints = [
- (_check_xml, 'Invalid XML for View Architecture!', ['arch'])
- ]
+ _name = 'ir.ui.view'
+ _columns = {
+ 'name': fields.char('View Name',size=64, required=True),
+ 'model': fields.char('Model', size=64, required=True),
+ 'priority': fields.integer('Priority', required=True),
+ 'type': fields.selection((
+ ('tree','Tree'),
+ ('form','Form'),
+ ('graph', 'Graph'),
+ ('calendar', 'Calendar')), 'View Type', required=True),
+ 'arch': fields.text('View Architecture', required=True),
+ 'inherit_id': fields.many2one('ir.ui.view', 'Inherited View'),
+ 'field_parent': fields.char('Childs Field',size=64),
+ }
+ _defaults = {
+ 'arch': lambda *a: '<?xml version="1.0"?>\n<tree title="Unknwown">\n\t<field name="name"/>\n</tree>',
+ 'priority': lambda *a: 16
+ }
+ _order = "priority"
+ _constraints = [
+ (_check_xml, 'Invalid XML for View Architecture!', ['arch'])
+ ]
view()
#class UserView(osv.osv):
-# _name = 'ir.ui.view.user'
-# _columns = {
-# 'name': fields.char('View Name',size=64, required=True),
-# 'model': fields.char('Model', size=64, required=True),
-# 'priority': fields.integer('Priority', required=True),
-# 'type': fields.selection((
-# ('tree','Tree'),
-# ('form','Form'),
-# ('graph', 'Graph'),
-# ('calendar', 'Calendar')), 'View Type', required=True),
-# 'arch': fields.text('View Architecture', required=True),
-# 'inherit_id': fields.many2one('ir.ui.view', 'Inherited View'),
-# 'field_parent': fields.char('Childs Field',size=64),
-# 'user_id': fields.many2one('res.users', 'User'),
-# 'ref_id': fields.many2one('ir.ui.view', 'Inherited View'),
-# }
-# _defaults = {
-# 'arch': lambda *a: '<?xml version="1.0"?>\n<tree title="Unknwown">\n\t<field name="name"/>\n</tree>',
-# 'priority': lambda *a: 16
-# }
-# _order = "priority"
-# _constraints = [
-# (_check_xml, 'Invalid XML for View Architecture!', ['arch'])
-# ]
+# _name = 'ir.ui.view.user'
+# _columns = {
+# 'name': fields.char('View Name',size=64, required=True),
+# 'model': fields.char('Model', size=64, required=True),
+# 'priority': fields.integer('Priority', required=True),
+# 'type': fields.selection((
+# ('tree','Tree'),
+# ('form','Form'),
+# ('graph', 'Graph'),
+# ('calendar', 'Calendar')), 'View Type', required=True),
+# 'arch': fields.text('View Architecture', required=True),
+# 'inherit_id': fields.many2one('ir.ui.view', 'Inherited View'),
+# 'field_parent': fields.char('Childs Field',size=64),
+# 'user_id': fields.many2one('res.users', 'User'),
+# 'ref_id': fields.many2one('ir.ui.view', 'Inherited View'),
+# }
+# _defaults = {
+# 'arch': lambda *a: '<?xml version="1.0"?>\n<tree title="Unknwown">\n\t<field name="name"/>\n</tree>',
+# 'priority': lambda *a: 16
+# }
+# _order = "priority"
+# _constraints = [
+# (_check_xml, 'Invalid XML for View Architecture!', ['arch'])
+# ]
#
#UserView()
class view_sc(osv.osv):
- _name = 'ir.ui.view_sc'
- _columns = {
- 'name': fields.char('Shortcut Name', size=64, required=True),
- 'res_id': fields.many2one('ir.values','Resource Ref.', ondelete='cascade'),
- 'sequence': fields.integer('Sequence'),
- 'user_id': fields.many2one('res.users', 'User Ref.', required=True, ondelete='cascade'),
- 'resource': fields.char('Resource Name', size=64, required=True)
- }
+ _name = 'ir.ui.view_sc'
+ _columns = {
+ 'name': fields.char('Shortcut Name', size=64, required=True),
+ 'res_id': fields.many2one('ir.values','Resource Ref.', ondelete='cascade'),
+ 'sequence': fields.integer('Sequence'),
+ 'user_id': fields.many2one('res.users', 'User Ref.', required=True, ondelete='cascade'),
+ 'resource': fields.char('Resource Name', size=64, required=True)
+ }
- def get_sc(self, cr, uid, user_id, model='ir.ui.menu', context={}):
- ids = self.search(cr, uid, [('user_id','=',user_id),('resource','=',model)], context=context)
- return self.read(cr, uid, ids, ['res_id','name'], context=context)
+ def get_sc(self, cr, uid, user_id, model='ir.ui.menu', context={}):
+ ids = self.search(cr, uid, [('user_id','=',user_id),('resource','=',model)], context=context)
+ return self.read(cr, uid, ids, ['res_id','name'], context=context)
- _order = 'sequence'
- _defaults = {
- 'resource': lambda *a: 'ir.ui.menu',
- 'user_id': lambda obj, cr, uid, context: uid,
- }
+ _order = 'sequence'
+ _defaults = {
+ 'resource': lambda *a: 'ir.ui.menu',
+ 'user_id': lambda obj, cr, uid, context: uid,
+ }
view_sc()
diff --git a/bin/addons/base/ir/ir_values.py b/bin/addons/base/ir/ir_values.py
index 84fafefa3f4..2681e562ec7 100644
--- a/bin/addons/base/ir/ir_values.py
+++ b/bin/addons/base/ir/ir_values.py
@@ -32,221 +32,221 @@ import pickle
from tools.translate import _
class ir_values(osv.osv):
- _name = 'ir.values'
-
- def _value_unpickle(self, cursor, user, ids, name, arg, context=None):
- res = {}
- for report in self.browse(cursor, user, ids, context=context):
- value = report[name[:-9]]
- if not report.object and value:
- try:
- value = str(pickle.loads(value))
- except:
- pass
- res[report.id] = value
- return res
-
- def _value_pickle(self, cursor, user, id, name, value, arg, context=None):
- if context is None:
- context = {}
- ctx = context.copy()
- if 'read_delta' in ctx:
- del ctx['read_delta']
- if not self.browse(cursor, user, id, context=context).object:
- value = pickle.dumps(eval(value))
- self.write(cursor, user, id, {name[:-9]: value}, context=ctx)
-
- _columns = {
- 'name': fields.char('Name', size=128),
- 'model': fields.char('Model', size=128),
- 'value': fields.text('Value'),
- 'value_unpickle': fields.function(_value_unpickle, fnct_inv=_value_pickle,
- method=True, type='text', string='Value'),
- 'object': fields.boolean('Is Object'),
- 'key': fields.char('Type', size=128),
- 'key2': fields.char('Value', size=256),
- 'meta': fields.text('Meta Datas'),
- 'meta_unpickle': fields.function(_value_unpickle, fnct_inv=_value_pickle,
- method=True, type='text', string='Meta Datas'),
- 'res_id': fields.integer('Resource ID'),
- 'user_id': fields.many2one('res.users', 'User', ondelete='cascade'),
- 'company_id': fields.many2one('res.company', 'Company')
- }
- _defaults = {
- 'key': lambda *a: 'action',
- 'key2': lambda *a: 'tree_but_open',
- 'company_id': lambda *a: False
- }
-
- def _auto_init(self, cr, context={}):
- super(ir_values, self)._auto_init(cr, context)
- cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'ir_values_key_model_key2_index\'')
- if not cr.fetchone():
- cr.execute('CREATE INDEX ir_values_key_model_key2_index ON ir_values (key, model, key2)')
- cr.commit()
-
- def set(self, cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=False, preserve_user=False, company=False):
- if type(value)==type(u''):
- value = value.encode('utf8')
- if not isobject:
- value = pickle.dumps(value)
- if meta:
- meta = pickle.dumps(meta)
- ids_res = []
- for model in models:
- if type(model)==type([]) or type(model)==type(()):
- model,res_id = model
- else:
- res_id=False
- if replace:
- if key in ('meta', 'default'):
- ids = self.search(cr, uid, [
- ('key', '=', key),
- ('key2', '=', key2),
- ('name', '=', name),
- ('model', '=', model),
- ('res_id', '=', res_id),
- ('user_id', '=', preserve_user and uid)
- ])
- else:
- ids = self.search(cr, uid, [
- ('key', '=', key),
- ('key2', '=', key2),
- ('value', '=', value),
- ('model', '=', model),
- ('res_id', '=', res_id),
- ('user_id', '=', preserve_user and uid)
- ])
- self.unlink(cr, uid, ids)
- vals = {
- 'name': name,
- 'value': value,
- 'model': model,
- 'object': isobject,
- 'key': key,
- 'key2': key2 and key2[:200],
- 'meta': meta,
- 'user_id': preserve_user and uid,
- }
- if company:
- cid = self.pool.get('res.users').browse(cr, uid, uid, context={}).company_id.id
- vals['company_id']=cid
- if res_id:
- vals['res_id']= res_id
- ids_res.append(self.create(cr, uid, vals))
- return ids_res
-
- def get(self, cr, uid, key, key2, models, meta=False, context={}, res_id_req=False, without_user=True, key2_req=True):
- result = []
- for m in models:
- if type(m)==type([]) or type(m)==type(()):
- m,res_id = m
- else:
- res_id=False
-
- where1 = ['key=%s','model=%s']
- where2 = [key,str(m)]
- where_opt = []
- if key2:
- where1.append('key2=%s')
- where2.append(key2[:200])
- else:
- dest = where1
- if not key2_req or meta:
- dest=where_opt
- dest.append('key2 is null')
-
- if res_id_req and (models[-1][0]==m):
- if res_id:
- where1.append('res_id=%d' % (res_id,))
- else:
- where1.append('(res_id is NULL)')
- elif res_id:
- if (models[-1][0]==m):
- where1.append('(res_id=%d or (res_id is null))' % (res_id,))
- where_opt.append('res_id=%d' % (res_id,))
- else:
- where1.append('res_id=%d' % (res_id,))
-
-# if not without_user:
- where_opt.append('user_id=%d' % (uid,))
-
-
- result = []
- ok = True
- while ok:
- if not where_opt:
- cr.execute('select id from ir_values where ' +\
- ' and '.join(where1)+' and user_id is null', where2)
- else:
- cr.execute('select id from ir_values where ' +\
- ' and '.join(where1+where_opt), where2)
- result.extend([x[0] for x in cr.fetchall()])
- if len(where_opt):
- where_opt.pop()
- else:
- ok = False
-
- if result:
- break
-
- if not result:
- return []
- cid = self.pool.get('res.users').browse(cr, uid, uid, context={}).company_id.id
- cr.execute('select id,name,value,object,meta, key ' \
- 'from ir_values ' \
- 'where id in ('+','.join(map(str,result))+') ' \
- 'and (company_id is null or company_id = %d) '\
- 'ORDER BY user_id', (cid,))
- result = cr.fetchall()
-
- def _result_get(x, keys):
- if x[1] in keys:
- return False
- keys.append(x[1])
- if x[3]:
- model,id = x[2].split(',')
- try:
- id = int(id)
- datas = self.pool.get(model).read(cr, uid, [id], False, context)
- except:
- return False
- if not len(datas):
- #ir_del(cr, uid, x[0])
- return False
- def clean(x):
- for key in ('report_sxw_content', 'report_rml_content',
- 'report_sxw', 'report_rml', 'report_sxw_content_data',
- 'report_rml_content_data'):
- if key in x:
- del x[key]
- return x
- datas = clean(datas[0])
- else:
- datas = pickle.loads(x[2])
- if meta:
- meta2 = pickle.loads(x[4])
- return (x[0],x[1],datas,meta2)
- return (x[0],x[1],datas)
- keys = []
- res = filter(bool, map(lambda x: _result_get(x, keys), list(result)))
- res2 = res[:]
- for r in res:
- if type(r) == type([]):
- if r[2]['type'] == 'ir.actions.report.xml' or r[2]['type'] == 'ir.actions.report.xml':
- print
- if r[2].has_key('groups_id'):
- groups = r[2]['groups_id']
- if len(groups) > 0:
- group_ids = ','.join([ str(x) for x in r[2]['groups_id']])
- cr.execute("select count(*) from res_groups_users_rel where gid in (%s) and uid='%s'" % (group_ids, uid))
- gr_ids = cr.fetchall()
- if not gr_ids[0][0] > 0:
- res2.remove(r)
- else:
- #raise osv.except_osv('Error !','You have not permission to perform operation !!!')
- res2.remove(r)
- return res2
+ _name = 'ir.values'
+
+ def _value_unpickle(self, cursor, user, ids, name, arg, context=None):
+ res = {}
+ for report in self.browse(cursor, user, ids, context=context):
+ value = report[name[:-9]]
+ if not report.object and value:
+ try:
+ value = str(pickle.loads(value))
+ except:
+ pass
+ res[report.id] = value
+ return res
+
+ def _value_pickle(self, cursor, user, id, name, value, arg, context=None):
+ if context is None:
+ context = {}
+ ctx = context.copy()
+ if 'read_delta' in ctx:
+ del ctx['read_delta']
+ if not self.browse(cursor, user, id, context=context).object:
+ value = pickle.dumps(eval(value))
+ self.write(cursor, user, id, {name[:-9]: value}, context=ctx)
+
+ _columns = {
+ 'name': fields.char('Name', size=128),
+ 'model': fields.char('Model', size=128),
+ 'value': fields.text('Value'),
+ 'value_unpickle': fields.function(_value_unpickle, fnct_inv=_value_pickle,
+ method=True, type='text', string='Value'),
+ 'object': fields.boolean('Is Object'),
+ 'key': fields.char('Type', size=128),
+ 'key2': fields.char('Value', size=256),
+ 'meta': fields.text('Meta Datas'),
+ 'meta_unpickle': fields.function(_value_unpickle, fnct_inv=_value_pickle,
+ method=True, type='text', string='Meta Datas'),
+ 'res_id': fields.integer('Resource ID'),
+ 'user_id': fields.many2one('res.users', 'User', ondelete='cascade'),
+ 'company_id': fields.many2one('res.company', 'Company')
+ }
+ _defaults = {
+ 'key': lambda *a: 'action',
+ 'key2': lambda *a: 'tree_but_open',
+ 'company_id': lambda *a: False
+ }
+
+ def _auto_init(self, cr, context={}):
+ super(ir_values, self)._auto_init(cr, context)
+ cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'ir_values_key_model_key2_index\'')
+ if not cr.fetchone():
+ cr.execute('CREATE INDEX ir_values_key_model_key2_index ON ir_values (key, model, key2)')
+ cr.commit()
+
+ def set(self, cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=False, preserve_user=False, company=False):
+ if type(value)==type(u''):
+ value = value.encode('utf8')
+ if not isobject:
+ value = pickle.dumps(value)
+ if meta:
+ meta = pickle.dumps(meta)
+ ids_res = []
+ for model in models:
+ if type(model)==type([]) or type(model)==type(()):
+ model,res_id = model
+ else:
+ res_id=False
+ if replace:
+ if key in ('meta', 'default'):
+ ids = self.search(cr, uid, [
+ ('key', '=', key),
+ ('key2', '=', key2),
+ ('name', '=', name),
+ ('model', '=', model),
+ ('res_id', '=', res_id),
+ ('user_id', '=', preserve_user and uid)
+ ])
+ else:
+ ids = self.search(cr, uid, [
+ ('key', '=', key),
+ ('key2', '=', key2),
+ ('value', '=', value),
+ ('model', '=', model),
+ ('res_id', '=', res_id),
+ ('user_id', '=', preserve_user and uid)
+ ])
+ self.unlink(cr, uid, ids)
+ vals = {
+ 'name': name,
+ 'value': value,
+ 'model': model,
+ 'object': isobject,
+ 'key': key,
+ 'key2': key2 and key2[:200],
+ 'meta': meta,
+ 'user_id': preserve_user and uid,
+ }
+ if company:
+ cid = self.pool.get('res.users').browse(cr, uid, uid, context={}).company_id.id
+ vals['company_id']=cid
+ if res_id:
+ vals['res_id']= res_id
+ ids_res.append(self.create(cr, uid, vals))
+ return ids_res
+
+ def get(self, cr, uid, key, key2, models, meta=False, context={}, res_id_req=False, without_user=True, key2_req=True):
+ result = []
+ for m in models:
+ if type(m)==type([]) or type(m)==type(()):
+ m,res_id = m
+ else:
+ res_id=False
+
+ where1 = ['key=%s','model=%s']
+ where2 = [key,str(m)]
+ where_opt = []
+ if key2:
+ where1.append('key2=%s')
+ where2.append(key2[:200])
+ else:
+ dest = where1
+ if not key2_req or meta:
+ dest=where_opt
+ dest.append('key2 is null')
+
+ if res_id_req and (models[-1][0]==m):
+ if res_id:
+ where1.append('res_id=%d' % (res_id,))
+ else:
+ where1.append('(res_id is NULL)')
+ elif res_id:
+ if (models[-1][0]==m):
+ where1.append('(res_id=%d or (res_id is null))' % (res_id,))
+ where_opt.append('res_id=%d' % (res_id,))
+ else:
+ where1.append('res_id=%d' % (res_id,))
+
+# if not without_user:
+ where_opt.append('user_id=%d' % (uid,))
+
+
+ result = []
+ ok = True
+ while ok:
+ if not where_opt:
+ cr.execute('select id from ir_values where ' +\
+ ' and '.join(where1)+' and user_id is null', where2)
+ else:
+ cr.execute('select id from ir_values where ' +\
+ ' and '.join(where1+where_opt), where2)
+ result.extend([x[0] for x in cr.fetchall()])
+ if len(where_opt):
+ where_opt.pop()
+ else:
+ ok = False
+
+ if result:
+ break
+
+ if not result:
+ return []
+ cid = self.pool.get('res.users').browse(cr, uid, uid, context={}).company_id.id
+ cr.execute('select id,name,value,object,meta, key ' \
+ 'from ir_values ' \
+ 'where id in ('+','.join(map(str,result))+') ' \
+ 'and (company_id is null or company_id = %d) '\
+ 'ORDER BY user_id', (cid,))
+ result = cr.fetchall()
+
+ def _result_get(x, keys):
+ if x[1] in keys:
+ return False
+ keys.append(x[1])
+ if x[3]:
+ model,id = x[2].split(',')
+ try:
+ id = int(id)
+ datas = self.pool.get(model).read(cr, uid, [id], False, context)
+ except:
+ return False
+ if not len(datas):
+ #ir_del(cr, uid, x[0])
+ return False
+ def clean(x):
+ for key in ('report_sxw_content', 'report_rml_content',
+ 'report_sxw', 'report_rml', 'report_sxw_content_data',
+ 'report_rml_content_data'):
+ if key in x:
+ del x[key]
+ return x
+ datas = clean(datas[0])
+ else:
+ datas = pickle.loads(x[2])
+ if meta:
+ meta2 = pickle.loads(x[4])
+ return (x[0],x[1],datas,meta2)
+ return (x[0],x[1],datas)
+ keys = []
+ res = filter(bool, map(lambda x: _result_get(x, keys), list(result)))
+ res2 = res[:]
+ for r in res:
+ if type(r) == type([]):
+ if r[2]['type'] == 'ir.actions.report.xml' or r[2]['type'] == 'ir.actions.report.xml':
+ print
+ if r[2].has_key('groups_id'):
+ groups = r[2]['groups_id']
+ if len(groups) > 0:
+ group_ids = ','.join([ str(x) for x in r[2]['groups_id']])
+ cr.execute("select count(*) from res_groups_users_rel where gid in (%s) and uid='%s'" % (group_ids, uid))
+ gr_ids = cr.fetchall()
+ if not gr_ids[0][0] > 0:
+ res2.remove(r)
+ else:
+ #raise osv.except_osv('Error !','You have not permission to perform operation !!!')
+ res2.remove(r)
+ return res2
ir_values()
diff --git a/bin/addons/base/ir/wizard/wizard_menu.py b/bin/addons/base/ir/wizard/wizard_menu.py
index 966bb84430b..32d25e3c849 100644
--- a/bin/addons/base/ir/wizard/wizard_menu.py
+++ b/bin/addons/base/ir/wizard/wizard_menu.py
@@ -30,57 +30,57 @@
from osv import fields,osv
class wizard_model_menu(osv.osv_memory):
- _name = 'wizard.ir.model.menu.create'
- _columns = {
- 'model_id': fields.many2one('ir.model','Model', required=True),
- 'menu_id': fields.many2one('ir.ui.menu', 'Parent Menu', required=True),
- 'name': fields.char('Menu Name', size=64, required=True),
- 'view_ids': fields.one2many('wizard.ir.model.menu.create.line', 'wizard_id', 'Views'),
- }
- _defaults = {
- 'model_id': lambda self,cr,uid,ctx: ctx.get('model_id', False)
- }
- def menu_create(self, cr, uid, ids, context={}):
- for menu in self.browse(cr, uid, ids, context):
- view_mode = []
- views = []
- for view in menu.view_ids:
- view_mode.append(view.view_type)
- views.append( (0,0,{
- 'view_id': view.view_id and view.view_id.id or False,
- 'view_mode': view.view_type,
- 'sequence': view.sequence
- }))
- val = {
- 'name': menu.name,
- 'res_model': menu.model_id.model,
- 'view_type': 'form',
- 'view_mode': ','.join(view_mode)
- }
- if views:
- val['view_ids'] = views
- else:
- val['view_mode'] = 'tree,form'
- action_id = self.pool.get('ir.actions.act_window').create(cr, uid, val)
- self.pool.get('ir.ui.menu').create(cr, uid, {
- 'name': menu.name,
- 'parent_id': menu.menu_id.id,
- 'action': 'ir.actions.act_window,%d' % (action_id,),
- 'icon': 'STOCK_INDENT'
- }, context)
- return {'type':'ir.actions.act_window_close'}
+ _name = 'wizard.ir.model.menu.create'
+ _columns = {
+ 'model_id': fields.many2one('ir.model','Model', required=True),
+ 'menu_id': fields.many2one('ir.ui.menu', 'Parent Menu', required=True),
+ 'name': fields.char('Menu Name', size=64, required=True),
+ 'view_ids': fields.one2many('wizard.ir.model.menu.create.line', 'wizard_id', 'Views'),
+ }
+ _defaults = {
+ 'model_id': lambda self,cr,uid,ctx: ctx.get('model_id', False)
+ }
+ def menu_create(self, cr, uid, ids, context={}):
+ for menu in self.browse(cr, uid, ids, context):
+ view_mode = []
+ views = []
+ for view in menu.view_ids:
+ view_mode.append(view.view_type)
+ views.append( (0,0,{
+ 'view_id': view.view_id and view.view_id.id or False,
+ 'view_mode': view.view_type,
+ 'sequence': view.sequence
+ }))
+ val = {
+ 'name': menu.name,
+ 'res_model': menu.model_id.model,
+ 'view_type': 'form',
+ 'view_mode': ','.join(view_mode)
+ }
+ if views:
+ val['view_ids'] = views
+ else:
+ val['view_mode'] = 'tree,form'
+ action_id = self.pool.get('ir.actions.act_window').create(cr, uid, val)
+ self.pool.get('ir.ui.menu').create(cr, uid, {
+ 'name': menu.name,
+ 'parent_id': menu.menu_id.id,
+ 'action': 'ir.actions.act_window,%d' % (action_id,),
+ 'icon': 'STOCK_INDENT'
+ }, context)
+ return {'type':'ir.actions.act_window_close'}
wizard_model_menu()
class wizard_model_menu_line(osv.osv_memory):
- _name = 'wizard.ir.model.menu.create.line'
- _columns = {
- 'wizard_id': fields.many2one('wizard.ir.model.menu.create','Wizard'),
- 'sequence': fields.integer('Sequence'),
- 'view_type': fields.selection([('tree','Tree'),('form','Form'),('graph','Graph'),('calendar','Calendar')],'View Type',required=True),
- 'view_id': fields.many2one('ir.ui.view', 'View'),
- }
- _defaults = {
- 'view_type': lambda self,cr,uid,ctx: 'tree'
- }
+ _name = 'wizard.ir.model.menu.create.line'
+ _columns = {
+ 'wizard_id': fields.many2one('wizard.ir.model.menu.create','Wizard'),
+ 'sequence': fields.integer('Sequence'),
+ 'view_type': fields.selection([('tree','Tree'),('form','Form'),('graph','Graph'),('calendar','Calendar')],'View Type',required=True),
+ 'view_id': fields.many2one('ir.ui.view', 'View'),
+ }
+ _defaults = {
+ 'view_type': lambda self,cr,uid,ctx: 'tree'
+ }
wizard_model_menu_line()
diff --git a/bin/addons/base/ir/workflow/print_instance.py b/bin/addons/base/ir/workflow/print_instance.py
index 74f2bd31733..428df57ac0e 100644
--- a/bin/addons/base/ir/workflow/print_instance.py
+++ b/bin/addons/base/ir/workflow/print_instance.py
@@ -34,175 +34,175 @@ 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,))
- nodes = cr.dictfetchall()
- activities = {}
- actfrom = {}
- actto = {}
- 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'],))
- wkfinfo = cr.dictfetchone()
- graph2 = pydot.Cluster('subflow'+str(n['subflow_id']), fontsize=12, label = "Subflow: "+n['name']+'\\nOSV: '+wkfinfo['osv'])
- (s1,s2) = graph_get(cr, graph2, n['subflow_id'], nested,workitem)
- graph.add_subgraph(graph2)
- actfrom[n['id']] = s2
- actto[n['id']] = s1
- else:
- args = {}
- if n['flow_start'] or n['flow_stop']:
- args['style']='filled'
- args['color']='lightgrey'
- args['label']=n['name']
- if n['subflow_id']:
- args['shape'] = 'box'
- if n['id'] in workitem:
- args['label']+='\\nx '+str(workitem[n['id']])
- args['color'] = "red"
- graph.add_node(pydot.Node(n['id'], **args))
- actfrom[n['id']] = (n['id'],{})
- actto[n['id']] = (n['id'],{})
- cr.execute('select * from wkf_transition where act_from in ('+','.join(map(lambda x: str(x['id']),nodes))+')')
- transitions = cr.dictfetchall()
- for t in transitions:
- args = {}
- args['label'] = str(t['condition']).replace(' or ', '\\nor ').replace(' and ', '\\nand ')
- if t['signal']:
- args['label'] += '\\n'+str(t['signal'])
- args['style'] = 'bold'
-
- if activities[t['act_from']]['split_mode']=='AND':
- args['arrowtail']='box'
- elif str(activities[t['act_from']]['split_mode'])=='OR ':
- args['arrowtail']='inv'
-
- if activities[t['act_to']]['join_mode']=='AND':
- args['arrowhead']='crow'
-
- activity_from = actfrom[t['act_from']][1].get(t['signal'], actfrom[t['act_from']][0])
- activity_to = actto[t['act_to']][1].get(t['signal'], actto[t['act_to']][0])
- graph.add_edge(pydot.Edge( activity_from ,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,))
- start = cr.fetchone()[0]
- cr.execute("select 'subflow.'||name,id from wkf_activity where flow_stop=True and wkf_id=%d", (wkf_id,))
- stop = cr.fetchall()
- stop = (stop[0][1], dict(stop))
- return ((start,{}),stop)
+ import pydot
+ cr.execute('select * from wkf_activity where wkf_id=%d', (wkf_id,))
+ nodes = cr.dictfetchall()
+ activities = {}
+ actfrom = {}
+ actto = {}
+ 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'],))
+ wkfinfo = cr.dictfetchone()
+ graph2 = pydot.Cluster('subflow'+str(n['subflow_id']), fontsize=12, label = "Subflow: "+n['name']+'\\nOSV: '+wkfinfo['osv'])
+ (s1,s2) = graph_get(cr, graph2, n['subflow_id'], nested,workitem)
+ graph.add_subgraph(graph2)
+ actfrom[n['id']] = s2
+ actto[n['id']] = s1
+ else:
+ args = {}
+ if n['flow_start'] or n['flow_stop']:
+ args['style']='filled'
+ args['color']='lightgrey'
+ args['label']=n['name']
+ if n['subflow_id']:
+ args['shape'] = 'box'
+ if n['id'] in workitem:
+ args['label']+='\\nx '+str(workitem[n['id']])
+ args['color'] = "red"
+ graph.add_node(pydot.Node(n['id'], **args))
+ actfrom[n['id']] = (n['id'],{})
+ actto[n['id']] = (n['id'],{})
+ cr.execute('select * from wkf_transition where act_from in ('+','.join(map(lambda x: str(x['id']),nodes))+')')
+ transitions = cr.dictfetchall()
+ for t in transitions:
+ args = {}
+ args['label'] = str(t['condition']).replace(' or ', '\\nor ').replace(' and ', '\\nand ')
+ if t['signal']:
+ args['label'] += '\\n'+str(t['signal'])
+ args['style'] = 'bold'
+
+ if activities[t['act_from']]['split_mode']=='AND':
+ args['arrowtail']='box'
+ elif str(activities[t['act_from']]['split_mode'])=='OR ':
+ args['arrowtail']='inv'
+
+ if activities[t['act_to']]['join_mode']=='AND':
+ args['arrowhead']='crow'
+
+ activity_from = actfrom[t['act_from']][1].get(t['signal'], actfrom[t['act_from']][0])
+ activity_to = actto[t['act_to']][1].get(t['signal'], actto[t['act_to']][0])
+ graph.add_edge(pydot.Edge( activity_from ,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,))
+ start = cr.fetchone()[0]
+ cr.execute("select 'subflow.'||name,id from wkf_activity where flow_stop=True and wkf_id=%d", (wkf_id,))
+ stop = cr.fetchall()
+ stop = (stop[0][1], dict(stop))
+ return ((start,{}),stop)
def graph_instance_get(cr, graph, inst_id, nested=False):
- workitems = {}
- cr.execute('select * from wkf_instance where id=%d', (inst_id,))
- inst = cr.dictfetchone()
+ workitems = {}
+ cr.execute('select * from wkf_instance where id=%d', (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,))
- workitems = dict(cr.fetchall())
+ def workitem_get(instance):
+ cr.execute('select act_id,count(*) from wkf_workitem where inst_id=%d group by act_id', (instance,))
+ workitems = dict(cr.fetchall())
- cr.execute('select subflow_id from wkf_workitem where inst_id=%d', (instance,))
- for (subflow_id,) in cr.fetchall():
- workitems.update(workitem_get(subflow_id))
- return workitems
- graph_get(cr, graph, inst['wkf_id'], nested, workitem_get(inst_id))
+ cr.execute('select subflow_id from wkf_workitem where inst_id=%d', (instance,))
+ for (subflow_id,) in cr.fetchall():
+ workitems.update(workitem_get(subflow_id))
+ return workitems
+ graph_get(cr, graph, inst['wkf_id'], nested, workitem_get(inst_id))
#
# TODO: pas clean: concurrent !!!
#
class report_graph_instance(object):
- def __init__(self, cr, uid, ids, data):
- logger = netsvc.Logger()
- try:
- import pydot
- except Exception,e:
- logger.notifyChannel('workflow', netsvc.LOG_WARNING,
- 'Import Error for pydot, you will not be able to render workflows\n'
- 'Consider Installing PyDot or dependencies: http://dkbza.org/pydot.html')
- raise e
- self.done = False
-
- try:
- cr.execute('select * from wkf where osv=%s limit 1',
- (data['model'],))
- wkfinfo = cr.dictfetchone()
- if not wkfinfo:
- ps_string = '''%PS-Adobe-3.0
+ def __init__(self, cr, uid, ids, data):
+ logger = netsvc.Logger()
+ try:
+ import pydot
+ except Exception,e:
+ logger.notifyChannel('workflow', netsvc.LOG_WARNING,
+ 'Import Error for pydot, you will not be able to render workflows\n'
+ 'Consider Installing PyDot or dependencies: http://dkbza.org/pydot.html')
+ raise e
+ self.done = False
+
+ try:
+ cr.execute('select * from wkf where osv=%s limit 1',
+ (data['model'],))
+ wkfinfo = cr.dictfetchone()
+ if not wkfinfo:
+ ps_string = '''%PS-Adobe-3.0
/inch {72 mul} def
/Times-Roman findfont 50 scalefont setfont
1.5 inch 15 inch moveto
(No workflow defined) show
showpage'''
- else:
- cr.execute('SELECT id FROM wkf_instance \
- WHERE res_id=%d AND wkf_id=%d \
- ORDER BY state LIMIT 1',
- (data['id'], wkfinfo['id']))
- inst_id = cr.fetchone()
- if not inst_id:
- ps_string = '''%PS-Adobe-3.0
+ else:
+ cr.execute('SELECT id FROM wkf_instance \
+ WHERE res_id=%d AND wkf_id=%d \
+ ORDER BY state LIMIT 1',
+ (data['id'], wkfinfo['id']))
+ inst_id = cr.fetchone()
+ if not inst_id:
+ ps_string = '''%PS-Adobe-3.0
/inch {72 mul} def
/Times-Roman findfont 50 scalefont setfont
1.5 inch 15 inch moveto
(No workflow instance defined) show
showpage'''
- else:
- inst_id = inst_id[0]
- graph = pydot.Dot(fontsize=16, label="\\n\\nWorkflow: %s\\n OSV: %s" % (wkfinfo['name'],wkfinfo['osv']))
- graph.set('size', '10.7,7.3')
- graph.set('center', '1')
- graph.set('ratio', 'auto')
- graph.set('rotate', '90')
- graph.set('rankdir', 'LR')
- graph_instance_get(cr, graph, inst_id, data.get('nested', False))
- ps_string = graph.create_ps(prog='dot')
- except Exception, e:
- import traceback, sys
- tb_s = reduce(lambda x, y: x+y, traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback))
- logger.notifyChannel('workflow', netsvc.LOG_ERROR, 'Exception in call: ' + tb_s)
- # string is in PS, like the success message would have been
- ps_string = '''%PS-Adobe-3.0
+ else:
+ inst_id = inst_id[0]
+ graph = pydot.Dot(fontsize=16, label="\\n\\nWorkflow: %s\\n OSV: %s" % (wkfinfo['name'],wkfinfo['osv']))
+ graph.set('size', '10.7,7.3')
+ graph.set('center', '1')
+ graph.set('ratio', 'auto')
+ graph.set('rotate', '90')
+ graph.set('rankdir', 'LR')
+ graph_instance_get(cr, graph, inst_id, data.get('nested', False))
+ ps_string = graph.create_ps(prog='dot')
+ except Exception, e:
+ import traceback, sys
+ tb_s = reduce(lambda x, y: x+y, traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback))
+ logger.notifyChannel('workflow', netsvc.LOG_ERROR, 'Exception in call: ' + tb_s)
+ # string is in PS, like the success message would have been
+ ps_string = '''%PS-Adobe-3.0
/inch {72 mul} def
/Times-Roman findfont 50 scalefont setfont
1.5 inch 15 inch moveto
(No workflow available) show
showpage'''
- if os.name == "nt":
- prog = 'ps2pdf.bat'
- else:
- prog = 'ps2pdf'
- args = (prog, '-', '-')
- input, output = tools.exec_command_pipe(*args)
- input.write(ps_string)
- input.close()
- self.result = output.read()
- output.close()
- self.done = True
-
- def is_done(self):
- return self.done
-
- def get(self):
- if self.done:
- return self.result
- else:
- return None
+ if os.name == "nt":
+ prog = 'ps2pdf.bat'
+ else:
+ prog = 'ps2pdf'
+ args = (prog, '-', '-')
+ input, output = tools.exec_command_pipe(*args)
+ input.write(ps_string)
+ input.close()
+ self.result = output.read()
+ output.close()
+ self.done = True
+
+ def is_done(self):
+ return self.done
+
+ def get(self):
+ if self.done:
+ return self.result
+ else:
+ return None
class report_graph(report.interface.report_int):
- def __init__(self, name, table):
- report.interface.report_int.__init__(self, name)
- self.table = table
-
- def result(self):
- if self.obj.is_done():
- return (True, self.obj.get(), 'pdf')
- else:
- return (False, False, False)
-
- def create(self, cr, uid, ids, data, context={}):
- self.obj = report_graph_instance(cr, uid, ids, data)
- return (self.obj.get(), 'pdf')
+ def __init__(self, name, table):
+ report.interface.report_int.__init__(self, name)
+ self.table = table
+
+ def result(self):
+ if self.obj.is_done():
+ return (True, self.obj.get(), 'pdf')
+ else:
+ return (False, False, False)
+
+ def create(self, cr, uid, ids, data, context={}):
+ self.obj = report_graph_instance(cr, uid, ids, data)
+ return (self.obj.get(), 'pdf')
report_graph('report.workflow.instance.graph', 'ir.workflow')
diff --git a/bin/addons/base/ir/workflow/pydot/__init__.py b/bin/addons/base/ir/workflow/pydot/__init__.py
index 6232f794cdd..6232f794cdd 100755..100644
--- a/bin/addons/base/ir/workflow/pydot/__init__.py
+++ b/bin/addons/base/ir/workflow/pydot/__init__.py
diff --git a/bin/addons/base/ir/workflow/pydot/dot_parser.py b/bin/addons/base/ir/workflow/pydot/dot_parser.py
index 30007ed47de..67a763144c7 100755..100644
--- a/bin/addons/base/ir/workflow/pydot/dot_parser.py
+++ b/bin/addons/base/ir/workflow/pydot/dot_parser.py
@@ -14,339 +14,339 @@ import glob
import pydot
from pyparsing import __version__ as pyparsing_version
-from pyparsing import Literal, CaselessLiteral, Word, \
- Upcase, OneOrMore, ZeroOrMore, Forward, NotAny, \
- delimitedList, oneOf, Group, Optional, Combine, \
- alphas, nums, restOfLine, cStyleComment, nums, \
- alphanums, printables, empty, quotedString, \
- ParseException, ParseResults, CharsNotIn, _noncomma
+from pyparsing import Literal, CaselessLiteral, Word, \
+ Upcase, OneOrMore, ZeroOrMore, Forward, NotAny, \
+ delimitedList, oneOf, Group, Optional, Combine, \
+ alphas, nums, restOfLine, cStyleComment, nums, \
+ alphanums, printables, empty, quotedString, \
+ ParseException, ParseResults, CharsNotIn, _noncomma
class P_AttrList:
- def __init__(self, toks):
- self.attrs = {}
- i = 0
- while i < len(toks):
- attrname = toks[i]
- attrvalue = toks[i+1]
- self.attrs[attrname] = attrvalue
- i += 2
+ def __init__(self, toks):
+ self.attrs = {}
+ i = 0
+ while i < len(toks):
+ attrname = toks[i]
+ attrvalue = toks[i+1]
+ self.attrs[attrname] = attrvalue
+ i += 2
- def __repr__(self):
- return "%s(%r)" % (self.__class__.__name__, self.attrs)
+ def __repr__(self):
+ return "%s(%r)" % (self.__class__.__name__, self.attrs)
class DefaultStatement(P_AttrList):
- def __init__(self, default_type, attrs):
- self.default_type = default_type
- self.attrs = attrs
+ def __init__(self, default_type, attrs):
+ self.default_type = default_type
+ self.attrs = attrs
- def __repr__(self):
- return "%s(%s, %r)" % \
- (self.__class__.__name__, self.default_type, self.attrs)
+ def __repr__(self):
+ return "%s(%s, %r)" % \
+ (self.__class__.__name__, self.default_type, self.attrs)
def push_top_graph_stmt(str, loc, toks):
- attrs = {}
- g = None
-
- for element in toks:
- if isinstance(element, ParseResults) or \
- isinstance(element, tuple) or \
- isinstance(element, list):
-
- element = element[0]
-
- if element == 'strict':
- attrs['strict'] = True
- elif element in ['graph', 'digraph']:
- attrs['graph_type'] = element
- elif type(element) == type(''):
- attrs['graph_name'] = element
- elif isinstance(element, pydot.Graph):
- g = pydot.Graph(**attrs)
- g.__dict__.update(element.__dict__)
- for e in g.get_edge_list():
- e.parent_graph = g
- for e in g.get_node_list():
- e.parent_graph = g
- for e in g.get_subgraph_list():
- e.set_graph_parent(g)
-
- elif isinstance(element, P_AttrList):
- attrs.update(element.attrs)
- else:
- raise ValueError, "Unknown element statement: %r " % element
-
- if g is not None:
- g.__dict__.update(attrs)
- return g
+ attrs = {}
+ g = None
+
+ for element in toks:
+ if isinstance(element, ParseResults) or \
+ isinstance(element, tuple) or \
+ isinstance(element, list):
+
+ element = element[0]
+
+ if element == 'strict':
+ attrs['strict'] = True
+ elif element in ['graph', 'digraph']:
+ attrs['graph_type'] = element
+ elif type(element) == type(''):
+ attrs['graph_name'] = element
+ elif isinstance(element, pydot.Graph):
+ g = pydot.Graph(**attrs)
+ g.__dict__.update(element.__dict__)
+ for e in g.get_edge_list():
+ e.parent_graph = g
+ for e in g.get_node_list():
+ e.parent_graph = g
+ for e in g.get_subgraph_list():
+ e.set_graph_parent(g)
+
+ elif isinstance(element, P_AttrList):
+ attrs.update(element.attrs)
+ else:
+ raise ValueError, "Unknown element statement: %r " % element
+
+ if g is not None:
+ g.__dict__.update(attrs)
+ return g
def add_defaults(element, defaults):
- d = element.__dict__
- for key, value in defaults.items():
- if not d.get(key):
- d[key] = value
+ d = element.__dict__
+ for key, value in defaults.items():
+ if not d.get(key):
+ d[key] = value
def add_elements(g, toks, defaults_graph=None, defaults_node=None, defaults_edge=None):
-
- if defaults_graph is None:
- defaults_graph = {}
- if defaults_node is None:
- defaults_node = {}
- if defaults_edge is None:
- defaults_edge = {}
-
- for element in toks:
- if isinstance(element, pydot.Graph):
- add_defaults(element, defaults_graph)
- g.add_subgraph(element)
- elif isinstance(element, pydot.Node):
- add_defaults(element, defaults_node)
- g.add_node(element)
- elif isinstance(element, pydot.Edge):
- add_defaults(element, defaults_edge)
- g.add_edge(element)
- elif isinstance(element, ParseResults):
- for e in element:
- add_elements(g, [e], defaults_graph, defaults_node, defaults_edge)
- elif isinstance(element, DefaultStatement):
- if element.default_type == 'graph':
- default_graph_attrs = pydot.Node('graph')
- default_graph_attrs.__dict__.update(element.attrs)
- g.add_node(default_graph_attrs)
-# defaults_graph.update(element.attrs)
-# g.__dict__.update(element.attrs)
- elif element.default_type == 'node':
- default_node_attrs = pydot.Node('node')
- default_node_attrs.__dict__.update(element.attrs)
- g.add_node(default_node_attrs)
- #defaults_node.update(element.attrs)
- elif element.default_type == 'edge':
- default_edge_attrs = pydot.Node('edge')
- default_edge_attrs.__dict__.update(element.attrs)
- g.add_node(default_edge_attrs)
- #defaults_edge.update(element.attrs)
- else:
- raise ValueError, "Unknown DefaultStatement: %s " % element.default_type
- elif isinstance(element, P_AttrList):
- g.__dict__.update(element.attrs)
- else:
- raise ValueError, "Unknown element statement: %r " % element
+
+ if defaults_graph is None:
+ defaults_graph = {}
+ if defaults_node is None:
+ defaults_node = {}
+ if defaults_edge is None:
+ defaults_edge = {}
+
+ for element in toks:
+ if isinstance(element, pydot.Graph):
+ add_defaults(element, defaults_graph)
+ g.add_subgraph(element)
+ elif isinstance(element, pydot.Node):
+ add_defaults(element, defaults_node)
+ g.add_node(element)
+ elif isinstance(element, pydot.Edge):
+ add_defaults(element, defaults_edge)
+ g.add_edge(element)
+ elif isinstance(element, ParseResults):
+ for e in element:
+ add_elements(g, [e], defaults_graph, defaults_node, defaults_edge)
+ elif isinstance(element, DefaultStatement):
+ if element.default_type == 'graph':
+ default_graph_attrs = pydot.Node('graph')
+ default_graph_attrs.__dict__.update(element.attrs)
+ g.add_node(default_graph_attrs)
+# defaults_graph.update(element.attrs)
+# g.__dict__.update(element.attrs)
+ elif element.default_type == 'node':
+ default_node_attrs = pydot.Node('node')
+ default_node_attrs.__dict__.update(element.attrs)
+ g.add_node(default_node_attrs)
+ #defaults_node.update(element.attrs)
+ elif element.default_type == 'edge':
+ default_edge_attrs = pydot.Node('edge')
+ default_edge_attrs.__dict__.update(element.attrs)
+ g.add_node(default_edge_attrs)
+ #defaults_edge.update(element.attrs)
+ else:
+ raise ValueError, "Unknown DefaultStatement: %s " % element.default_type
+ elif isinstance(element, P_AttrList):
+ g.__dict__.update(element.attrs)
+ else:
+ raise ValueError, "Unknown element statement: %r " % element
def push_graph_stmt(str, loc, toks):
- g = pydot.Subgraph()
- add_elements(g, toks)
- return g
+ g = pydot.Subgraph()
+ add_elements(g, toks)
+ return g
-def push_subgraph_stmt(str, loc, toks):
- for e in toks:
- if len(e)==3:
- g = e[2]
- g.set_name(e[1])
+def push_subgraph_stmt(str, loc, toks):
+ for e in toks:
+ if len(e)==3:
+ g = e[2]
+ g.set_name(e[1])
- return g
+ return g
def push_default_stmt(str, loc, toks):
- # The pydot class instances should be marked as
- # default statements to be inherited by actual
- # graphs, nodes and edges.
- # print "push_default_stmt", toks
- default_type = toks[0][0]
- if len(toks) > 1:
- attrs = toks[1].attrs
- else:
- attrs = {}
-
- if default_type in ['graph', 'node', 'edge']:
- return DefaultStatement(default_type, attrs)
- else:
- raise ValueError, "Unknown default statement: %r " % toks
+ # The pydot class instances should be marked as
+ # default statements to be inherited by actual
+ # graphs, nodes and edges.
+ # print "push_default_stmt", toks
+ default_type = toks[0][0]
+ if len(toks) > 1:
+ attrs = toks[1].attrs
+ else:
+ attrs = {}
+
+ if default_type in ['graph', 'node', 'edge']:
+ return DefaultStatement(default_type, attrs)
+ else:
+ raise ValueError, "Unknown default statement: %r " % toks
def push_attr_list(str, loc, toks):
- p = P_AttrList(toks)
- return p
+ p = P_AttrList(toks)
+ return p
def get_port(node):
- if len(node)>1:
- if isinstance(node[1], ParseResults):
- if len(node[1][0])==2:
- if node[1][0][0]==':':
- return node[1][0][1]
-
- return None
+ if len(node)>1:
+ if isinstance(node[1], ParseResults):
+ if len(node[1][0])==2:
+ if node[1][0][0]==':':
+ return node[1][0][1]
+
+ return None
def push_edge_stmt(str, loc, toks):
-
- tok_attrs = [a for a in toks if isinstance(a, P_AttrList)]
- attrs = {}
- for a in tok_attrs:
- attrs.update(a.attrs)
-
- n_prev = toks[0]
- e = []
- for n_next in tuple(toks)[2::2]:
- port = get_port(n_prev)
- if port is not None:
- n_prev_port = ':'+port
- else:
- n_prev_port = ''
-
- port = get_port(n_next)
- if port is not None:
- n_next_port = ':'+port
- else:
- n_next_port = ''
-
- e.append(pydot.Edge(n_prev[0]+n_prev_port, n_next[0]+n_next_port, **attrs))
- n_prev = n_next
- return e
+
+ tok_attrs = [a for a in toks if isinstance(a, P_AttrList)]
+ attrs = {}
+ for a in tok_attrs:
+ attrs.update(a.attrs)
+
+ n_prev = toks[0]
+ e = []
+ for n_next in tuple(toks)[2::2]:
+ port = get_port(n_prev)
+ if port is not None:
+ n_prev_port = ':'+port
+ else:
+ n_prev_port = ''
+
+ port = get_port(n_next)
+ if port is not None:
+ n_next_port = ':'+port
+ else:
+ n_next_port = ''
+
+ e.append(pydot.Edge(n_prev[0]+n_prev_port, n_next[0]+n_next_port, **attrs))
+ n_prev = n_next
+ return e
def push_node_stmt(str, loc, toks):
- if len(toks) == 2:
- attrs = toks[1].attrs
- else:
- attrs = {}
-
- node_name = toks[0]
- if isinstance(node_name, list) or isinstance(node_name, tuple):
- if len(node_name)>0:
- node_name = node_name[0]
-
- n = pydot.Node(node_name, **attrs)
- return n
+ if len(toks) == 2:
+ attrs = toks[1].attrs
+ else:
+ attrs = {}
+
+ node_name = toks[0]
+ if isinstance(node_name, list) or isinstance(node_name, tuple):
+ if len(node_name)>0:
+ node_name = node_name[0]
+
+ n = pydot.Node(node_name, **attrs)
+ return n
def strip_quotes( s, l, t ):
- return [ t[0].strip('"') ]
+ return [ t[0].strip('"') ]
graphparser = None
def GRAPH_DEF():
- global graphparser
-
- if not graphparser:
- # punctuation
- colon = Literal(":")
- lbrace = Literal("{")
- rbrace = Literal("}")
- lbrack = Literal("[")
- rbrack = Literal("]")
- lparen = Literal("(")
- rparen = Literal(")")
- equals = Literal("=")
- comma = Literal(",")
- dot = Literal(".")
- slash = Literal("/")
- bslash = Literal("\\")
- star = Literal("*")
- semi = Literal(";")
- at = Literal("@")
- minus = Literal("-")
-
- # keywords
- strict_ = Literal("strict")
- graph_ = Literal("graph")
- digraph_ = Literal("digraph")
- subgraph_ = Literal("subgraph")
- node_ = Literal("node")
- edge_ = Literal("edge")
-
- identifier = Word(alphanums + "_" ).setName("identifier")
-
- double_quote = Literal('"')
- double_quoted_string = \
- Combine( double_quote + ZeroOrMore(CharsNotIn('"')) + double_quote )
-
- alphastring_ = OneOrMore(CharsNotIn(_noncomma))
-
- ID = (identifier | double_quoted_string.setParseAction(strip_quotes) |\
- alphastring_).setName("ID")
-
- html_text = Combine(Literal("<<") + OneOrMore(CharsNotIn(",]")))
-
- float_number = Combine(Optional(minus) + \
- OneOrMore(Word(nums + "."))).setName("float_number")
-
- righthand_id = (float_number | ID | html_text).setName("righthand_id")
-
- port_angle = (at + ID).setName("port_angle")
-
- port_location = (Group(colon + ID) | \
- Group(colon + lparen + ID + comma + ID + rparen)).setName("port_location")
-
- port = (Group(port_location + Optional(port_angle)) | \
- Group(port_angle + Optional(port_location))).setName("port")
-
- node_id = (ID + Optional(port))
- a_list = OneOrMore(ID + Optional(equals.suppress() + righthand_id) + \
- Optional(comma.suppress())).setName("a_list")
-
- attr_list = OneOrMore(lbrack.suppress() + Optional(a_list) + \
- rbrack.suppress()).setName("attr_list")
-
- attr_stmt = (Group(graph_ | node_ | edge_) + attr_list).setName("attr_stmt")
-
- edgeop = (Literal("--") | Literal("->")).setName("edgeop")
-
- stmt_list = Forward()
- graph_stmt = Group(lbrace.suppress() + Optional(stmt_list) + \
- rbrace.suppress()).setName("graph_stmt")
-
- subgraph = (Group(Optional(subgraph_ + Optional(ID)) + graph_stmt) | \
- Group(subgraph_ + ID)).setName("subgraph")
-
- edgeRHS = OneOrMore(edgeop + Group(node_id | subgraph))
-
- edge_stmt = Group(node_id | subgraph) + edgeRHS + Optional(attr_list)
-
- node_stmt = (node_id + Optional(attr_list) + semi.suppress()).setName("node_stmt")
-
- assignment = (ID + equals.suppress() + righthand_id).setName("assignment")
- stmt = (assignment | edge_stmt | attr_stmt | node_stmt | subgraph).setName("stmt")
- stmt_list << OneOrMore(stmt + Optional(semi.suppress()))
-
- graphparser = (Optional(strict_) + Group((graph_ | digraph_)) + \
- Optional(ID) + graph_stmt).setResultsName("graph")
-
- singleLineComment = "//" + restOfLine
- graphparser.ignore(singleLineComment)
- graphparser.ignore(cStyleComment)
-
- assignment.setParseAction(push_attr_list)
- a_list.setParseAction(push_attr_list)
- edge_stmt.setParseAction(push_edge_stmt)
- node_stmt.setParseAction(push_node_stmt)
- attr_stmt.setParseAction(push_default_stmt)
-
- subgraph.setParseAction(push_subgraph_stmt)
- graph_stmt.setParseAction(push_graph_stmt)
- graphparser.setParseAction(push_top_graph_stmt)
-
- return graphparser
+ global graphparser
+
+ if not graphparser:
+ # punctuation
+ colon = Literal(":")
+ lbrace = Literal("{")
+ rbrace = Literal("}")
+ lbrack = Literal("[")
+ rbrack = Literal("]")
+ lparen = Literal("(")
+ rparen = Literal(")")
+ equals = Literal("=")
+ comma = Literal(",")
+ dot = Literal(".")
+ slash = Literal("/")
+ bslash = Literal("\\")
+ star = Literal("*")
+ semi = Literal(";")
+ at = Literal("@")
+ minus = Literal("-")
+
+ # keywords
+ strict_ = Literal("strict")
+ graph_ = Literal("graph")
+ digraph_ = Literal("digraph")
+ subgraph_ = Literal("subgraph")
+ node_ = Literal("node")
+ edge_ = Literal("edge")
+
+ identifier = Word(alphanums + "_" ).setName("identifier")
+
+ double_quote = Literal('"')
+ double_quoted_string = \
+ Combine( double_quote + ZeroOrMore(CharsNotIn('"')) + double_quote )
+
+ alphastring_ = OneOrMore(CharsNotIn(_noncomma))
+
+ ID = (identifier | double_quoted_string.setParseAction(strip_quotes) |\
+ alphastring_).setName("ID")
+
+ html_text = Combine(Literal("<<") + OneOrMore(CharsNotIn(",]")))
+
+ float_number = Combine(Optional(minus) + \
+ OneOrMore(Word(nums + "."))).setName("float_number")
+
+ righthand_id = (float_number | ID | html_text).setName("righthand_id")
+
+ port_angle = (at + ID).setName("port_angle")
+
+ port_location = (Group(colon + ID) | \
+ Group(colon + lparen + ID + comma + ID + rparen)).setName("port_location")
+
+ port = (Group(port_location + Optional(port_angle)) | \
+ Group(port_angle + Optional(port_location))).setName("port")
+
+ node_id = (ID + Optional(port))
+ a_list = OneOrMore(ID + Optional(equals.suppress() + righthand_id) + \
+ Optional(comma.suppress())).setName("a_list")
+
+ attr_list = OneOrMore(lbrack.suppress() + Optional(a_list) + \
+ rbrack.suppress()).setName("attr_list")
+
+ attr_stmt = (Group(graph_ | node_ | edge_) + attr_list).setName("attr_stmt")
+
+ edgeop = (Literal("--") | Literal("->")).setName("edgeop")
+
+ stmt_list = Forward()
+ graph_stmt = Group(lbrace.suppress() + Optional(stmt_list) + \
+ rbrace.suppress()).setName("graph_stmt")
+
+ subgraph = (Group(Optional(subgraph_ + Optional(ID)) + graph_stmt) | \
+ Group(subgraph_ + ID)).setName("subgraph")
+
+ edgeRHS = OneOrMore(edgeop + Group(node_id | subgraph))
+
+ edge_stmt = Group(node_id | subgraph) + edgeRHS + Optional(attr_list)
+
+ node_stmt = (node_id + Optional(attr_list) + semi.suppress()).setName("node_stmt")
+
+ assignment = (ID + equals.suppress() + righthand_id).setName("assignment")
+ stmt = (assignment | edge_stmt | attr_stmt | node_stmt | subgraph).setName("stmt")
+ stmt_list << OneOrMore(stmt + Optional(semi.suppress()))
+
+ graphparser = (Optional(strict_) + Group((graph_ | digraph_)) + \
+ Optional(ID) + graph_stmt).setResultsName("graph")
+
+ singleLineComment = "//" + restOfLine
+ graphparser.ignore(singleLineComment)
+ graphparser.ignore(cStyleComment)
+
+ assignment.setParseAction(push_attr_list)
+ a_list.setParseAction(push_attr_list)
+ edge_stmt.setParseAction(push_edge_stmt)
+ node_stmt.setParseAction(push_node_stmt)
+ attr_stmt.setParseAction(push_default_stmt)
+
+ subgraph.setParseAction(push_subgraph_stmt)
+ graph_stmt.setParseAction(push_graph_stmt)
+ graphparser.setParseAction(push_top_graph_stmt)
+
+ return graphparser
def parse_dot_data(data):
- try:
- graphparser = GRAPH_DEF()
- if pyparsing_version >= '1.2':
- graphparser.parseWithTabs()
- tokens = graphparser.parseString(data)
- graph = tokens.graph
- return graph
- except ParseException, err:
- print err.line
- print " "*(err.column-1) + "^"
- print err
- return None
+ try:
+ graphparser = GRAPH_DEF()
+ if pyparsing_version >= '1.2':
+ graphparser.parseWithTabs()
+ tokens = graphparser.parseString(data)
+ graph = tokens.graph
+ return graph
+ except ParseException, err:
+ print err.line
+ print " "*(err.column-1) + "^"
+ print err
+ return None
diff --git a/bin/addons/base/ir/workflow/pydot/pydot.py b/bin/addons/base/ir/workflow/pydot/pydot.py
index 947099f3ca0..e793a0a593b 100755..100644
--- a/bin/addons/base/ir/workflow/pydot/pydot.py
+++ b/bin/addons/base/ir/workflow/pydot/pydot.py
@@ -6,12 +6,12 @@ and process graphs in Graphviz's dot language.
References:
-pydot Homepage: http://www.dkbza.org/pydot.html
-Graphviz: http://www.research.att.com/sw/tools/graphviz/
-DOT Language: http://www.research.att.com/~erg/graphviz/info/lang.html
+pydot Homepage: http://www.dkbza.org/pydot.html
+Graphviz: http://www.research.att.com/sw/tools/graphviz/
+DOT Language: http://www.research.att.com/~erg/graphviz/info/lang.html
Programmed and tested with Graphviz 1.12 and Python 2.3.3 on GNU/Linux
-by Ero Carrera (c) 2004 [ero@dkbza.org]
+by Ero Carrera (c) 2004 [ero@dkbza.org]
Distributed under MIT license [http://opensource.org/licenses/mit-license.html].
"""
@@ -27,1049 +27,1049 @@ import dot_parser
def graph_from_dot_data(data):
- """Load graph as defined by data in DOT format.
-
- The data is assumed to be in DOT format. It will
- be parsed and a Dot class will be returned,
- representing the graph.
- """
-
- graph = dot_parser.parse_dot_data(data)
- if graph is not None:
- dot = Dot()
- dot.__dict__.update(graph.__dict__)
- return dot
-
- return None
+ """Load graph as defined by data in DOT format.
+
+ The data is assumed to be in DOT format. It will
+ be parsed and a Dot class will be returned,
+ representing the graph.
+ """
+
+ graph = dot_parser.parse_dot_data(data)
+ if graph is not None:
+ dot = Dot()
+ dot.__dict__.update(graph.__dict__)
+ return dot
+
+ return None
def graph_from_dot_file(path):
- """Load graph as defined by a DOT file.
-
- The file is assumed to be in DOT format. It will
- be loaded, parsed and a Dot class will be returned,
- representing the graph.
- """
-
- fd = file(path, 'rb')
- data = fd.read()
- fd.close()
-
- return graph_from_dot_data(data)
+ """Load graph as defined by a DOT file.
+
+ The file is assumed to be in DOT format. It will
+ be loaded, parsed and a Dot class will be returned,
+ representing the graph.
+ """
+
+ fd = file(path, 'rb')
+ data = fd.read()
+ fd.close()
+
+ return graph_from_dot_data(data)
def graph_from_edges(edge_list, node_prefix='', directed=False):
- """Creates a basic graph out of an edge list.
-
- The edge list has to be a list of tuples representing
- the nodes connected by the edge.
- The values can be anything: bool, int, float, str.
-
- If the graph is undirected by default, it is only
- calculated from one of the symmetric halves of the matrix.
- """
- if directed:
- graph = Dot(graph_type='digraph')
- else:
- graph = Dot(graph_type='graph')
- for edge in edge_list:
- e = Edge(node_prefix+str(edge[0]), node_prefix+str(edge[1]))
- graph.add_edge(e)
- return graph
+ """Creates a basic graph out of an edge list.
+
+ The edge list has to be a list of tuples representing
+ the nodes connected by the edge.
+ The values can be anything: bool, int, float, str.
+
+ If the graph is undirected by default, it is only
+ calculated from one of the symmetric halves of the matrix.
+ """
+ if directed:
+ graph = Dot(graph_type='digraph')
+ else:
+ graph = Dot(graph_type='graph')
+ for edge in edge_list:
+ e = Edge(node_prefix+str(edge[0]), node_prefix+str(edge[1]))
+ graph.add_edge(e)
+ return graph
def graph_from_adjacency_matrix(matrix, node_prefix='', directed=False):
- """Creates a basic graph out of an adjacency matrix.
-
- The matrix has to be a list of rows of values
- representing an adjacency matrix.
- The values can be anything: bool, int, float, as long
- as they can evaluate to True or False.
- """
- node_orig = 1
- if directed:
- graph = Dot(graph_type='digraph')
- else:
- graph = Dot(graph_type='graph')
- for row in matrix:
- if not directed:
- skip = matrix.index(row)
- r = row[skip:]
- else:
- skip = 0
- r = row
- node_dest = skip+1
- for e in r:
- if e:
- graph.add_edge( \
- Edge( node_prefix+str(node_orig), \
- node_prefix+str(node_dest)))
- node_dest += 1
- node_orig += 1
- return graph
+ """Creates a basic graph out of an adjacency matrix.
+
+ The matrix has to be a list of rows of values
+ representing an adjacency matrix.
+ The values can be anything: bool, int, float, as long
+ as they can evaluate to True or False.
+ """
+ node_orig = 1
+ if directed:
+ graph = Dot(graph_type='digraph')
+ else:
+ graph = Dot(graph_type='graph')
+ for row in matrix:
+ if not directed:
+ skip = matrix.index(row)
+ r = row[skip:]
+ else:
+ skip = 0
+ r = row
+ node_dest = skip+1
+ for e in r:
+ if e:
+ graph.add_edge( \
+ Edge( node_prefix+str(node_orig), \
+ node_prefix+str(node_dest)))
+ node_dest += 1
+ node_orig += 1
+ return graph
def graph_from_incidence_matrix(matrix, node_prefix='', directed=False):
- """Creates a basic graph out of an incidence matrix.
-
- The matrix has to be a list of rows of values
- representing an incidence matrix.
- The values can be anything: bool, int, float, as long
- as they can evaluate to True or False.
- """
- node_orig = 1
- if directed:
- graph = Dot(graph_type='digraph')
- else:
- graph = Dot(graph_type='graph')
- for row in matrix:
- nodes = []
- c = 1
- for node in row:
- if node:
- nodes.append(c*node)
- c += 1
- nodes.sort()
- if len(nodes) == 2:
- graph.add_edge( \
- Edge(node_prefix+str(abs(nodes[0])), \
- node_prefix+str(nodes[1]) ))
- if not directed:
- graph.set_simplify(True)
- return graph
-
-
+ """Creates a basic graph out of an incidence matrix.
+
+ The matrix has to be a list of rows of values
+ representing an incidence matrix.
+ The values can be anything: bool, int, float, as long
+ as they can evaluate to True or False.
+ """
+ node_orig = 1
+ if directed:
+ graph = Dot(graph_type='digraph')
+ else:
+ graph = Dot(graph_type='graph')
+ for row in matrix:
+ nodes = []
+ c = 1
+ for node in row:
+ if node:
+ nodes.append(c*node)
+ c += 1
+ nodes.sort()
+ if len(nodes) == 2:
+ graph.add_edge( \
+ Edge(node_prefix+str(abs(nodes[0])), \
+ node_prefix+str(nodes[1]) ))
+ if not directed:
+ graph.set_simplify(True)
+ return graph
+
+
def find_graphviz():
- """Locate Graphviz's executables in the system.
-
- Attempts to locate graphviz's executables in a Unix system.
- It will look for 'dot', 'twopi' and 'neato' in all the directories
- specified in the PATH environment variable.
- It will return a dictionary containing the program names as keys
- and their paths as values.
- """
- progs = {'dot': '', 'twopi': '', 'neato': '', 'circo': '', 'fdp': ''}
- if not os.environ.has_key('PATH'):
- return None
- for path in os.environ['PATH'].split(os.pathsep):
- for prg in progs.keys():
- if os.path.exists(path+os.path.sep+prg):
- progs[prg] = path+os.path.sep+prg
- elif os.path.exists(path+os.path.sep+prg + '.exe'):
- progs[prg] = path+os.path.sep+prg + '.exe'
- return progs
+ """Locate Graphviz's executables in the system.
+
+ Attempts to locate graphviz's executables in a Unix system.
+ It will look for 'dot', 'twopi' and 'neato' in all the directories
+ specified in the PATH environment variable.
+ It will return a dictionary containing the program names as keys
+ and their paths as values.
+ """
+ progs = {'dot': '', 'twopi': '', 'neato': '', 'circo': '', 'fdp': ''}
+ if not os.environ.has_key('PATH'):
+ return None
+ for path in os.environ['PATH'].split(os.pathsep):
+ for prg in progs.keys():
+ if os.path.exists(path+os.path.sep+prg):
+ progs[prg] = path+os.path.sep+prg
+ elif os.path.exists(path+os.path.sep+prg + '.exe'):
+ progs[prg] = path+os.path.sep+prg + '.exe'
+ return progs
class Common:
- """Common information to several classes.
-
- Should not be directly used, several classes are derived from
- this one.
- """
- chars_ID = None
- parent_graph = None
-
- def char_range(self, a,b):
- """Generate a list containing a range of characters.
-
- Returns a list of characters starting from 'a' up to 'b'
- both inclusive.
- """
- return map(chr, range(ord(a), ord(b)+1))
-
- def is_ID(self, s):
- """Checks whether a string is an dot language ID.
-
- It will check whether the string is solely composed
- by the characters allowed in an ID or not.
- """
- if not self.chars_ID:
- self.chars_ID = self.char_range('a','z')+self.char_range('A','Z')+ \
- self.char_range('0','9')+['_']
- for c in s:
- if c not in self.chars_ID:
- return False
- return True
+ """Common information to several classes.
+
+ Should not be directly used, several classes are derived from
+ this one.
+ """
+ chars_ID = None
+ parent_graph = None
+
+ def char_range(self, a,b):
+ """Generate a list containing a range of characters.
+
+ Returns a list of characters starting from 'a' up to 'b'
+ both inclusive.
+ """
+ return map(chr, range(ord(a), ord(b)+1))
+
+ def is_ID(self, s):
+ """Checks whether a string is an dot language ID.
+
+ It will check whether the string is solely composed
+ by the characters allowed in an ID or not.
+ """
+ if not self.chars_ID:
+ self.chars_ID = self.char_range('a','z')+self.char_range('A','Z')+ \
+ self.char_range('0','9')+['_']
+ for c in s:
+ if c not in self.chars_ID:
+ return False
+ return True
class Error(Exception):
- """General error handling class.
- """
- def __init__(self, value):
- self.value = value
- def __str__(self):
- return self.value
+ """General error handling class.
+ """
+ def __init__(self, value):
+ self.value = value
+ def __str__(self):
+ return self.value
class Node(object, Common):
- """A graph node.
-
- This class represents a graph's node with all its attributes.
-
- node(name, attribute=value, ...)
-
- name: node's name
-
- All the attributes defined in the Graphviz dot language should
- be supported.
- """
- attributes = ['showboxes', 'URL', 'fontcolor', 'fontsize', 'label', 'fontname', \
- 'comment', 'root', 'toplabel', 'vertices', 'width', 'z', 'bottomlabel', \
- 'distortion', 'fixedsize', 'group', 'height', 'orientation', 'pin', \
- 'rects', 'regular', 'shape', 'shapefile', 'sides', 'skew', 'pos', \
- 'layer', 'tooltip', 'style', 'target', 'color', 'peripheries',
- 'fillcolor']
-
- def __init__(self, name, **attrs):
-
- if isinstance(name, str) and not name.startswith('"'):
- idx = name.find(':')
- if idx>0:
- name = name[:idx]
-
- self.name = str(name)
- for attr in self.attributes:
- # Set all the attributes to None.
- self.__setattr__(attr, None)
- # Generate all the Setter methods.
- self.__setattr__('set_'+attr, lambda x, a=attr : self.__setattr__(a, x))
- # Generate all the Getter methods.
- self.__setattr__('get_'+attr, lambda a=attr : self.__getattribute__(a))
- for attr, val in attrs.items():
- self.__setattr__(attr, val)
-
- def set_name(self, node_name):
- """Set the node's name."""
-
- self.name = str(node_name)
-
- def get_name(self):
- """Get the node's name."""
-
- return self.name
-
- def set(self, name, value):
- """Set an attribute value by name.
-
- Given an attribute 'name' it will set its value to 'value'.
- There's always the possibility of using the methods:
- set_'name'(value)
- which are defined for all the existing attributes.
- """
- if name in self.attributes:
- self.__dict__[name] = value
- return True
- # Attribute is not known
- return False
-
- def to_string(self):
- """Returns a string representation of the node in dot language.
- """
-
- if not isinstance(self.name, str):
- self.name = str(self.name)
-
- # RMF: special case defaults for node, edge and graph properties.
- if self.name in ['node', 'edge', 'graph']:
- node = self.name
- else:
- node = '"'+self.name+'"'
-
- node_attr = None
- all_attrs = [a for a in self.attributes]
- all_attrs += [a for a in Graph.attributes if a not in all_attrs]
- all_attrs += [a for a in Edge.attributes if a not in all_attrs]
- for attr in all_attrs:
- if self.__dict__.has_key(attr) \
- and self.__getattribute__(attr) is not None:
- if not node_attr:
- node_attr = ''
- else:
- node_attr += ', '
- node_attr += attr+'='
- val = self.__dict__[attr]
-
- if val.startswith('<') and val.endswith('>'):
- node_attr += val
- elif (isinstance(val, str) or isinstance(val, unicode)) and not self.is_ID(val):
- node_attr += '"'+val+'"'
- else:
- node_attr += str(val)
-
- if node_attr:
- node += ' ['+node_attr+']'
- node += ';'
-
- return node
+ """A graph node.
+
+ This class represents a graph's node with all its attributes.
+
+ node(name, attribute=value, ...)
+
+ name: node's name
+
+ All the attributes defined in the Graphviz dot language should
+ be supported.
+ """
+ attributes = ['showboxes', 'URL', 'fontcolor', 'fontsize', 'label', 'fontname', \
+ 'comment', 'root', 'toplabel', 'vertices', 'width', 'z', 'bottomlabel', \
+ 'distortion', 'fixedsize', 'group', 'height', 'orientation', 'pin', \
+ 'rects', 'regular', 'shape', 'shapefile', 'sides', 'skew', 'pos', \
+ 'layer', 'tooltip', 'style', 'target', 'color', 'peripheries',
+ 'fillcolor']
+
+ def __init__(self, name, **attrs):
+
+ if isinstance(name, str) and not name.startswith('"'):
+ idx = name.find(':')
+ if idx>0:
+ name = name[:idx]
+
+ self.name = str(name)
+ for attr in self.attributes:
+ # Set all the attributes to None.
+ self.__setattr__(attr, None)
+ # Generate all the Setter methods.
+ self.__setattr__('set_'+attr, lambda x, a=attr : self.__setattr__(a, x))
+ # Generate all the Getter methods.
+ self.__setattr__('get_'+attr, lambda a=attr : self.__getattribute__(a))
+ for attr, val in attrs.items():
+ self.__setattr__(attr, val)
+
+ def set_name(self, node_name):
+ """Set the node's name."""
+
+ self.name = str(node_name)
+
+ def get_name(self):
+ """Get the node's name."""
+
+ return self.name
+
+ def set(self, name, value):
+ """Set an attribute value by name.
+
+ Given an attribute 'name' it will set its value to 'value'.
+ There's always the possibility of using the methods:
+ set_'name'(value)
+ which are defined for all the existing attributes.
+ """
+ if name in self.attributes:
+ self.__dict__[name] = value
+ return True
+ # Attribute is not known
+ return False
+
+ def to_string(self):
+ """Returns a string representation of the node in dot language.
+ """
+
+ if not isinstance(self.name, str):
+ self.name = str(self.name)
+
+ # RMF: special case defaults for node, edge and graph properties.
+ if self.name in ['node', 'edge', 'graph']:
+ node = self.name
+ else:
+ node = '"'+self.name+'"'
+
+ node_attr = None
+ all_attrs = [a for a in self.attributes]
+ all_attrs += [a for a in Graph.attributes if a not in all_attrs]
+ all_attrs += [a for a in Edge.attributes if a not in all_attrs]
+ for attr in all_attrs:
+ if self.__dict__.has_key(attr) \
+ and self.__getattribute__(attr) is not None:
+ if not node_attr:
+ node_attr = ''
+ else:
+ node_attr += ', '
+ node_attr += attr+'='
+ val = self.__dict__[attr]
+
+ if val.startswith('<') and val.endswith('>'):
+ node_attr += val
+ elif (isinstance(val, str) or isinstance(val, unicode)) and not self.is_ID(val):
+ node_attr += '"'+val+'"'
+ else:
+ node_attr += str(val)
+
+ if node_attr:
+ node += ' ['+node_attr+']'
+ node += ';'
+
+ return node
class Edge(object, Common):
- """A graph edge.
-
- This class represents a graph's edge with all its attributes.
-
- edge(src, dst, attribute=value, ...)
-
- src: source node's name
- dst: destination node's name
-
- All the attributes defined in the Graphviz dot language should
- be supported.
-
- Attributes can be set through the dynamically generated methods:
-
- set_[attribute name], i.e. set_label, set_fontname
-
- or using the instance's attributes:
-
- Edge.[attribute name], i.e. edge_instance.label, edge_instance.fontname
- """
- attributes = ['style', 'target', 'pos', 'layer', 'tooltip', 'color', 'showboxes',\
- 'URL', 'fontcolor', 'fontsize', 'label', 'fontname', 'comment', 'lp', \
- 'arrowhead', 'arrowsize', 'arrowtail', 'constraint', 'decorate', 'dir', \
- 'headURL', 'headclip', 'headhref', 'headlabel', 'headport', \
- 'headtarget', 'headtooltip', 'href', 'labelangle', 'labeldistance', \
- 'labelfloat', 'labelfontcolor', 'labelfontname', 'labelfontsize', 'len',\
- 'lhead', 'ltail', 'minlen', 'samehead', 'sametail', 'weight', 'tailURL',\
- 'tailclip', 'tailhref', 'taillabel', 'tailport', 'tailtarget', \
- 'tailtooltip']
-
- def __init__(self, src, dst, **attrs):
- self.src = src
- self.dst = dst
- for attr in self.attributes:
- # Set all the attributes to None.
- self.__setattr__(attr, None)
- # Generate all the Setter methods.
- self.__setattr__('set_'+attr, lambda x, a=attr : self.__setattr__(a, x))
- # Generate all the Getter methods.
- self.__setattr__('get_'+attr, lambda a=attr : self.__getattribute__(a))
- for attr, val in attrs.items():
- self.__setattr__(attr, val)
-
- def get_source(self):
- """Get the edges source node name."""
-
- return self.src
-
- def get_destination(self):
- """Get the edge's destination node name."""
-
- return self.dst
-
- def __eq__(self, edge):
- """Compare two edges.
-
- If the parent graph is directed, arcs linking
- node A to B are considered equal and A->B != B->A
-
- If the parent graph is undirected, any edge
- connecting two nodes is equal to any other
- edge connecting the same nodes, A->B == B->A
- """
-
- if not isinstance(edge, Edge):
- raise Error, 'Can\'t compare and edge to a non-edge object.'
- if self.parent_graph.graph_type=='graph':
- # If the graph is undirected, the edge has neither
- # source nor destination.
- if (self.src==edge.src and self.dst==edge.dst) or \
- (self.src==edge.dst and self.dst==edge.src):
- return True
- else:
- if self.src==edge.src and self.dst==edge.dst:
- return True
- return False
-
-
- def set(self, name, value):
- """Set an attribute value by name.
-
- Given an attribute 'name' it will set its value to 'value'.
- There's always the possibility of using the methods:
- set_'name'(value)
- which are defined for all the existing attributes.
- """
- if name in self.attributes:
- self.__dict__[name] = value
- return True
- # Attribute is not known
- return False
-
-
- def parse_node_ref(self, node_str):
-
- if not isinstance(node_str, str):
- node_str = str(node_str)
-
- if node_str[0]=='"' and node_str[-1]=='"' and node_str[0].count('"')%2!=0:
- return node_str
-
- node_port_idx = node_str.rfind(':')
-
- if node_port_idx>0 and node_str[0]=='"' and node_str[node_port_idx-1]=='"':
- return node_str
-
- node_str = node_str.replace('"', '')
-
- if node_port_idx>0:
- a = node_str[:node_port_idx]
- b = node_str[node_port_idx+1:]
- if self.is_ID(a):
- node = a
- else:
- node = '"'+a+'"'
- if self.is_ID(b):
- node += ':'+b
- else:
- node+=':"'+b+'"'
- return node
-
- return '"'+node_str+'"'
-
-
- def to_string(self):
- """Returns a string representation of the edge in dot language.
- """
-
- src = self.parse_node_ref(self.src)
- dst = self.parse_node_ref(self.dst)
-
- edge = src
- if self.parent_graph and \
- self.parent_graph.graph_type and \
- self.parent_graph.graph_type=='digraph':
- edge+=' -> '
- else:
- edge+=' -- '
- edge+=dst
-
- edge_attr = None
- for attr in self.attributes:
- if self.__dict__.has_key(attr) \
- and self.__getattribute__(attr) is not None:
- if not edge_attr:
- edge_attr = ''
- else:
- edge_attr+=', '
- edge_attr+=attr+'='
- val = self.__dict__[attr]
- if (isinstance(val, str) or isinstance(val, unicode)) and not self.is_ID(val):
- edge_attr+='"'+val+'"'
- else:
- edge_attr+=str(val)
-
- if edge_attr:
- edge+=' ['+edge_attr+']'
- edge+=';'
-
- return edge
-
+ """A graph edge.
+
+ This class represents a graph's edge with all its attributes.
+
+ edge(src, dst, attribute=value, ...)
+
+ src: source node's name
+ dst: destination node's name
+
+ All the attributes defined in the Graphviz dot language should
+ be supported.
+
+ Attributes can be set through the dynamically generated methods:
+
+ set_[attribute name], i.e. set_label, set_fontname
+
+ or using the instance's attributes:
+
+ Edge.[attribute name], i.e. edge_instance.label, edge_instance.fontname
+ """
+ attributes = ['style', 'target', 'pos', 'layer', 'tooltip', 'color', 'showboxes',\
+ 'URL', 'fontcolor', 'fontsize', 'label', 'fontname', 'comment', 'lp', \
+ 'arrowhead', 'arrowsize', 'arrowtail', 'constraint', 'decorate', 'dir', \
+ 'headURL', 'headclip', 'headhref', 'headlabel', 'headport', \
+ 'headtarget', 'headtooltip', 'href', 'labelangle', 'labeldistance', \
+ 'labelfloat', 'labelfontcolor', 'labelfontname', 'labelfontsize', 'len',\
+ 'lhead', 'ltail', 'minlen', 'samehead', 'sametail', 'weight', 'tailURL',\
+ 'tailclip', 'tailhref', 'taillabel', 'tailport', 'tailtarget', \
+ 'tailtooltip']
+
+ def __init__(self, src, dst, **attrs):
+ self.src = src
+ self.dst = dst
+ for attr in self.attributes:
+ # Set all the attributes to None.
+ self.__setattr__(attr, None)
+ # Generate all the Setter methods.
+ self.__setattr__('set_'+attr, lambda x, a=attr : self.__setattr__(a, x))
+ # Generate all the Getter methods.
+ self.__setattr__('get_'+attr, lambda a=attr : self.__getattribute__(a))
+ for attr, val in attrs.items():
+ self.__setattr__(attr, val)
+
+ def get_source(self):
+ """Get the edges source node name."""
+
+ return self.src
+
+ def get_destination(self):
+ """Get the edge's destination node name."""
+
+ return self.dst
+
+ def __eq__(self, edge):
+ """Compare two edges.
+
+ If the parent graph is directed, arcs linking
+ node A to B are considered equal and A->B != B->A
+
+ If the parent graph is undirected, any edge
+ connecting two nodes is equal to any other
+ edge connecting the same nodes, A->B == B->A
+ """
+
+ if not isinstance(edge, Edge):
+ raise Error, 'Can\'t compare and edge to a non-edge object.'
+ if self.parent_graph.graph_type=='graph':
+ # If the graph is undirected, the edge has neither
+ # source nor destination.
+ if (self.src==edge.src and self.dst==edge.dst) or \
+ (self.src==edge.dst and self.dst==edge.src):
+ return True
+ else:
+ if self.src==edge.src and self.dst==edge.dst:
+ return True
+ return False
+
+
+ def set(self, name, value):
+ """Set an attribute value by name.
+
+ Given an attribute 'name' it will set its value to 'value'.
+ There's always the possibility of using the methods:
+ set_'name'(value)
+ which are defined for all the existing attributes.
+ """
+ if name in self.attributes:
+ self.__dict__[name] = value
+ return True
+ # Attribute is not known
+ return False
+
+
+ def parse_node_ref(self, node_str):
+
+ if not isinstance(node_str, str):
+ node_str = str(node_str)
+
+ if node_str[0]=='"' and node_str[-1]=='"' and node_str[0].count('"')%2!=0:
+ return node_str
+
+ node_port_idx = node_str.rfind(':')
+
+ if node_port_idx>0 and node_str[0]=='"' and node_str[node_port_idx-1]=='"':
+ return node_str
+
+ node_str = node_str.replace('"', '')
+
+ if node_port_idx>0:
+ a = node_str[:node_port_idx]
+ b = node_str[node_port_idx+1:]
+ if self.is_ID(a):
+ node = a
+ else:
+ node = '"'+a+'"'
+ if self.is_ID(b):
+ node += ':'+b
+ else:
+ node+=':"'+b+'"'
+ return node
+
+ return '"'+node_str+'"'
+
+
+ def to_string(self):
+ """Returns a string representation of the edge in dot language.
+ """
+
+ src = self.parse_node_ref(self.src)
+ dst = self.parse_node_ref(self.dst)
+
+ edge = src
+ if self.parent_graph and \
+ self.parent_graph.graph_type and \
+ self.parent_graph.graph_type=='digraph':
+ edge+=' -> '
+ else:
+ edge+=' -- '
+ edge+=dst
+
+ edge_attr = None
+ for attr in self.attributes:
+ if self.__dict__.has_key(attr) \
+ and self.__getattribute__(attr) is not None:
+ if not edge_attr:
+ edge_attr = ''
+ else:
+ edge_attr+=', '
+ edge_attr+=attr+'='
+ val = self.__dict__[attr]
+ if (isinstance(val, str) or isinstance(val, unicode)) and not self.is_ID(val):
+ edge_attr+='"'+val+'"'
+ else:
+ edge_attr+=str(val)
+
+ if edge_attr:
+ edge+=' ['+edge_attr+']'
+ edge+=';'
+
+ return edge
+
class Graph(object, Common):
- """Class representing a graph in Graphviz's dot language.
-
- This class implements the methods to work on a representation
- of a graph in Graphviz's dot language.
-
- graph(graph_name='G', type='digraph', strict=False, suppress_disconnected=False, attribute=value, ...)
-
- graph_name:
- the graph's name
- type:
- can be 'graph' or 'digraph'
- suppress_disconnected:
- defaults to False, which will remove from the
- graph any disconnected nodes.
- simplify:
- if True it will avoid displaying equal edges, i.e.
- only one edge between two nodes. removing the
- duplicated ones.
-
- All the attributes defined in the Graphviz dot language should
- be supported.
-
- Attributes can be set through the dynamically generated methods:
-
- set_[attribute name], i.e. set_size, set_fontname
-
- or using the instance's attributes:
-
- Graph.[attribute name], i.e. graph_instance.label, graph_instance.fontname
- """
-
- attributes = ['Damping', 'bb', 'center', 'clusterrank', 'compound', 'concentrate',\
- 'defaultdist', 'dim', 'fontpath', 'epsilon', 'layers', 'layersep', \
- 'margin', 'maxiter', 'mclimit', 'mindist', 'pack', 'packmode', 'model', \
- 'page', 'pagedir', 'nodesep', 'normalize', 'nslimit1', 'ordering', \
- 'orientation', 'outputorder', 'overlap', 'remincross', 'resolution', \
- 'rankdir', 'ranksep', 'ratio', 'rotate', 'samplepoints', 'searchsize', \
- 'sep', 'size', 'splines', 'start', 'stylesheet', 'truecolor', \
- 'viewport', 'voro_margin', 'quantum', 'bgcolor', 'labeljust', \
- 'labelloc', 'root', 'showboxes', 'URL', 'fontcolor', 'fontsize', \
- 'label' ,'fontname', 'comment', 'lp', 'target', 'color', 'style', \
- 'concentrators']
-
- def __init__(self, graph_name='G', graph_type='digraph', strict=False, \
- suppress_disconnected=False, simplify=False, **attrs):
-
- if graph_type not in ['graph', 'digraph']:
- raise Error, 'Invalid type. Accepted graph types are: graph, digraph, subgraph'
- self.graph_type = graph_type
- self.graph_name = graph_name
- self.strict = strict
- self.suppress_disconnected = suppress_disconnected
- self.simplify = simplify
- self.node_list = []
- self.edge_list = []
- self.edge_src_list = []
- self.edge_dst_list = []
- self.subgraph_list = []
- self.parent_graph = self
- for attr in self.attributes:
- # Set all the attributes to None.
- self.__setattr__(attr, None)
- # Generate all the Setter methods.
- self.__setattr__('set_'+attr, lambda x, a=attr : self.__setattr__(a, x))
- # Generate all the Getter methods.
- self.__setattr__('get_'+attr, lambda a=attr : self.__getattribute__(a))
- for attr, val in attrs.items():
- self.__setattr__(attr, val)
-
- def set_simplify(self, simplify):
- """Set whether to simplify or not.
-
- If True it will avoid displaying equal edges, i.e.
- only one edge between two nodes. removing the
- duplicated ones.
- """
-
- self.simplify = simplify
-
- def get_simplify(self):
- """Get whether to simplify or not.
-
- Refer to set_simplify for more information.
- """
-
- return self.simplify
-
-
- def set_type(self, graph_type):
- """Set the graph's type, 'graph' or 'digraph'."""
- self.graph_type = graph_type
-
- def get_type(self):
- """Get the graph's type, 'graph' or 'digraph'."""
- return self.graph_type
-
- def set_name(self, graph_name):
- """Set the graph's name."""
-
- self.graph_name = graph_name
-
- def get_name(self):
- """Get the graph's name."""
-
- return self.graph_name
-
- def set_strict(self, val):
- """Set graph to 'strict' mode.
-
- This option is only valid for top level graphs.
- """
-
- self.strict = val
-
- def get_strict(self, val):
- """Get graph's 'strict' mode (True, False).
-
- This option is only valid for top level graphs.
- """
-
- return self.strict
-
- def set_suppress_disconnected(self, val):
- """Suppress disconnected nodes in the output graph.
-
- This option will skip nodes in the graph with no incoming or outgoing
- edges. This option works also for subgraphs and has effect only in the
- current graph/subgraph.
- """
-
- self.suppress_disconnected = val
-
- def get_suppress_disconnected(self, val):
- """Get if suppress disconnected is set.
-
- Refer to set_suppress_disconnected for more information.
- """
-
- self.suppress_disconnected = val
-
- def set(self, name, value):
- """Set an attribute value by name.
-
- Given an attribute 'name' it will set its value to 'value'.
- There's always the possibility of using the methods:
-
- set_'name'(value)
-
- which are defined for all the existing attributes.
- """
- if name in self.attributes:
- self.__dict__[name] = value
- return True
- # Attribute is not known
- return False
-
- def get(self, name):
- """Get an attribute value by name.
-
- Given an attribute 'name' it will get its value.
- There's always the possibility of using the methods:
-
- get_'name'()
-
- which are defined for all the existing attributes.
- """
- return self.__dict__[name]
-
- def add_node(self, graph_node):
- """Adds a node object to the graph.
-
- It takes a node object as its only argument and returns
- None.
- """
-
- if not isinstance(graph_node, Node):
- raise Error, 'add_node received a non node class object'
-
- if self.get_node(graph_node.get_name()) is None:
- self.node_list.append(graph_node)
- graph_node.parent_graph = self.parent_graph
-
- def get_node(self, name):
- """Retrieved a node from the graph.
-
- Given a node's name the corresponding Node
- instance will be returned.
-
- If multiple nodes exist with that name, a list of
- Node instances is returned.
- If only one node exists, the instance is returned.
- None is returned otherwise.
- """
-
- match = [node for node in self.node_list if node.get_name() == str(name)]
-
- l = len(match)
- if l==1:
- return match[0]
- elif l>1:
- return match
- else:
- return None
-
- def get_node_list(self):
- """Get the list of Node instances.
-
- This method returns the list of Node instances
- composing the graph.
- """
-
- return self.node_list
-
- def add_edge(self, graph_edge):
- """Adds an edge object to the graph.
-
- It takes a edge object as its only argument and returns
- None.
- """
-
- if not isinstance(graph_edge, Edge):
- raise Error, 'add_edge received a non edge class object'
-
- self.edge_list.append(graph_edge)
-
- src = self.get_node(graph_edge.get_source())
- if src is None:
- self.add_node(Node(graph_edge.get_source()))
-
- dst = self.get_node(graph_edge.get_destination())
- if dst is None:
- self.add_node(Node(graph_edge.get_destination()))
-
- graph_edge.parent_graph = self.parent_graph
-
- if graph_edge.src not in self.edge_src_list:
- self.edge_src_list.append(graph_edge.src)
-
- if graph_edge.dst not in self.edge_dst_list:
- self.edge_dst_list.append(graph_edge.dst)
-
- def get_edge(self, src, dst):
- """Retrieved an edge from the graph.
-
- Given an edge's source and destination the corresponding
- Edge instance will be returned.
-
- If multiple edges exist with that source and destination,
- a list of Edge instances is returned.
- If only one edge exists, the instance is returned.
- None is returned otherwise.
- """
-
- match = [edge for edge in self.edge_list if edge.src == src and edge.dst == dst]
-
- l = len(match)
- if l==1:
- return match[0]
- elif l>1:
- return match
- else:
- return None
-
- def get_edge_list(self):
- """Get the list of Edge instances.
-
- This method returns the list of Edge instances
- composing the graph.
- """
-
- return self.edge_list
-
- def add_subgraph(self, sgraph):
- """Adds an edge object to the graph.
-
- It takes a subgraph object as its only argument and returns
- None.
- """
- if not isinstance(sgraph, Subgraph) and not isinstance(sgraph, Cluster):
- raise Error, 'add_subgraph received a non subgraph class object'
-
- self.subgraph_list.append(sgraph)
-
- sgraph.set_graph_parent(self.parent_graph)
- return None
-
- def get_subgraph(self, name):
- """Retrieved a subgraph from the graph.
-
- Given a subgraph's name the corresponding
- Subgraph instance will be returned.
-
- If multiple subgraphs exist with the same name, a list of
- Subgraph instances is returned.
- If only one Subgraph exists, the instance is returned.
- None is returned otherwise.
- """
-
- match = [sgraph for sgraph in self.subgraph_list if sgraph.graph_name == name]
-
- l = len(match)
- if l==1:
- return match[0]
- elif l>1:
- return match
- else:
- return None
-
- def get_subgraph_list(self):
- """Get the list of Subgraph instances.
-
- This method returns the list of Subgraph instances
- in the graph.
- """
-
- return self.subgraph_list
-
- def set_graph_parent(self, parent):
- """Sets a graph and its elements to point the the parent.
-
- Any subgraph added to a parent graph receives a reference
- to the parent to access some common data.
- """
- self.parent_graph = parent
-
- for elm in self.edge_list:
- elm.parent_graph = parent
-
- for elm in self.node_list:
- elm.parent_graph = parent
-
- for elm in self.subgraph_list:
- elm.parent_graph = parent
- elm.set_graph_parent(parent)
-
- def to_string(self, indent=''):
- """Returns a string representation of the graph in dot language.
-
- It will return the graph and all its subelements in string from.
- """
- graph = indent+''
- if self.__dict__.has_key('strict'):
- if self==self.parent_graph and self.strict:
- graph+='strict '
-
- graph+=self.graph_type+' '+self.graph_name+' {\n'
-
- for attr in self.attributes:
- if self.__dict__.has_key(attr) \
- and self.__getattribute__(attr) is not None:
- graph += indent+'\t'+attr+'='
- val = self.__dict__[attr]
- if isinstance(val, str) and not self.is_ID(val):
- graph += '"'+val+'"'
- else:
- graph += str(val)
- graph+=';\n'
-
- # RMF: for graphviz to handle edge/node defaults correctly,
- # it seems they must appear before the rest of the nodes/edges
- # so if they exist, dump them out first.
- for elm in self.node_list:
- if elm.name in ['node', 'edge', 'graph']:
- graph += indent+'\t'+elm.to_string()+'\n'
-
- for elm in self.subgraph_list:
- graph += elm.to_string(indent+'\t')+'\n'
-
- for elm in self.node_list:
- # RMF: don't repeat the node/edge defaults
- if elm.name in ['node', 'edge', 'graph']:
- continue
- if self.suppress_disconnected:
- if elm.name not in self.edge_src_list+self.edge_dst_list:
- continue
- graph+=indent+'\t'+elm.to_string()+'\n'
-
- edges_done = []
- for elm in self.edge_list:
- if self.simplify and elm in edges_done:
- continue
- graph+=indent+'\t'+elm.to_string()+'\n'
- edges_done.append(elm)
-
- graph+=indent+'}\n'
-
- return graph
+ """Class representing a graph in Graphviz's dot language.
+
+ This class implements the methods to work on a representation
+ of a graph in Graphviz's dot language.
+
+ graph(graph_name='G', type='digraph', strict=False, suppress_disconnected=False, attribute=value, ...)
+
+ graph_name:
+ the graph's name
+ type:
+ can be 'graph' or 'digraph'
+ suppress_disconnected:
+ defaults to False, which will remove from the
+ graph any disconnected nodes.
+ simplify:
+ if True it will avoid displaying equal edges, i.e.
+ only one edge between two nodes. removing the
+ duplicated ones.
+
+ All the attributes defined in the Graphviz dot language should
+ be supported.
+
+ Attributes can be set through the dynamically generated methods:
+
+ set_[attribute name], i.e. set_size, set_fontname
+
+ or using the instance's attributes:
+
+ Graph.[attribute name], i.e. graph_instance.label, graph_instance.fontname
+ """
+
+ attributes = ['Damping', 'bb', 'center', 'clusterrank', 'compound', 'concentrate',\
+ 'defaultdist', 'dim', 'fontpath', 'epsilon', 'layers', 'layersep', \
+ 'margin', 'maxiter', 'mclimit', 'mindist', 'pack', 'packmode', 'model', \
+ 'page', 'pagedir', 'nodesep', 'normalize', 'nslimit1', 'ordering', \
+ 'orientation', 'outputorder', 'overlap', 'remincross', 'resolution', \
+ 'rankdir', 'ranksep', 'ratio', 'rotate', 'samplepoints', 'searchsize', \
+ 'sep', 'size', 'splines', 'start', 'stylesheet', 'truecolor', \
+ 'viewport', 'voro_margin', 'quantum', 'bgcolor', 'labeljust', \
+ 'labelloc', 'root', 'showboxes', 'URL', 'fontcolor', 'fontsize', \
+ 'label' ,'fontname', 'comment', 'lp', 'target', 'color', 'style', \
+ 'concentrators']
+
+ def __init__(self, graph_name='G', graph_type='digraph', strict=False, \
+ suppress_disconnected=False, simplify=False, **attrs):
+
+ if graph_type not in ['graph', 'digraph']:
+ raise Error, 'Invalid type. Accepted graph types are: graph, digraph, subgraph'
+ self.graph_type = graph_type
+ self.graph_name = graph_name
+ self.strict = strict
+ self.suppress_disconnected = suppress_disconnected
+ self.simplify = simplify
+ self.node_list = []
+ self.edge_list = []
+ self.edge_src_list = []
+ self.edge_dst_list = []
+ self.subgraph_list = []
+ self.parent_graph = self
+ for attr in self.attributes:
+ # Set all the attributes to None.
+ self.__setattr__(attr, None)
+ # Generate all the Setter methods.
+ self.__setattr__('set_'+attr, lambda x, a=attr : self.__setattr__(a, x))
+ # Generate all the Getter methods.
+ self.__setattr__('get_'+attr, lambda a=attr : self.__getattribute__(a))
+ for attr, val in attrs.items():
+ self.__setattr__(attr, val)
+
+ def set_simplify(self, simplify):
+ """Set whether to simplify or not.
+
+ If True it will avoid displaying equal edges, i.e.
+ only one edge between two nodes. removing the
+ duplicated ones.
+ """
+
+ self.simplify = simplify
+
+ def get_simplify(self):
+ """Get whether to simplify or not.
+
+ Refer to set_simplify for more information.
+ """
+
+ return self.simplify
+
+
+ def set_type(self, graph_type):
+ """Set the graph's type, 'graph' or 'digraph'."""
+ self.graph_type = graph_type
+
+ def get_type(self):
+ """Get the graph's type, 'graph' or 'digraph'."""
+ return self.graph_type
+
+ def set_name(self, graph_name):
+ """Set the graph's name."""
+
+ self.graph_name = graph_name
+
+ def get_name(self):
+ """Get the graph's name."""
+
+ return self.graph_name
+
+ def set_strict(self, val):
+ """Set graph to 'strict' mode.
+
+ This option is only valid for top level graphs.
+ """
+
+ self.strict = val
+
+ def get_strict(self, val):
+ """Get graph's 'strict' mode (True, False).
+
+ This option is only valid for top level graphs.
+ """
+
+ return self.strict
+
+ def set_suppress_disconnected(self, val):
+ """Suppress disconnected nodes in the output graph.
+
+ This option will skip nodes in the graph with no incoming or outgoing
+ edges. This option works also for subgraphs and has effect only in the
+ current graph/subgraph.
+ """
+
+ self.suppress_disconnected = val
+
+ def get_suppress_disconnected(self, val):
+ """Get if suppress disconnected is set.
+
+ Refer to set_suppress_disconnected for more information.
+ """
+
+ self.suppress_disconnected = val
+
+ def set(self, name, value):
+ """Set an attribute value by name.
+
+ Given an attribute 'name' it will set its value to 'value'.
+ There's always the possibility of using the methods:
+
+ set_'name'(value)
+
+ which are defined for all the existing attributes.
+ """
+ if name in self.attributes:
+ self.__dict__[name] = value
+ return True
+ # Attribute is not known
+ return False
+
+ def get(self, name):
+ """Get an attribute value by name.
+
+ Given an attribute 'name' it will get its value.
+ There's always the possibility of using the methods:
+
+ get_'name'()
+
+ which are defined for all the existing attributes.
+ """
+ return self.__dict__[name]
+
+ def add_node(self, graph_node):
+ """Adds a node object to the graph.
+
+ It takes a node object as its only argument and returns
+ None.
+ """
+
+ if not isinstance(graph_node, Node):
+ raise Error, 'add_node received a non node class object'
+
+ if self.get_node(graph_node.get_name()) is None:
+ self.node_list.append(graph_node)
+ graph_node.parent_graph = self.parent_graph
+
+ def get_node(self, name):
+ """Retrieved a node from the graph.
+
+ Given a node's name the corresponding Node
+ instance will be returned.
+
+ If multiple nodes exist with that name, a list of
+ Node instances is returned.
+ If only one node exists, the instance is returned.
+ None is returned otherwise.
+ """
+
+ match = [node for node in self.node_list if node.get_name() == str(name)]
+
+ l = len(match)
+ if l==1:
+ return match[0]
+ elif l>1:
+ return match
+ else:
+ return None
+
+ def get_node_list(self):
+ """Get the list of Node instances.
+
+ This method returns the list of Node instances
+ composing the graph.
+ """
+
+ return self.node_list
+
+ def add_edge(self, graph_edge):
+ """Adds an edge object to the graph.
+
+ It takes a edge object as its only argument and returns
+ None.
+ """
+
+ if not isinstance(graph_edge, Edge):
+ raise Error, 'add_edge received a non edge class object'
+
+ self.edge_list.append(graph_edge)
+
+ src = self.get_node(graph_edge.get_source())
+ if src is None:
+ self.add_node(Node(graph_edge.get_source()))
+
+ dst = self.get_node(graph_edge.get_destination())
+ if dst is None:
+ self.add_node(Node(graph_edge.get_destination()))
+
+ graph_edge.parent_graph = self.parent_graph
+
+ if graph_edge.src not in self.edge_src_list:
+ self.edge_src_list.append(graph_edge.src)
+
+ if graph_edge.dst not in self.edge_dst_list:
+ self.edge_dst_list.append(graph_edge.dst)
+
+ def get_edge(self, src, dst):
+ """Retrieved an edge from the graph.
+
+ Given an edge's source and destination the corresponding
+ Edge instance will be returned.
+
+ If multiple edges exist with that source and destination,
+ a list of Edge instances is returned.
+ If only one edge exists, the instance is returned.
+ None is returned otherwise.
+ """
+
+ match = [edge for edge in self.edge_list if edge.src == src and edge.dst == dst]
+
+ l = len(match)
+ if l==1:
+ return match[0]
+ elif l>1:
+ return match
+ else:
+ return None
+
+ def get_edge_list(self):
+ """Get the list of Edge instances.
+
+ This method returns the list of Edge instances
+ composing the graph.
+ """
+
+ return self.edge_list
+
+ def add_subgraph(self, sgraph):
+ """Adds an edge object to the graph.
+
+ It takes a subgraph object as its only argument and returns
+ None.
+ """
+ if not isinstance(sgraph, Subgraph) and not isinstance(sgraph, Cluster):
+ raise Error, 'add_subgraph received a non subgraph class object'
+
+ self.subgraph_list.append(sgraph)
+
+ sgraph.set_graph_parent(self.parent_graph)
+ return None
+
+ def get_subgraph(self, name):
+ """Retrieved a subgraph from the graph.
+
+ Given a subgraph's name the corresponding
+ Subgraph instance will be returned.
+
+ If multiple subgraphs exist with the same name, a list of
+ Subgraph instances is returned.
+ If only one Subgraph exists, the instance is returned.
+ None is returned otherwise.
+ """
+
+ match = [sgraph for sgraph in self.subgraph_list if sgraph.graph_name == name]
+
+ l = len(match)
+ if l==1:
+ return match[0]
+ elif l>1:
+ return match
+ else:
+ return None
+
+ def get_subgraph_list(self):
+ """Get the list of Subgraph instances.
+
+ This method returns the list of Subgraph instances
+ in the graph.
+ """
+
+ return self.subgraph_list
+
+ def set_graph_parent(self, parent):
+ """Sets a graph and its elements to point the the parent.
+
+ Any subgraph added to a parent graph receives a reference
+ to the parent to access some common data.
+ """
+ self.parent_graph = parent
+
+ for elm in self.edge_list:
+ elm.parent_graph = parent
+
+ for elm in self.node_list:
+ elm.parent_graph = parent
+
+ for elm in self.subgraph_list:
+ elm.parent_graph = parent
+ elm.set_graph_parent(parent)
+
+ def to_string(self, indent=''):
+ """Returns a string representation of the graph in dot language.
+
+ It will return the graph and all its subelements in string from.
+ """
+ graph = indent+''
+ if self.__dict__.has_key('strict'):
+ if self==self.parent_graph and self.strict:
+ graph+='strict '
+
+ graph+=self.graph_type+' '+self.graph_name+' {\n'
+
+ for attr in self.attributes:
+ if self.__dict__.has_key(attr) \
+ and self.__getattribute__(attr) is not None:
+ graph += indent+'\t'+attr+'='
+ val = self.__dict__[attr]
+ if isinstance(val, str) and not self.is_ID(val):
+ graph += '"'+val+'"'
+ else:
+ graph += str(val)
+ graph+=';\n'
+
+ # RMF: for graphviz to handle edge/node defaults correctly,
+ # it seems they must appear before the rest of the nodes/edges
+ # so if they exist, dump them out first.
+ for elm in self.node_list:
+ if elm.name in ['node', 'edge', 'graph']:
+ graph += indent+'\t'+elm.to_string()+'\n'
+
+ for elm in self.subgraph_list:
+ graph += elm.to_string(indent+'\t')+'\n'
+
+ for elm in self.node_list:
+ # RMF: don't repeat the node/edge defaults
+ if elm.name in ['node', 'edge', 'graph']:
+ continue
+ if self.suppress_disconnected:
+ if elm.name not in self.edge_src_list+self.edge_dst_list:
+ continue
+ graph+=indent+'\t'+elm.to_string()+'\n'
+
+ edges_done = []
+ for elm in self.edge_list:
+ if self.simplify and elm in edges_done:
+ continue
+ graph+=indent+'\t'+elm.to_string()+'\n'
+ edges_done.append(elm)
+
+ graph+=indent+'}\n'
+
+ return graph
class Subgraph(Graph):
- """Class representing a subgraph in Graphviz's dot language.
-
- This class implements the methods to work on a representation
- of a subgraph in Graphviz's dot language.
-
- subgraph(graph_name='subG', suppress_disconnected=False, attribute=value, ...)
-
- graph_name:
- the subgraph's name
- suppress_disconnected:
- defaults to false, which will remove from the
- subgraph any disconnected nodes.
- All the attributes defined in the Graphviz dot language should
- be supported.
-
- Attributes can be set through the dynamically generated methods:
-
- set_[attribute name], i.e. set_size, set_fontname
-
- or using the instance's attributes:
-
- Subgraph.[attribute name], i.e.
- subgraph_instance.label, subgraph_instance.fontname
- """
-
- attributes = Graph.attributes+['rank']
-
- # RMF: subgraph should have all the attributes of graph so it can be passed
- # as a graph to all methods
- def __init__(self, graph_name='subG', suppress_disconnected=False, \
- simplify=False, **attrs):
-
- self.graph_type = 'subgraph'
- self.graph_name = graph_name
- self.suppress_disconnected = suppress_disconnected
- self.simplify = simplify
- self.node_list = []
- self.edge_list = []
- self.edge_src_list = []
- self.edge_dst_list = []
- self.subgraph_list = []
- for attr in self.attributes:
- # Set all the attributes to None.
- self.__setattr__(attr, None)
- # Generate all the Setter methods.
- self.__setattr__('set_'+attr, lambda x, a=attr : self.__setattr__(a, x))
- # Generate all the Getter methods.
- self.__setattr__('get_'+attr, lambda a=attr : self.__getattribute__(a))
- for attr, val in attrs.items():
- self.__setattr__(attr, val)
-
+ """Class representing a subgraph in Graphviz's dot language.
+
+ This class implements the methods to work on a representation
+ of a subgraph in Graphviz's dot language.
+
+ subgraph(graph_name='subG', suppress_disconnected=False, attribute=value, ...)
+
+ graph_name:
+ the subgraph's name
+ suppress_disconnected:
+ defaults to false, which will remove from the
+ subgraph any disconnected nodes.
+ All the attributes defined in the Graphviz dot language should
+ be supported.
+
+ Attributes can be set through the dynamically generated methods:
+
+ set_[attribute name], i.e. set_size, set_fontname
+
+ or using the instance's attributes:
+
+ Subgraph.[attribute name], i.e.
+ subgraph_instance.label, subgraph_instance.fontname
+ """
+
+ attributes = Graph.attributes+['rank']
+
+ # RMF: subgraph should have all the attributes of graph so it can be passed
+ # as a graph to all methods
+ def __init__(self, graph_name='subG', suppress_disconnected=False, \
+ simplify=False, **attrs):
+
+ self.graph_type = 'subgraph'
+ self.graph_name = graph_name
+ self.suppress_disconnected = suppress_disconnected
+ self.simplify = simplify
+ self.node_list = []
+ self.edge_list = []
+ self.edge_src_list = []
+ self.edge_dst_list = []
+ self.subgraph_list = []
+ for attr in self.attributes:
+ # Set all the attributes to None.
+ self.__setattr__(attr, None)
+ # Generate all the Setter methods.
+ self.__setattr__('set_'+attr, lambda x, a=attr : self.__setattr__(a, x))
+ # Generate all the Getter methods.
+ self.__setattr__('get_'+attr, lambda a=attr : self.__getattribute__(a))
+ for attr, val in attrs.items():
+ self.__setattr__(attr, val)
+
class Cluster(Graph):
- """Class representing a cluster in Graphviz's dot language.
-
- This class implements the methods to work on a representation
- of a cluster in Graphviz's dot language.
-
- cluster(graph_name='subG', suppress_disconnected=False, attribute=value, ...)
-
- graph_name:
- the cluster's name (the string 'cluster' will be always prepended)
- suppress_disconnected:
- defaults to false, which will remove from the
- cluster any disconnected nodes.
- All the attributes defined in the Graphviz dot language should
- be supported.
-
- Attributes can be set through the dynamically generated methods:
-
- set_[attribute name], i.e. set_color, set_fontname
-
- or using the instance's attributes:
-
- Cluster.[attribute name], i.e.
- cluster_instance.color, cluster_instance.fontname
- """
-
- attributes = ['pencolor', 'bgcolor', 'labeljust', 'labelloc', 'URL', 'fontcolor', \
- 'fontsize', 'label', 'fontname', 'lp', 'style', 'target', 'color', \
- 'peripheries', 'fillcolor']
-
- def __init__(self, graph_name='subG', suppress_disconnected=False, \
- simplify=False, **attrs):
-
- #if type not in ['subgraph']:
- # raise Error, 'Invalid type. Accepted graph types are: subgraph'
- self.graph_type = 'subgraph'
- self.graph_name = 'cluster_'+graph_name
- self.suppress_disconnected = suppress_disconnected
- self.simplify = simplify
- self.node_list = []
- self.edge_list = []
- self.edge_src_list = []
- self.edge_dst_list = []
- self.subgraph_list = []
- for attr in self.attributes:
- # Set all the attributes to None.
- self.__setattr__(attr, None)
- # Generate all the Setter methods.
- self.__setattr__('set_'+attr, lambda x, a=attr : self.__setattr__(a, x))
- # Generate all the Getter methods.
- self.__setattr__('get_'+attr, lambda a=attr : self.__getattribute__(a))
- for attr, val in attrs.items():
- self.__setattr__(attr, val)
+ """Class representing a cluster in Graphviz's dot language.
+
+ This class implements the methods to work on a representation
+ of a cluster in Graphviz's dot language.
+
+ cluster(graph_name='subG', suppress_disconnected=False, attribute=value, ...)
+
+ graph_name:
+ the cluster's name (the string 'cluster' will be always prepended)
+ suppress_disconnected:
+ defaults to false, which will remove from the
+ cluster any disconnected nodes.
+ All the attributes defined in the Graphviz dot language should
+ be supported.
+
+ Attributes can be set through the dynamically generated methods:
+
+ set_[attribute name], i.e. set_color, set_fontname
+
+ or using the instance's attributes:
+
+ Cluster.[attribute name], i.e.
+ cluster_instance.color, cluster_instance.fontname
+ """
+
+ attributes = ['pencolor', 'bgcolor', 'labeljust', 'labelloc', 'URL', 'fontcolor', \
+ 'fontsize', 'label', 'fontname', 'lp', 'style', 'target', 'color', \
+ 'peripheries', 'fillcolor']
+
+ def __init__(self, graph_name='subG', suppress_disconnected=False, \
+ simplify=False, **attrs):
+
+ #if type not in ['subgraph']:
+ # raise Error, 'Invalid type. Accepted graph types are: subgraph'
+ self.graph_type = 'subgraph'
+ self.graph_name = 'cluster_'+graph_name
+ self.suppress_disconnected = suppress_disconnected
+ self.simplify = simplify
+ self.node_list = []
+ self.edge_list = []
+ self.edge_src_list = []
+ self.edge_dst_list = []
+ self.subgraph_list = []
+ for attr in self.attributes:
+ # Set all the attributes to None.
+ self.__setattr__(attr, None)
+ # Generate all the Setter methods.
+ self.__setattr__('set_'+attr, lambda x, a=attr : self.__setattr__(a, x))
+ # Generate all the Getter methods.
+ self.__setattr__('get_'+attr, lambda a=attr : self.__getattribute__(a))
+ for attr, val in attrs.items():
+ self.__setattr__(attr, val)
class Dot(Graph):
- """A container for handling a dot language file.
-
- This class implements methods to write and process
- a dot language file. It is a derived class of
- the base class 'Graph'.
- """
-
- progs = None
-
- formats = ['ps', 'ps2', 'hpgl', 'pcl', 'mif', 'pic', 'gd', 'gd2', 'gif', 'jpg', \
- 'jpeg', 'png', 'wbmp', 'ismap', 'imap', 'cmap', 'vrml', 'vtx', 'mp', \
- 'fig', 'svg', 'svgz', 'dia', 'dot', 'canon', 'plain', 'plain-ext', 'xdot']
-
- def __init__(self, prog='dot', **args):
- Graph.__init__(self, **args)
-
- self.prog = prog
-
- # Automatically creates all the methods enabling the creation
- # of output in any of the supported formats.
- for frmt in self.formats:
- self.__setattr__('create_'+frmt, lambda f=frmt, prog=self.prog : self.create(format=f, prog=prog))
- f = self.__dict__['create_'+frmt]
- f.__doc__ = '''Refer to docstring from 'create' for more information.'''
-
- for frmt in self.formats+['raw']:
- self.__setattr__('write_'+frmt, lambda path, f=frmt, prog=self.prog : self.write(path, format=f, prog=prog))
- f = self.__dict__['write_'+frmt]
- f.__doc__ = '''Refer to docstring from 'write' for more information.'''
-
- def set_prog(self, prog):
- """Sets the default program.
-
- Sets the default program in charge of processing
- the dot file into a graph.
- """
- self.prog = prog
-
- def write(self, path, prog=None, format='raw'):
- """Writes a graph to a file.
-
- Given a filename 'path' it will open/create and truncate
- such file and write on it a representation of the graph
- defined by the dot object and in the format specified by
- 'format'.
- The format 'raw' is used to dump the string representation
- of the Dot object, without further processing.
- The output can be processed by any of graphviz tools, defined
- in 'prog', which defaults to 'dot'
- Returns True or False according to the success of the write
- operation.
-
- There's also the preferred possibility of using:
-
- write_'format'(path, prog='program')
-
- which are automatically defined for all the supported formats.
- [write_ps(), write_gif(), write_dia(), ...]
- """
-
- if prog is None:
- prog = self.prog
-
- dot_fd = file(path, "w+b")
- if format == 'raw':
- dot_fd.write(self.to_string())
- else:
- dot_fd.write(self.create(prog, format))
- dot_fd.close()
-
- return True
-
- def create(self, prog=None, format='ps'):
- """Creates and returns a Postscript representation of the graph.
-
- create will write the graph to a temporary dot file and process
- it with the program given by 'prog' (which defaults to 'twopi'),
- reading the Postscript output and returning it as a string is the
- operation is successful.
- On failure None is returned.
-
- There's also the preferred possibility of using:
-
- create_'format'(prog='program')
-
- which are automatically defined for all the supported formats.
- [create_ps(), create_gif(), create_dia(), ...]
- """
- if prog is None:
- prog = self.prog
-
- if self.progs is None:
- self.progs = find_graphviz()
- if self.progs is None:
- return None
- if not self.progs.has_key(prog):
- # Program not found ?!?!
- return None
-
- tmp_fd, tmp_name = tempfile.mkstemp()
- os.close(tmp_fd)
- self.write(tmp_name)
- stdin, stdout, stderr = os.popen3(self.progs[prog]+' -T'+format+' '+tmp_name, 'b')
- stdin.close()
- stderr.close()
- data = stdout.read()
- stdout.close()
- os.unlink(tmp_name)
- return data
+ """A container for handling a dot language file.
+
+ This class implements methods to write and process
+ a dot language file. It is a derived class of
+ the base class 'Graph'.
+ """
+
+ progs = None
+
+ formats = ['ps', 'ps2', 'hpgl', 'pcl', 'mif', 'pic', 'gd', 'gd2', 'gif', 'jpg', \
+ 'jpeg', 'png', 'wbmp', 'ismap', 'imap', 'cmap', 'vrml', 'vtx', 'mp', \
+ 'fig', 'svg', 'svgz', 'dia', 'dot', 'canon', 'plain', 'plain-ext', 'xdot']
+
+ def __init__(self, prog='dot', **args):
+ Graph.__init__(self, **args)
+
+ self.prog = prog
+
+ # Automatically creates all the methods enabling the creation
+ # of output in any of the supported formats.
+ for frmt in self.formats:
+ self.__setattr__('create_'+frmt, lambda f=frmt, prog=self.prog : self.create(format=f, prog=prog))
+ f = self.__dict__['create_'+frmt]
+ f.__doc__ = '''Refer to docstring from 'create' for more information.'''
+
+ for frmt in self.formats+['raw']:
+ self.__setattr__('write_'+frmt, lambda path, f=frmt, prog=self.prog : self.write(path, format=f, prog=prog))
+ f = self.__dict__['write_'+frmt]
+ f.__doc__ = '''Refer to docstring from 'write' for more information.'''
+
+ def set_prog(self, prog):
+ """Sets the default program.
+
+ Sets the default program in charge of processing
+ the dot file into a graph.
+ """
+ self.prog = prog
+
+ def write(self, path, prog=None, format='raw'):
+ """Writes a graph to a file.
+
+ Given a filename 'path' it will open/create and truncate
+ such file and write on it a representation of the graph
+ defined by the dot object and in the format specified by
+ 'format'.
+ The format 'raw' is used to dump the string representation
+ of the Dot object, without further processing.
+ The output can be processed by any of graphviz tools, defined
+ in 'prog', which defaults to 'dot'
+ Returns True or False according to the success of the write
+ operation.
+
+ There's also the preferred possibility of using:
+
+ write_'format'(path, prog='program')
+
+ which are automatically defined for all the supported formats.
+ [write_ps(), write_gif(), write_dia(), ...]
+ """
+
+ if prog is None:
+ prog = self.prog
+
+ dot_fd = file(path, "w+b")
+ if format == 'raw':
+ dot_fd.write(self.to_string())
+ else:
+ dot_fd.write(self.create(prog, format))
+ dot_fd.close()
+
+ return True
+
+ def create(self, prog=None, format='ps'):
+ """Creates and returns a Postscript representation of the graph.
+
+ create will write the graph to a temporary dot file and process
+ it with the program given by 'prog' (which defaults to 'twopi'),
+ reading the Postscript output and returning it as a string is the
+ operation is successful.
+ On failure None is returned.
+
+ There's also the preferred possibility of using:
+
+ create_'format'(prog='program')
+
+ which are automatically defined for all the supported formats.
+ [create_ps(), create_gif(), create_dia(), ...]
+ """
+ if prog is None:
+ prog = self.prog
+
+ if self.progs is None:
+ self.progs = find_graphviz()
+ if self.progs is None:
+ return None
+ if not self.progs.has_key(prog):
+ # Program not found ?!?!
+ return None
+
+ tmp_fd, tmp_name = tempfile.mkstemp()
+ os.close(tmp_fd)
+ self.write(tmp_name)
+ stdin, stdout, stderr = os.popen3(self.progs[prog]+' -T'+format+' '+tmp_name, 'b')
+ stdin.close()
+ stderr.close()
+ data = stdout.read()
+ stdout.close()
+ os.unlink(tmp_name)
+ return data
diff --git a/bin/addons/base/ir/workflow/pydot/setup.py b/bin/addons/base/ir/workflow/pydot/setup.py
index cd8956bebbd..5209f242d81 100755..100644
--- a/bin/addons/base/ir/workflow/pydot/setup.py
+++ b/bin/addons/base/ir/workflow/pydot/setup.py
@@ -3,21 +3,21 @@
from distutils.core import setup
import pydot
-setup( name = 'pydot',
- version = pydot.__version__,
- description = 'Python interface to Graphiz\'s Dot',
- author = 'Ero Carrera',
- author_email = 'ero@dkbza.org',
- url = 'http://dkbza.org/pydot.html',
- license = 'MIT',
- platforms = ["any"],
- classifiers = ['Development Status :: 5 - Production/Stable', \
- 'Intended Audience :: Science/Research', \
- 'License :: OSI Approved :: MIT License',\
- 'Natural Language :: English', \
- 'Operating System :: OS Independent', \
- 'Programming Language :: Python', \
- 'Topic :: Scientific/Engineering :: Visualization',\
- 'Topic :: Software Development :: Libraries :: Python Modules'],
- long_description = "\n".join(pydot.__doc__.split('\n')),
- py_modules = ['pydot', 'dot_parser'])
+setup( name = 'pydot',
+ version = pydot.__version__,
+ description = 'Python interface to Graphiz\'s Dot',
+ author = 'Ero Carrera',
+ author_email = 'ero@dkbza.org',
+ url = 'http://dkbza.org/pydot.html',
+ license = 'MIT',
+ platforms = ["any"],
+ classifiers = ['Development Status :: 5 - Production/Stable', \
+ 'Intended Audience :: Science/Research', \
+ 'License :: OSI Approved :: MIT License',\
+ 'Natural Language :: English', \
+ 'Operating System :: OS Independent', \
+ 'Programming Language :: Python', \
+ 'Topic :: Scientific/Engineering :: Visualization',\
+ 'Topic :: Software Development :: Libraries :: Python Modules'],
+ long_description = "\n".join(pydot.__doc__.split('\n')),
+ py_modules = ['pydot', 'dot_parser'])
diff --git a/bin/addons/base/ir/workflow/workflow.py b/bin/addons/base/ir/workflow/workflow.py
index 6aebf7262ec..24a8e315570 100644
--- a/bin/addons/base/ir/workflow/workflow.py
+++ b/bin/addons/base/ir/workflow/workflow.py
@@ -32,157 +32,157 @@ from tools import graph
import netsvc
class workflow(osv.osv):
- _name = "workflow"
- _table = "wkf"
- _log_access = False
- _columns = {
- 'name': fields.char('Name', size=64, required=True),
- 'osv': fields.char('Resource Model', size=64, required=True),
- 'on_create': fields.boolean('On Create'),
- 'activities': fields.one2many('workflow.activity', 'wkf_id', 'Activities'),
- }
- _defaults = {
- 'on_create': lambda *a: True
- }
+ _name = "workflow"
+ _table = "wkf"
+ _log_access = False
+ _columns = {
+ 'name': fields.char('Name', size=64, required=True),
+ 'osv': fields.char('Resource Model', size=64, required=True),
+ 'on_create': fields.boolean('On Create'),
+ 'activities': fields.one2many('workflow.activity', 'wkf_id', 'Activities'),
+ }
+ _defaults = {
+ 'on_create': lambda *a: True
+ }
- def write(self, cr, user, ids, vals, context=None):
- if not context:
- context={}
- wf_service = netsvc.LocalService("workflow")
- wf_service.clear_cache(cr, user)
- return super(workflow, self).write(cr, user, ids, vals, context=context)
+ def write(self, cr, user, ids, vals, context=None):
+ if not context:
+ context={}
+ wf_service = netsvc.LocalService("workflow")
+ wf_service.clear_cache(cr, user)
+ return super(workflow, self).write(cr, user, ids, vals, context=context)
- #
- # scale = [stepx, stepy, posx, posy ]
- #
+ #
+ # scale = [stepx, stepy, posx, posy ]
+ #
- def graph_get(self, cr, uid, id, scale, context={}):
+ def graph_get(self, cr, uid, id, scale, context={}):
- nodes= []
- transitions = []
- start = []
- tres = {}
- workflow = self.browse(cr, uid, id, context)
- for a in workflow.activities:
- nodes.append((a.id,a.name))
- if a.flow_start:
- start.append((a.id,a.name))
- for t in a.out_transitions:
- transitions.append( ((a.id,a.name), (t.act_to.id,t.act_to.name)) )
- tres[t.id] = (a.id,t.act_to.id)
- g = graph(nodes, transitions)
- g.process(start)
- g.scale(*scale)
- result = g.result_get()
- results = {}
+ nodes= []
+ transitions = []
+ start = []
+ tres = {}
+ workflow = self.browse(cr, uid, id, context)
+ for a in workflow.activities:
+ nodes.append((a.id,a.name))
+ if a.flow_start:
+ start.append((a.id,a.name))
+ for t in a.out_transitions:
+ transitions.append( ((a.id,a.name), (t.act_to.id,t.act_to.name)) )
+ tres[t.id] = (a.id,t.act_to.id)
+ g = graph(nodes, transitions)
+ g.process(start)
+ g.scale(*scale)
+ result = g.result_get()
+ results = {}
- for r in result.items():
- r[1]['name'] = r[0][1]
- results[str(r[0][0])] = r[1]
- return {'node': results, 'transition': tres}
+ for r in result.items():
+ r[1]['name'] = r[0][1]
+ results[str(r[0][0])] = r[1]
+ return {'node': results, 'transition': tres}
- def create(self, cr, user, vals, context=None):
- if not context:
- context={}
- wf_service = netsvc.LocalService("workflow")
- wf_service.clear_cache(cr, user)
- return super(workflow, self).create(cr, user, vals, context=context)
+ def create(self, cr, user, vals, context=None):
+ if not context:
+ context={}
+ wf_service = netsvc.LocalService("workflow")
+ wf_service.clear_cache(cr, user)
+ return super(workflow, self).create(cr, user, vals, context=context)
workflow()
class wkf_activity(osv.osv):
- _name = "workflow.activity"
- _table = "wkf_activity"
- _log_access = False
- _columns = {
- 'name': fields.char('Name', size=64, required=True),
- 'wkf_id': fields.many2one('workflow', 'Workflow', required=True, select=True, ondelete='cascade'),
- 'split_mode': fields.selection([('XOR', 'Xor'), ('OR','Or'), ('AND','And')], 'Split Mode', size=3, required=True),
- 'join_mode': fields.selection([('XOR', 'Xor'), ('AND', 'And')], 'Join Mode', size=3, required=True),
- 'kind': fields.selection([('dummy', 'Dummy'), ('function', 'Function'), ('subflow', 'Subflow'), ('stopall', 'Stop All')], 'Kind', size=64, required=True),
- 'action': fields.text('Python Action'),
- 'action_id': fields.many2one('ir.actions.server', 'Server Action', ondelete='set null'),
- 'flow_start': fields.boolean('Flow Start'),
- 'flow_stop': fields.boolean('Flow Stop'),
- 'subflow_id': fields.many2one('workflow', 'Subflow'),
- 'signal_send': fields.char('Signal (subflow.*)', size=32),
- 'out_transitions': fields.one2many('workflow.transition', 'act_from', 'Outgoing transitions'),
- 'in_transitions': fields.one2many('workflow.transition', 'act_to', 'Incoming transitions'),
- }
- _defaults = {
- 'kind': lambda *a: 'dummy',
- 'join_mode': lambda *a: 'XOR',
- 'split_mode': lambda *a: 'XOR',
- }
+ _name = "workflow.activity"
+ _table = "wkf_activity"
+ _log_access = False
+ _columns = {
+ 'name': fields.char('Name', size=64, required=True),
+ 'wkf_id': fields.many2one('workflow', 'Workflow', required=True, select=True, ondelete='cascade'),
+ 'split_mode': fields.selection([('XOR', 'Xor'), ('OR','Or'), ('AND','And')], 'Split Mode', size=3, required=True),
+ 'join_mode': fields.selection([('XOR', 'Xor'), ('AND', 'And')], 'Join Mode', size=3, required=True),
+ 'kind': fields.selection([('dummy', 'Dummy'), ('function', 'Function'), ('subflow', 'Subflow'), ('stopall', 'Stop All')], 'Kind', size=64, required=True),
+ 'action': fields.text('Python Action'),
+ 'action_id': fields.many2one('ir.actions.server', 'Server Action', ondelete='set null'),
+ 'flow_start': fields.boolean('Flow Start'),
+ 'flow_stop': fields.boolean('Flow Stop'),
+ 'subflow_id': fields.many2one('workflow', 'Subflow'),
+ 'signal_send': fields.char('Signal (subflow.*)', size=32),
+ 'out_transitions': fields.one2many('workflow.transition', 'act_from', 'Outgoing transitions'),
+ 'in_transitions': fields.one2many('workflow.transition', 'act_to', 'Incoming transitions'),
+ }
+ _defaults = {
+ 'kind': lambda *a: 'dummy',
+ 'join_mode': lambda *a: 'XOR',
+ 'split_mode': lambda *a: 'XOR',
+ }
wkf_activity()
class wkf_transition(osv.osv):
- _table = "wkf_transition"
- _name = "workflow.transition"
- _log_access = False
- _rec_name = 'signal' #TODO: pas top mais bon...
- _columns = {
- 'trigger_model': fields.char('Trigger Type', size=128),
- 'trigger_expr_id': fields.char('Trigger Expr ID', size=128),
- 'signal': fields.char('Signal (button Name)', size=64),
- 'role_id': fields.many2one('res.roles', 'Role Required'),
- 'condition': fields.char('Condition', required=True, size=128),
- 'act_from': fields.many2one('workflow.activity', 'Source Activity', required=True, select=True, ondelete='cascade'),
- 'act_to': fields.many2one('workflow.activity', 'Destination Activity', required=True, select=True, ondelete='cascade'),
- }
- _defaults = {
- 'condition': lambda *a: 'True',
- }
+ _table = "wkf_transition"
+ _name = "workflow.transition"
+ _log_access = False
+ _rec_name = 'signal' #TODO: pas top mais bon...
+ _columns = {
+ 'trigger_model': fields.char('Trigger Type', size=128),
+ 'trigger_expr_id': fields.char('Trigger Expr ID', size=128),
+ 'signal': fields.char('Signal (button Name)', size=64),
+ 'role_id': fields.many2one('res.roles', 'Role Required'),
+ 'condition': fields.char('Condition', required=True, size=128),
+ 'act_from': fields.many2one('workflow.activity', 'Source Activity', required=True, select=True, ondelete='cascade'),
+ 'act_to': fields.many2one('workflow.activity', 'Destination Activity', required=True, select=True, ondelete='cascade'),
+ }
+ _defaults = {
+ 'condition': lambda *a: 'True',
+ }
wkf_transition()
class wkf_instance(osv.osv):
- _table = "wkf_instance"
- _name = "workflow.instance"
- _rec_name = 'res_type'
- _log_access = False
- _columns = {
- 'wkf_id': fields.many2one('workflow', 'Workflow', ondelete='restrict'),
- 'uid': fields.integer('User ID'),
- 'res_id': fields.integer('Resource ID'),
- 'res_type': fields.char('Resource Model', size=64),
- 'state': fields.char('State', size=32),
- }
- def _auto_init(self, cr, context={}):
- super(wkf_instance, self)._auto_init(cr, context)
- cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'wkf_instance_res_id_res_type_state_index\'')
- if not cr.fetchone():
- cr.execute('CREATE INDEX wkf_instance_res_id_res_type_state_index ON wkf_instance (res_id, res_type, state)')
- cr.commit()
+ _table = "wkf_instance"
+ _name = "workflow.instance"
+ _rec_name = 'res_type'
+ _log_access = False
+ _columns = {
+ 'wkf_id': fields.many2one('workflow', 'Workflow', ondelete='restrict'),
+ 'uid': fields.integer('User ID'),
+ 'res_id': fields.integer('Resource ID'),
+ 'res_type': fields.char('Resource Model', size=64),
+ 'state': fields.char('State', size=32),
+ }
+ def _auto_init(self, cr, context={}):
+ super(wkf_instance, self)._auto_init(cr, context)
+ cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'wkf_instance_res_id_res_type_state_index\'')
+ if not cr.fetchone():
+ cr.execute('CREATE INDEX wkf_instance_res_id_res_type_state_index ON wkf_instance (res_id, res_type, state)')
+ cr.commit()
wkf_instance()
class wkf_workitem(osv.osv):
- _table = "wkf_workitem"
- _name = "workflow.workitem"
- _log_access = False
- _rec_name = 'state'
- _columns = {
- 'act_id': fields.many2one('workflow.activity', 'Activity', required=True, ondelete="cascade"),
- 'subflow_id': fields.many2one('workflow.instance', 'Subflow', ondelete="cascade"),
- 'inst_id': fields.many2one('workflow.instance', 'Instance', required=True, ondelete="cascade", select=1),
- 'state': fields.char('State', size=64),
- }
+ _table = "wkf_workitem"
+ _name = "workflow.workitem"
+ _log_access = False
+ _rec_name = 'state'
+ _columns = {
+ 'act_id': fields.many2one('workflow.activity', 'Activity', required=True, ondelete="cascade"),
+ 'subflow_id': fields.many2one('workflow.instance', 'Subflow', ondelete="cascade"),
+ 'inst_id': fields.many2one('workflow.instance', 'Instance', required=True, ondelete="cascade", select=1),
+ 'state': fields.char('State', size=64),
+ }
wkf_workitem()
class wkf_triggers(osv.osv):
- _table = "wkf_triggers"
- _name = "workflow.triggers"
- _log_access = False
- _columns = {
- 'res_id': fields.integer('Resource ID', size=128),
- 'model': fields.char('Model', size=128),
- 'instance_id': fields.many2one('workflow.instance', 'Destination Instance', ondelete="cascade"),
- 'workitem_id': fields.many2one('workflow.workitem', 'Workitem', required=True, ondelete="cascade"),
- }
- def _auto_init(self, cr, context={}):
- super(wkf_triggers, self)._auto_init(cr, context)
- cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'wkf_triggers_res_id_model_index\'')
- if not cr.fetchone():
- cr.execute('CREATE INDEX wkf_triggers_res_id_model_index ON wkf_triggers (res_id, model)')
- cr.commit()
+ _table = "wkf_triggers"
+ _name = "workflow.triggers"
+ _log_access = False
+ _columns = {
+ 'res_id': fields.integer('Resource ID', size=128),
+ 'model': fields.char('Model', size=128),
+ 'instance_id': fields.many2one('workflow.instance', 'Destination Instance', ondelete="cascade"),
+ 'workitem_id': fields.many2one('workflow.workitem', 'Workitem', required=True, ondelete="cascade"),
+ }
+ def _auto_init(self, cr, context={}):
+ super(wkf_triggers, self)._auto_init(cr, context)
+ cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'wkf_triggers_res_id_model_index\'')
+ if not cr.fetchone():
+ cr.execute('CREATE INDEX wkf_triggers_res_id_model_index ON wkf_triggers (res_id, model)')
+ cr.commit()
wkf_triggers()
diff --git a/bin/addons/base/module/module.py b/bin/addons/base/module/module.py
index 1ad9a844ea0..76ead57fdbd 100644
--- a/bin/addons/base/module/module.py
+++ b/bin/addons/base/module/module.py
@@ -44,609 +44,609 @@ ver_regexp = re.compile("^(\\d+)((\\.\\d+)*)([a-z]?)((_(pre|p|beta|alpha|rc)\\d*
suffix_regexp = re.compile("^(alpha|beta|rc|pre|p)(\\d*)$")
def vercmp(ver1, ver2):
- """
- Compare two versions
- Take from portage_versions.py
- @param ver1: version to compare with
- @type ver1: string (example "1.2-r3")
- @param ver2: version to compare again
- @type ver2: string (example "2.1-r1")
- @rtype: None or float
- @return:
- 1. position if ver1 is greater than ver2
- 2. negative if ver1 is less than ver2
- 3. 0 if ver1 equals ver2
- 4. None if ver1 or ver2 are invalid
- """
-
- match1 = ver_regexp.match(ver1)
- match2 = ver_regexp.match(ver2)
-
- if not match1 or not match1.groups():
- return None
- if not match2 or not match2.groups():
- return None
-
- list1 = [int(match1.group(1))]
- list2 = [int(match2.group(1))]
-
- if len(match1.group(2)) or len(match2.group(2)):
- vlist1 = match1.group(2)[1:].split(".")
- vlist2 = match2.group(2)[1:].split(".")
- for i in range(0, max(len(vlist1), len(vlist2))):
- # Implicit .0 is given -1, so 1.0.0 > 1.0
- # would be ambiguous if two versions that aren't literally equal
- # are given the same value (in sorting, for example).
- if len(vlist1) <= i or len(vlist1[i]) == 0:
- list1.append(-1)
- list2.append(int(vlist2[i]))
- elif len(vlist2) <= i or len(vlist2[i]) == 0:
- list1.append(int(vlist1[i]))
- list2.append(-1)
- # Let's make life easy and use integers unless we're forced to use floats
- elif (vlist1[i][0] != "0" and vlist2[i][0] != "0"):
- list1.append(int(vlist1[i]))
- list2.append(int(vlist2[i]))
- # now we have to use floats so 1.02 compares correctly against 1.1
- else:
- list1.append(float("0."+vlist1[i]))
- list2.append(float("0."+vlist2[i]))
- # and now the final letter
- if len(match1.group(4)):
- list1.append(ord(match1.group(4)))
- if len(match2.group(4)):
- list2.append(ord(match2.group(4)))
-
- for i in range(0, max(len(list1), len(list2))):
- if len(list1) <= i:
- return -1
- elif len(list2) <= i:
- return 1
- elif list1[i] != list2[i]:
- return list1[i] - list2[i]
-
- # main version is equal, so now compare the _suffix part
- list1 = match1.group(5).split("_")[1:]
- list2 = match2.group(5).split("_")[1:]
-
- for i in range(0, max(len(list1), len(list2))):
- # Implicit _p0 is given a value of -1, so that 1 < 1_p0
- if len(list1) <= i:
- s1 = ("p","-1")
- else:
- s1 = suffix_regexp.match(list1[i]).groups()
- if len(list2) <= i:
- s2 = ("p","-1")
- else:
- s2 = suffix_regexp.match(list2[i]).groups()
- if s1[0] != s2[0]:
- return suffix_value[s1[0]] - suffix_value[s2[0]]
- if s1[1] != s2[1]:
- # it's possible that the s(1|2)[1] == ''
- # in such a case, fudge it.
- try:
- r1 = int(s1[1])
- except ValueError:
- r1 = 0
- try:
- r2 = int(s2[1])
- except ValueError:
- r2 = 0
- if r1 - r2:
- return r1 - r2
-
- # the suffix part is equal to, so finally check the revision
- if match1.group(9):
- r1 = int(match1.group(9))
- else:
- r1 = 0
- if match2.group(9):
- r2 = int(match2.group(9))
- else:
- r2 = 0
- return r1 - r2
+ """
+ Compare two versions
+ Take from portage_versions.py
+ @param ver1: version to compare with
+ @type ver1: string (example "1.2-r3")
+ @param ver2: version to compare again
+ @type ver2: string (example "2.1-r1")
+ @rtype: None or float
+ @return:
+ 1. position if ver1 is greater than ver2
+ 2. negative if ver1 is less than ver2
+ 3. 0 if ver1 equals ver2
+ 4. None if ver1 or ver2 are invalid
+ """
+
+ match1 = ver_regexp.match(ver1)
+ match2 = ver_regexp.match(ver2)
+
+ if not match1 or not match1.groups():
+ return None
+ if not match2 or not match2.groups():
+ return None
+
+ list1 = [int(match1.group(1))]
+ list2 = [int(match2.group(1))]
+
+ if len(match1.group(2)) or len(match2.group(2)):
+ vlist1 = match1.group(2)[1:].split(".")
+ vlist2 = match2.group(2)[1:].split(".")
+ for i in range(0, max(len(vlist1), len(vlist2))):
+ # Implicit .0 is given -1, so 1.0.0 > 1.0
+ # would be ambiguous if two versions that aren't literally equal
+ # are given the same value (in sorting, for example).
+ if len(vlist1) <= i or len(vlist1[i]) == 0:
+ list1.append(-1)
+ list2.append(int(vlist2[i]))
+ elif len(vlist2) <= i or len(vlist2[i]) == 0:
+ list1.append(int(vlist1[i]))
+ list2.append(-1)
+ # Let's make life easy and use integers unless we're forced to use floats
+ elif (vlist1[i][0] != "0" and vlist2[i][0] != "0"):
+ list1.append(int(vlist1[i]))
+ list2.append(int(vlist2[i]))
+ # now we have to use floats so 1.02 compares correctly against 1.1
+ else:
+ list1.append(float("0."+vlist1[i]))
+ list2.append(float("0."+vlist2[i]))
+ # and now the final letter
+ if len(match1.group(4)):
+ list1.append(ord(match1.group(4)))
+ if len(match2.group(4)):
+ list2.append(ord(match2.group(4)))
+
+ for i in range(0, max(len(list1), len(list2))):
+ if len(list1) <= i:
+ return -1
+ elif len(list2) <= i:
+ return 1
+ elif list1[i] != list2[i]:
+ return list1[i] - list2[i]
+
+ # main version is equal, so now compare the _suffix part
+ list1 = match1.group(5).split("_")[1:]
+ list2 = match2.group(5).split("_")[1:]
+
+ for i in range(0, max(len(list1), len(list2))):
+ # Implicit _p0 is given a value of -1, so that 1 < 1_p0
+ if len(list1) <= i:
+ s1 = ("p","-1")
+ else:
+ s1 = suffix_regexp.match(list1[i]).groups()
+ if len(list2) <= i:
+ s2 = ("p","-1")
+ else:
+ s2 = suffix_regexp.match(list2[i]).groups()
+ if s1[0] != s2[0]:
+ return suffix_value[s1[0]] - suffix_value[s2[0]]
+ if s1[1] != s2[1]:
+ # it's possible that the s(1|2)[1] == ''
+ # in such a case, fudge it.
+ try:
+ r1 = int(s1[1])
+ except ValueError:
+ r1 = 0
+ try:
+ r2 = int(s2[1])
+ except ValueError:
+ r2 = 0
+ if r1 - r2:
+ return r1 - r2
+
+ # the suffix part is equal to, so finally check the revision
+ if match1.group(9):
+ r1 = int(match1.group(9))
+ else:
+ r1 = 0
+ if match2.group(9):
+ r2 = int(match2.group(9))
+ else:
+ r2 = 0
+ return r1 - r2
class module_repository(osv.osv):
- _name = "ir.module.repository"
- _description = "Module Repository"
- _columns = {
- 'name': fields.char('Name', size=128),
- 'url': fields.char('Url', size=256, required=True),
- 'sequence': fields.integer('Sequence', required=True),
- 'filter': fields.char('Filter', size=128, required=True,
- help='Regexp to search module on the repository webpage:\n'
- '- The first parenthesis must match the name of the module.\n'
- '- The second parenthesis must match all the version number.\n'
- '- The last parenthesis must match the extension of the module.'),
- 'active': fields.boolean('Active'),
- }
- _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)"',
- 'active': lambda *a: 1,
- }
- _order = "sequence"
+ _name = "ir.module.repository"
+ _description = "Module Repository"
+ _columns = {
+ 'name': fields.char('Name', size=128),
+ 'url': fields.char('Url', size=256, required=True),
+ 'sequence': fields.integer('Sequence', required=True),
+ 'filter': fields.char('Filter', size=128, required=True,
+ help='Regexp to search module on the repository webpage:\n'
+ '- The first parenthesis must match the name of the module.\n'
+ '- The second parenthesis must match all the version number.\n'
+ '- The last parenthesis must match the extension of the module.'),
+ 'active': fields.boolean('Active'),
+ }
+ _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)"',
+ 'active': lambda *a: 1,
+ }
+ _order = "sequence"
module_repository()
class module_category(osv.osv):
- _name = "ir.module.category"
- _description = "Module Category"
-
- def _module_nbr(self,cr,uid, ids, prop, unknow_none,context):
- 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,))
- 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
-
- _columns = {
- 'name': fields.char("Name", size=128, required=True),
- 'parent_id': fields.many2one('ir.module.category', 'Parent Category', select=True),
- 'child_ids': fields.one2many('ir.module.category', 'parent_id', 'Parent Category'),
- 'module_nr': fields.function(_module_nbr, method=True, string='# of Modules', type='integer')
- }
- _order = 'name'
+ _name = "ir.module.category"
+ _description = "Module Category"
+
+ def _module_nbr(self,cr,uid, ids, prop, unknow_none,context):
+ 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,))
+ 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
+
+ _columns = {
+ 'name': fields.char("Name", size=128, required=True),
+ 'parent_id': fields.many2one('ir.module.category', 'Parent Category', select=True),
+ 'child_ids': fields.one2many('ir.module.category', 'parent_id', 'Parent Category'),
+ 'module_nr': fields.function(_module_nbr, method=True, string='# of Modules', type='integer')
+ }
+ _order = 'name'
module_category()
class module(osv.osv):
- _name = "ir.module.module"
- _description = "Module"
-
- def get_module_info(self, name):
- try:
- f = tools.file_open(os.path.join(name, '__terp__.py'))
- data = f.read()
- info = eval(data)
- if 'version' in info:
- info['version'] = release.version.rsplit('.', 1)[0] + '.' + info['version']
- f.close()
- except:
- return {}
- return info
-
- def _get_installed_version(self, cr, uid, ids, field_name=None, arg=None, context={}):
- res = {}
- 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] = ''
- return res
-
- _columns = {
- 'name': fields.char("Name", size=128, readonly=True, required=True),
- 'category_id': fields.many2one('ir.module.category', 'Category', readonly=True),
- 'shortdesc': fields.char('Short description', size=256, readonly=True),
- 'description': fields.text("Description", readonly=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),
- '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),
- 'state': fields.selection([
- ('uninstallable','Not Installable'),
- ('uninstalled','Not Installed'),
- ('installed','Installed'),
- ('to upgrade','To be upgraded'),
- ('to remove','To be removed'),
- ('to install','To be installed')
- ], string='State', readonly=True),
- 'demo': fields.boolean('Demo data'),
- 'license': fields.selection([('GPL-2', 'GPL-2'),
- ('Other proprietary', 'Other proprietary')], string='License',
- readonly=True),
- }
-
- _defaults = {
- 'state': lambda *a: 'uninstalled',
- 'demo': lambda *a: False,
- 'license': lambda *a: 'GPL-2',
- }
- _order = 'name'
-
- _sql_constraints = [
- ('name_uniq', 'unique (name)', 'The name of the module must be unique !')
- ]
-
- def unlink(self, cr, uid, ids, context=None):
- if not ids:
- return True
- if isinstance(ids, (int, long)):
- ids = [ids]
- for mod in self.read(cr, uid, ids, ['state'], context):
- if mod['state'] in ('installed', 'to upgrade', 'to remove', 'to install'):
- raise orm.except_orm(_('Error'),
- _('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_change(self, cr, uid, ids, newstate, context={}, level=50):
- if level<1:
- raise Exception, _('Recursion error in modules dependencies !')
- demo = True
- for module in self.browse(cr, uid, ids):
- mdemo = True
- for dep in module.dependencies_id:
- ids2 = self.search(cr, uid, [('name','=',dep.name)])
- mdemo = self.state_change(cr, uid, ids2, newstate, context, level-1,)\
- and mdemo
- if not module.dependencies_id:
- mdemo = module.demo
- if module.state == 'uninstalled':
- self.write(cr, uid, [module.id], {'state': newstate, 'demo':mdemo})
- demo = demo and mdemo
- return demo
-
- def state_upgrade(self, cr, uid, ids, newstate, context=None, level=50):
- dep_obj = self.pool.get('ir.module.module.dependency')
- if level<1:
- raise Exception, _('Recursion error in modules dependencies !')
- for module in self.browse(cr, uid, ids):
- dep_ids = dep_obj.search(cr, uid, [('name', '=', module.name)])
- if dep_ids:
- ids2 = []
- for dep in dep_obj.browse(cr, uid, dep_ids):
- if dep.module_id.state != 'to upgrade':
- ids2.append(dep.module_id.id)
- self.state_upgrade(cr, uid, ids2, newstate, context, level)
- if module.state == 'installed':
- self.write(cr, uid, module.id, {'state': newstate})
- return True
-
- def button_install(self, cr, uid, ids, context={}):
- return self.state_change(cr, uid, ids, 'to install', context)
-
- def button_install_cancel(self, cr, uid, ids, context={}):
- self.write(cr, uid, ids, {'state': 'uninstalled', 'demo':False})
- return True
-
- def button_uninstall(self, cr, uid, ids, context={}):
- for module in self.browse(cr, uid, ids):
- cr.execute('''select m.state,m.name
- from
- ir_module_module_dependency d
- join
- ir_module_module m on (d.module_id=m.id)
- where
- d.name=%s and
- m.state not in ('uninstalled','uninstallable','to remove')''', (module.name,))
- res = cr.fetchall()
- if res:
- raise orm.except_orm(_('Error'), _('The module you are trying to remove depends on installed modules :\n %s') % '\n'.join(map(lambda x: '\t%s: %s' % (x[0], x[1]), res)))
- self.write(cr, uid, ids, {'state': 'to remove'})
- return True
-
- def button_uninstall_cancel(self, cr, uid, ids, context={}):
- self.write(cr, uid, ids, {'state': 'installed'})
- return True
- def button_upgrade(self, cr, uid, ids, context=None):
- return self.state_upgrade(cr, uid, ids, 'to upgrade', context)
- def button_upgrade_cancel(self, cr, uid, ids, context={}):
- self.write(cr, uid, ids, {'state': 'installed'})
- return True
- def button_update_translations(self, cr, uid, ids, context={}):
- cr.execute('select code from res_lang where translatable=TRUE')
- langs = [l[0] for l in cr.fetchall()]
- modules = self.read(cr, uid, ids, ['name'])
- for module in modules:
- files = self.get_module_info(module['name']).get('translations', {})
- for lang in langs:
- if files.has_key(lang):
- filepath = files[lang]
- # if filepath does not contain :// we prepend the path of the module
- if filepath.find('://') == -1:
- filepath = addons.get_module_resource(module['name'], filepath)
- tools.trans_load(filepath, lang)
- return True
-
- # update the list of available packages
- def update_list(self, cr, uid, context={}):
- robj = self.pool.get('ir.module.repository')
- res = [0, 0] # [update, add]
-
- # iterate through installed modules and mark them as being so
- for name in addons.get_modules():
- mod_name = name
- if name[-4:]=='.zip':
- mod_name=name[:-4]
- ids = self.search(cr, uid, [('name','=',mod_name)])
- if ids:
- id = ids[0]
- mod = self.browse(cr, uid, id)
- terp = self.get_module_info(mod_name)
- if terp.get('installable', True) and mod.state == 'uninstallable':
- self.write(cr, uid, id, {'state': 'uninstalled'})
- if vercmp(terp.get('version', ''), mod.latest_version or '0') > 0:
- self.write(cr, uid, id, {
- 'latest_version': terp.get('version'),
- 'url': ''})
- res[0] += 1
- self.write(cr, uid, id, {
- 'description': terp.get('description', ''),
- 'shortdesc': terp.get('name', ''),
- 'author': terp.get('author', 'Unknown'),
- 'website': terp.get('website', ''),
- 'license': terp.get('license', 'GPL-2'),
- })
- cr.execute('DELETE FROM ir_module_module_dependency\
- WHERE module_id = %d', (id,))
- self._update_dependencies(cr, uid, ids[0], terp.get('depends',
- []))
- self._update_category(cr, uid, ids[0], terp.get('category',
- 'Uncategorized'))
- continue
- terp_file = addons.get_module_resource(name, '__terp__.py')
- mod_path = addons.get_module_path(name)
- if os.path.isdir(mod_path) or os.path.islink(mod_path) or zipfile.is_zipfile(mod_path):
- terp = self.get_module_info(mod_name)
- if not terp or not terp.get('installable', True):
- continue
- if not os.path.isfile(mod_path+'.zip'):
- import imp
- # XXX must restrict to only addons paths
- imp.load_module(name, *imp.find_module(mod_name))
- else:
- import zipimport
- zimp = zipimport.zipimporter(mod_path+'.zip')
- zimp.load_module(mod_name)
- id = self.create(cr, uid, {
- 'name': mod_name,
- 'state': 'uninstalled',
- 'description': terp.get('description', ''),
- '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
- self._update_dependencies(cr, uid, id, terp.get('depends', []))
- self._update_category(cr, uid, id, terp.get('category', 'Uncategorized'))
-
- import socket
- socket.setdefaulttimeout(10)
- for repository in robj.browse(cr, uid, robj.search(cr, uid, [])):
- try:
- index_page = urllib.urlopen(repository.url).read()
- except IOError, e:
- if e.errno == 21:
- raise orm.except_orm(_('Error'),
- _("This url '%s' must provide an html file with links to zip modules") % (repository.url))
- else:
- raise
- modules = re.findall(repository.filter, index_page, re.I+re.M)
- mod_sort = {}
- for m in modules:
- name = m[0]
- version = m[1]
- extension = m[-1]
- if version == 'x': # 'x' version was a mistake
- version = '0'
- if name in mod_sort:
- if vercmp(version, mod_sort[name][0]) <= 0:
- continue
- mod_sort[name] = [version, extension]
- for name in mod_sort.keys():
- version, extension = mod_sort[name]
- url = repository.url+'/'+name+'-'+version+extension
- ids = self.search(cr, uid, [('name','=',name)])
- if not ids:
- self.create(cr, uid, {
- 'name': name,
- 'latest_version': version,
- 'published_version': version,
- 'url': url,
- 'state': 'uninstalled',
- })
- 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'
- c = vercmp(version, latest_version)
- if c > 0:
- self.write(cr, uid, id,
- {'latest_version': version, 'url': url})
- res[0] += 1
- published_version = self.read(cr, uid, id, ['published_version'])\
- ['published_version']
- if published_version == 'x' or not published_version:
- published_version = '0'
- c = vercmp(version, published_version)
- if c > 0:
- self.write(cr, uid, id,
- {'published_version': version})
- return res
-
- def download(self, cr, uid, ids, download=True, context=None):
- res = []
- for mod in self.browse(cr, uid, ids, context=context):
- if not mod.url:
- continue
- match = re.search('-([a-zA-Z0-9\._-]+)(\.zip)', mod.url, re.I)
- version = '0'
- if match:
- version = match.group(1)
- if vercmp(mod.installed_version or '0', version) >= 0:
- continue
- res.append(mod.url)
- if not download:
- continue
- zipfile = urllib.urlopen(mod.url).read()
- fname = addons.get_module_path(mod.name+'.zip')
- try:
- fp = file(fname, 'wb')
- fp.write(zipfile)
- fp.close()
- except IOError, e:
- raise orm.except_orm(_('Error'), _('Can not create the module file:\n %s') % (fname,))
- terp = self.get_module_info(mod.name)
- self.write(cr, uid, mod.id, {
- 'description': terp.get('description', ''),
- 'shortdesc': terp.get('name', ''),
- 'author': terp.get('author', 'Unknown'),
- 'website': terp.get('website', ''),
- 'license': terp.get('license', 'GPL-2'),
- })
- cr.execute('DELETE FROM ir_module_module_dependency ' \
- 'WHERE module_id = %d', (mod.id,))
- self._update_dependencies(cr, uid, mod.id, terp.get('depends',
- []))
- self._update_category(cr, uid, mod.id, terp.get('category',
- 'Uncategorized'))
- # Import module
- zimp = zipimport.zipimporter(fname)
- zimp.load_module(mod.name)
- return res
-
- 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))
-
- 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))
- 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))
- else:
- c_id = c_id[0]
- p_id = c_id
- categs = categs[1:]
- self.write(cr, uid, [id], {'category_id': p_id})
+ _name = "ir.module.module"
+ _description = "Module"
+
+ def get_module_info(self, name):
+ try:
+ f = tools.file_open(os.path.join(name, '__terp__.py'))
+ data = f.read()
+ info = eval(data)
+ if 'version' in info:
+ info['version'] = release.version.rsplit('.', 1)[0] + '.' + info['version']
+ f.close()
+ except:
+ return {}
+ return info
+
+ def _get_installed_version(self, cr, uid, ids, field_name=None, arg=None, context={}):
+ res = {}
+ 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] = ''
+ return res
+
+ _columns = {
+ 'name': fields.char("Name", size=128, readonly=True, required=True),
+ 'category_id': fields.many2one('ir.module.category', 'Category', readonly=True),
+ 'shortdesc': fields.char('Short description', size=256, readonly=True),
+ 'description': fields.text("Description", readonly=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),
+ '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),
+ 'state': fields.selection([
+ ('uninstallable','Not Installable'),
+ ('uninstalled','Not Installed'),
+ ('installed','Installed'),
+ ('to upgrade','To be upgraded'),
+ ('to remove','To be removed'),
+ ('to install','To be installed')
+ ], string='State', readonly=True),
+ 'demo': fields.boolean('Demo data'),
+ 'license': fields.selection([('GPL-2', 'GPL-2'),
+ ('Other proprietary', 'Other proprietary')], string='License',
+ readonly=True),
+ }
+
+ _defaults = {
+ 'state': lambda *a: 'uninstalled',
+ 'demo': lambda *a: False,
+ 'license': lambda *a: 'GPL-2',
+ }
+ _order = 'name'
+
+ _sql_constraints = [
+ ('name_uniq', 'unique (name)', 'The name of the module must be unique !')
+ ]
+
+ def unlink(self, cr, uid, ids, context=None):
+ if not ids:
+ return True
+ if isinstance(ids, (int, long)):
+ ids = [ids]
+ for mod in self.read(cr, uid, ids, ['state'], context):
+ if mod['state'] in ('installed', 'to upgrade', 'to remove', 'to install'):
+ raise orm.except_orm(_('Error'),
+ _('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_change(self, cr, uid, ids, newstate, context={}, level=50):
+ if level<1:
+ raise Exception, _('Recursion error in modules dependencies !')
+ demo = True
+ for module in self.browse(cr, uid, ids):
+ mdemo = True
+ for dep in module.dependencies_id:
+ ids2 = self.search(cr, uid, [('name','=',dep.name)])
+ mdemo = self.state_change(cr, uid, ids2, newstate, context, level-1,)\
+ and mdemo
+ if not module.dependencies_id:
+ mdemo = module.demo
+ if module.state == 'uninstalled':
+ self.write(cr, uid, [module.id], {'state': newstate, 'demo':mdemo})
+ demo = demo and mdemo
+ return demo
+
+ def state_upgrade(self, cr, uid, ids, newstate, context=None, level=50):
+ dep_obj = self.pool.get('ir.module.module.dependency')
+ if level<1:
+ raise Exception, _('Recursion error in modules dependencies !')
+ for module in self.browse(cr, uid, ids):
+ dep_ids = dep_obj.search(cr, uid, [('name', '=', module.name)])
+ if dep_ids:
+ ids2 = []
+ for dep in dep_obj.browse(cr, uid, dep_ids):
+ if dep.module_id.state != 'to upgrade':
+ ids2.append(dep.module_id.id)
+ self.state_upgrade(cr, uid, ids2, newstate, context, level)
+ if module.state == 'installed':
+ self.write(cr, uid, module.id, {'state': newstate})
+ return True
+
+ def button_install(self, cr, uid, ids, context={}):
+ return self.state_change(cr, uid, ids, 'to install', context)
+
+ def button_install_cancel(self, cr, uid, ids, context={}):
+ self.write(cr, uid, ids, {'state': 'uninstalled', 'demo':False})
+ return True
+
+ def button_uninstall(self, cr, uid, ids, context={}):
+ for module in self.browse(cr, uid, ids):
+ cr.execute('''select m.state,m.name
+ from
+ ir_module_module_dependency d
+ join
+ ir_module_module m on (d.module_id=m.id)
+ where
+ d.name=%s and
+ m.state not in ('uninstalled','uninstallable','to remove')''', (module.name,))
+ res = cr.fetchall()
+ if res:
+ raise orm.except_orm(_('Error'), _('The module you are trying to remove depends on installed modules :\n %s') % '\n'.join(map(lambda x: '\t%s: %s' % (x[0], x[1]), res)))
+ self.write(cr, uid, ids, {'state': 'to remove'})
+ return True
+
+ def button_uninstall_cancel(self, cr, uid, ids, context={}):
+ self.write(cr, uid, ids, {'state': 'installed'})
+ return True
+ def button_upgrade(self, cr, uid, ids, context=None):
+ return self.state_upgrade(cr, uid, ids, 'to upgrade', context)
+ def button_upgrade_cancel(self, cr, uid, ids, context={}):
+ self.write(cr, uid, ids, {'state': 'installed'})
+ return True
+ def button_update_translations(self, cr, uid, ids, context={}):
+ cr.execute('select code from res_lang where translatable=TRUE')
+ langs = [l[0] for l in cr.fetchall()]
+ modules = self.read(cr, uid, ids, ['name'])
+ for module in modules:
+ files = self.get_module_info(module['name']).get('translations', {})
+ for lang in langs:
+ if files.has_key(lang):
+ filepath = files[lang]
+ # if filepath does not contain :// we prepend the path of the module
+ if filepath.find('://') == -1:
+ filepath = addons.get_module_resource(module['name'], filepath)
+ tools.trans_load(filepath, lang)
+ return True
+
+ # update the list of available packages
+ def update_list(self, cr, uid, context={}):
+ robj = self.pool.get('ir.module.repository')
+ res = [0, 0] # [update, add]
+
+ # iterate through installed modules and mark them as being so
+ for name in addons.get_modules():
+ mod_name = name
+ if name[-4:]=='.zip':
+ mod_name=name[:-4]
+ ids = self.search(cr, uid, [('name','=',mod_name)])
+ if ids:
+ id = ids[0]
+ mod = self.browse(cr, uid, id)
+ terp = self.get_module_info(mod_name)
+ if terp.get('installable', True) and mod.state == 'uninstallable':
+ self.write(cr, uid, id, {'state': 'uninstalled'})
+ if vercmp(terp.get('version', ''), mod.latest_version or '0') > 0:
+ self.write(cr, uid, id, {
+ 'latest_version': terp.get('version'),
+ 'url': ''})
+ res[0] += 1
+ self.write(cr, uid, id, {
+ 'description': terp.get('description', ''),
+ 'shortdesc': terp.get('name', ''),
+ 'author': terp.get('author', 'Unknown'),
+ 'website': terp.get('website', ''),
+ 'license': terp.get('license', 'GPL-2'),
+ })
+ cr.execute('DELETE FROM ir_module_module_dependency\
+ WHERE module_id = %d', (id,))
+ self._update_dependencies(cr, uid, ids[0], terp.get('depends',
+ []))
+ self._update_category(cr, uid, ids[0], terp.get('category',
+ 'Uncategorized'))
+ continue
+ terp_file = addons.get_module_resource(name, '__terp__.py')
+ mod_path = addons.get_module_path(name)
+ if os.path.isdir(mod_path) or os.path.islink(mod_path) or zipfile.is_zipfile(mod_path):
+ terp = self.get_module_info(mod_name)
+ if not terp or not terp.get('installable', True):
+ continue
+ if not os.path.isfile(mod_path+'.zip'):
+ import imp
+ # XXX must restrict to only addons paths
+ imp.load_module(name, *imp.find_module(mod_name))
+ else:
+ import zipimport
+ zimp = zipimport.zipimporter(mod_path+'.zip')
+ zimp.load_module(mod_name)
+ id = self.create(cr, uid, {
+ 'name': mod_name,
+ 'state': 'uninstalled',
+ 'description': terp.get('description', ''),
+ '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
+ self._update_dependencies(cr, uid, id, terp.get('depends', []))
+ self._update_category(cr, uid, id, terp.get('category', 'Uncategorized'))
+
+ import socket
+ socket.setdefaulttimeout(10)
+ for repository in robj.browse(cr, uid, robj.search(cr, uid, [])):
+ try:
+ index_page = urllib.urlopen(repository.url).read()
+ except IOError, e:
+ if e.errno == 21:
+ raise orm.except_orm(_('Error'),
+ _("This url '%s' must provide an html file with links to zip modules") % (repository.url))
+ else:
+ raise
+ modules = re.findall(repository.filter, index_page, re.I+re.M)
+ mod_sort = {}
+ for m in modules:
+ name = m[0]
+ version = m[1]
+ extension = m[-1]
+ if version == 'x': # 'x' version was a mistake
+ version = '0'
+ if name in mod_sort:
+ if vercmp(version, mod_sort[name][0]) <= 0:
+ continue
+ mod_sort[name] = [version, extension]
+ for name in mod_sort.keys():
+ version, extension = mod_sort[name]
+ url = repository.url+'/'+name+'-'+version+extension
+ ids = self.search(cr, uid, [('name','=',name)])
+ if not ids:
+ self.create(cr, uid, {
+ 'name': name,
+ 'latest_version': version,
+ 'published_version': version,
+ 'url': url,
+ 'state': 'uninstalled',
+ })
+ 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'
+ c = vercmp(version, latest_version)
+ if c > 0:
+ self.write(cr, uid, id,
+ {'latest_version': version, 'url': url})
+ res[0] += 1
+ published_version = self.read(cr, uid, id, ['published_version'])\
+ ['published_version']
+ if published_version == 'x' or not published_version:
+ published_version = '0'
+ c = vercmp(version, published_version)
+ if c > 0:
+ self.write(cr, uid, id,
+ {'published_version': version})
+ return res
+
+ def download(self, cr, uid, ids, download=True, context=None):
+ res = []
+ for mod in self.browse(cr, uid, ids, context=context):
+ if not mod.url:
+ continue
+ match = re.search('-([a-zA-Z0-9\._-]+)(\.zip)', mod.url, re.I)
+ version = '0'
+ if match:
+ version = match.group(1)
+ if vercmp(mod.installed_version or '0', version) >= 0:
+ continue
+ res.append(mod.url)
+ if not download:
+ continue
+ zipfile = urllib.urlopen(mod.url).read()
+ fname = addons.get_module_path(mod.name+'.zip')
+ try:
+ fp = file(fname, 'wb')
+ fp.write(zipfile)
+ fp.close()
+ except IOError, e:
+ raise orm.except_orm(_('Error'), _('Can not create the module file:\n %s') % (fname,))
+ terp = self.get_module_info(mod.name)
+ self.write(cr, uid, mod.id, {
+ 'description': terp.get('description', ''),
+ 'shortdesc': terp.get('name', ''),
+ 'author': terp.get('author', 'Unknown'),
+ 'website': terp.get('website', ''),
+ 'license': terp.get('license', 'GPL-2'),
+ })
+ cr.execute('DELETE FROM ir_module_module_dependency ' \
+ 'WHERE module_id = %d', (mod.id,))
+ self._update_dependencies(cr, uid, mod.id, terp.get('depends',
+ []))
+ self._update_category(cr, uid, mod.id, terp.get('category',
+ 'Uncategorized'))
+ # Import module
+ zimp = zipimport.zipimporter(fname)
+ zimp.load_module(mod.name)
+ return res
+
+ 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))
+
+ 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))
+ 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))
+ else:
+ c_id = c_id[0]
+ p_id = c_id
+ categs = categs[1:]
+ self.write(cr, uid, [id], {'category_id': p_id})
module()
class module_dependency(osv.osv):
- _name = "ir.module.module.dependency"
- _description = "Module dependency"
-
- def _state(self, cr, uid, ids, name, args, context={}):
- result = {}
- mod_obj = self.pool.get('ir.module.module')
- for md in self.browse(cr, uid, ids):
- ids = mod_obj.search(cr, uid, [('name', '=', md.name)])
- if ids:
- result[md.id] = mod_obj.read(cr, uid, [ids[0]], ['state'])[0]['state']
- else:
- result[md.id] = 'unknown'
- return result
-
- _columns = {
- 'name': fields.char('Name', size=128),
- 'module_id': fields.many2one('ir.module.module', 'Module', select=True, ondelete='cascade'),
- 'state': fields.function(_state, method=True, type='selection', selection=[
- ('uninstallable','Uninstallable'),
- ('uninstalled','Not Installed'),
- ('installed','Installed'),
- ('to upgrade','To be upgraded'),
- ('to remove','To be removed'),
- ('to install','To be installed'),
- ('unknown', 'Unknown'),
- ], string='State', readonly=True),
- }
+ _name = "ir.module.module.dependency"
+ _description = "Module dependency"
+
+ def _state(self, cr, uid, ids, name, args, context={}):
+ result = {}
+ mod_obj = self.pool.get('ir.module.module')
+ for md in self.browse(cr, uid, ids):
+ ids = mod_obj.search(cr, uid, [('name', '=', md.name)])
+ if ids:
+ result[md.id] = mod_obj.read(cr, uid, [ids[0]], ['state'])[0]['state']
+ else:
+ result[md.id] = 'unknown'
+ return result
+
+ _columns = {
+ 'name': fields.char('Name', size=128),
+ 'module_id': fields.many2one('ir.module.module', 'Module', select=True, ondelete='cascade'),
+ 'state': fields.function(_state, method=True, type='selection', selection=[
+ ('uninstallable','Uninstallable'),
+ ('uninstalled','Not Installed'),
+ ('installed','Installed'),
+ ('to upgrade','To be upgraded'),
+ ('to remove','To be removed'),
+ ('to install','To be installed'),
+ ('unknown', 'Unknown'),
+ ], string='State', readonly=True),
+ }
module_dependency()
class module_config_wizard_step(osv.osv):
- _name = 'ir.module.module.configuration.step'
- _columns={
- 'name':fields.char('Name',size=64,required=True, select=True),
- 'note':fields.text('Text'),
- 'action_id':fields.many2one('ir.actions.act_window', 'Action', select=True,required=True, ondelete='cascade'),
- 'sequence':fields.integer('Sequence'),
- 'state':fields.selection([('open', 'Open'),('done', 'Done'),('skip','Skip')], string='State', required=True)
- }
- _defaults={
- 'state': lambda *a: 'open',
- 'sequence': lambda *a: 10,
- }
- _order="sequence"
+ _name = 'ir.module.module.configuration.step'
+ _columns={
+ 'name':fields.char('Name',size=64,required=True, select=True),
+ 'note':fields.text('Text'),
+ 'action_id':fields.many2one('ir.actions.act_window', 'Action', select=True,required=True, ondelete='cascade'),
+ 'sequence':fields.integer('Sequence'),
+ 'state':fields.selection([('open', 'Open'),('done', 'Done'),('skip','Skip')], string='State', required=True)
+ }
+ _defaults={
+ 'state': lambda *a: 'open',
+ 'sequence': lambda *a: 10,
+ }
+ _order="sequence"
module_config_wizard_step()
class module_configuration(osv.osv_memory):
- _name='ir.module.module.configuration.wizard'
- def _get_action_name(self, cr, uid, context={}):
- item_obj = self.pool.get('ir.module.module.configuration.step')
- item_ids = item_obj.search(cr, uid, [
- ('state', '=', 'open'),
- ], limit=1, context=context)
- if item_ids and len(item_ids):
- item = item_obj.browse(cr, uid, item_ids[0], context=context)
- return item.note
- else:
- return "Your database is now fully configured.\n\nClick 'Continue' and enyoy your OpenERP experience..."
- return False
-
- def _get_action(self, cr, uid, context={}):
- item_obj = self.pool.get('ir.module.module.configuration.step')
- item_ids = item_obj.search(cr, uid, [
- ('state', '=', 'open'),
- ], limit=1, context=context)
- if item_ids:
- item = item_obj.browse(cr, uid, item_ids[0], context=context)
- return item.id
- return False
-
- _columns = {
- 'name': fields.text('Next Wizard',readonly=True),
- 'item_id':fields.many2one('ir.module.module.configuration.step', 'Next Configuration Wizard',invisible=True, readonly=True),
-
- }
- _defaults={
- 'item_id':_get_action,
- 'name':_get_action_name,
-
- }
- def button_skip(self,cr,uid,ids,context=None):
- item_obj = self.pool.get('ir.module.module.configuration.step')
- item_id=self.read(cr,uid,ids)[0]['item_id']
- if item_id:
- item = item_obj.browse(cr, uid, item_id, context=context)
- item_obj.write(cr, uid, item.id, {
- 'state': 'skip',
- }, context=context)
- return{
- 'view_type': 'form',
- "view_mode": 'form',
- 'res_model': 'ir.module.module.configuration.wizard',
- 'type': 'ir.actions.act_window',
- 'target':'new',
- }
- return {'type':'ir.actions.act_window_close'}
-
- def button_continue(self, cr, uid, ids, context=None):
- item_obj = self.pool.get('ir.module.module.configuration.step')
- item_id=self.read(cr,uid,ids)[0]['item_id']
- if item_id:
- item = item_obj.browse(cr, uid, item_id, context=context)
- item_obj.write(cr, uid, item.id, {
- 'state': 'done',
- }, context=context)
- return{
- 'view_type': item.action_id.view_type,
- 'view_id':item.action_id.view_id and [item.action_id.view_id.id] or False,
- 'res_model': item.action_id.res_model,
- 'type': item.action_id.type,
- 'target':item.action_id.target,
- }
- return {'type':'ir.actions.act_window_close' }
+ _name='ir.module.module.configuration.wizard'
+ def _get_action_name(self, cr, uid, context={}):
+ item_obj = self.pool.get('ir.module.module.configuration.step')
+ item_ids = item_obj.search(cr, uid, [
+ ('state', '=', 'open'),
+ ], limit=1, context=context)
+ if item_ids and len(item_ids):
+ item = item_obj.browse(cr, uid, item_ids[0], context=context)
+ return item.note
+ else:
+ return "Your database is now fully configured.\n\nClick 'Continue' and enyoy your OpenERP experience..."
+ return False
+
+ def _get_action(self, cr, uid, context={}):
+ item_obj = self.pool.get('ir.module.module.configuration.step')
+ item_ids = item_obj.search(cr, uid, [
+ ('state', '=', 'open'),
+ ], limit=1, context=context)
+ if item_ids:
+ item = item_obj.browse(cr, uid, item_ids[0], context=context)
+ return item.id
+ return False
+
+ _columns = {
+ 'name': fields.text('Next Wizard',readonly=True),
+ 'item_id':fields.many2one('ir.module.module.configuration.step', 'Next Configuration Wizard',invisible=True, readonly=True),
+
+ }
+ _defaults={
+ 'item_id':_get_action,
+ 'name':_get_action_name,
+
+ }
+ def button_skip(self,cr,uid,ids,context=None):
+ item_obj = self.pool.get('ir.module.module.configuration.step')
+ item_id=self.read(cr,uid,ids)[0]['item_id']
+ if item_id:
+ item = item_obj.browse(cr, uid, item_id, context=context)
+ item_obj.write(cr, uid, item.id, {
+ 'state': 'skip',
+ }, context=context)
+ return{
+ 'view_type': 'form',
+ "view_mode": 'form',
+ 'res_model': 'ir.module.module.configuration.wizard',
+ 'type': 'ir.actions.act_window',
+ 'target':'new',
+ }
+ return {'type':'ir.actions.act_window_close'}
+
+ def button_continue(self, cr, uid, ids, context=None):
+ item_obj = self.pool.get('ir.module.module.configuration.step')
+ item_id=self.read(cr,uid,ids)[0]['item_id']
+ if item_id:
+ item = item_obj.browse(cr, uid, item_id, context=context)
+ item_obj.write(cr, uid, item.id, {
+ 'state': 'done',
+ }, context=context)
+ return{
+ 'view_type': item.action_id.view_type,
+ 'view_id':item.action_id.view_id and [item.action_id.view_id.id] or False,
+ 'res_model': item.action_id.res_model,
+ 'type': item.action_id.type,
+ 'target':item.action_id.target,
+ }
+ return {'type':'ir.actions.act_window_close' }
module_configuration()
diff --git a/bin/addons/base/module/report/ir_module_reference_print.py b/bin/addons/base/module/report/ir_module_reference_print.py
index f934803e862..57ffc71bdc4 100644
--- a/bin/addons/base/module/report/ir_module_reference_print.py
+++ b/bin/addons/base/module/report/ir_module_reference_print.py
@@ -31,33 +31,33 @@ import time
from report import report_sxw
class ir_module_reference_print(report_sxw.rml_parse):
- def __init__(self, cr, uid, name, context):
- super(ir_module_reference_print, self).__init__(cr, uid, name, context)
- self.localcontext.update({
- 'time': time,
- 'findobj': self._object_find,
- 'objdoc': self._object_doc,
- 'findflds': self._fields_find,
- })
- def _object_doc(self, obj):
- modobj = self.pool.get(obj)
- return modobj.__doc__
+ def __init__(self, cr, uid, name, context):
+ super(ir_module_reference_print, self).__init__(cr, uid, name, context)
+ self.localcontext.update({
+ 'time': time,
+ 'findobj': self._object_find,
+ 'objdoc': self._object_doc,
+ 'findflds': self._fields_find,
+ })
+ def _object_doc(self, obj):
+ modobj = self.pool.get(obj)
+ return modobj.__doc__
- def _object_find(self, module):
- modobj = self.pool.get('ir.model')
- if module=='base':
- ids = modobj.search(self.cr, self.uid, [('model','=like','res%')])
- ids += modobj.search(self.cr, self.uid, [('model','=like','ir%')])
- else:
- ids = modobj.search(self.cr, self.uid, [('model','=like',module+'%')])
- return modobj.browse(self.cr, self.uid, ids)
+ def _object_find(self, module):
+ modobj = self.pool.get('ir.model')
+ if module=='base':
+ ids = modobj.search(self.cr, self.uid, [('model','=like','res%')])
+ ids += modobj.search(self.cr, self.uid, [('model','=like','ir%')])
+ else:
+ ids = modobj.search(self.cr, self.uid, [('model','=like',module+'%')])
+ return modobj.browse(self.cr, self.uid, ids)
- def _fields_find(self, obj):
- modobj = self.pool.get(obj)
- res = modobj.fields_get(self.cr, self.uid).items()
- return res
+ def _fields_find(self, obj):
+ modobj = self.pool.get(obj)
+ res = modobj.fields_get(self.cr, self.uid).items()
+ return res
report_sxw.report_sxw('report.ir.module.reference', 'ir.module.module',
- 'addons/base/module/report/ir_module_reference.rml',
- parser=ir_module_reference_print, header=False)
+ 'addons/base/module/report/ir_module_reference.rml',
+ parser=ir_module_reference_print, header=False)
diff --git a/bin/addons/base/module/wizard/add_new.py b/bin/addons/base/module/wizard/add_new.py
index 0b5ec6a2f2f..39465dff970 100644
--- a/bin/addons/base/module/wizard/add_new.py
+++ b/bin/addons/base/module/wizard/add_new.py
@@ -49,48 +49,48 @@ _info_arch = '''<?xml version="1.0"?>
_info_fields = {}
class wizard_install_module(wizard.interface):
- def watch_dir(self, cr, uid, data, context):
- mod_obj = pooler.get_pool(cr.dbname).get('ir.module.module')
- all_mods = mod_obj.read(cr, uid, mod_obj.search(cr, uid, []), ['name', 'state'])
- known_modules = [x['name'] for x in all_mods]
- ls_ad = glob.glob(os.path.join(tools.config['addons_path'], '*', '__terp__.py'))
- modules = [module_name_re.match(name).group(1) for name in ls_ad]
- for fname in os.listdir(tools.config['addons_path']):
- if zipfile.is_zipfile(fname):
- modules.append( fname.split('.')[0])
- for module in modules:
- if module in known_modules:
- continue
- terp = mod_obj.get_module_info(module)
- if not terp.get('installable', True):
- continue
- imp.load_module(module, *imp.find_module(module))
- mod_id = mod_obj.create(cr, uid, {
- 'name': module,
- 'state': 'uninstalled',
- 'description': terp.get('description', ''),
- 'shortdesc': terp.get('name', ''),
- 'author': terp.get('author', 'Unknown')})
- dependencies = terp.get('depends', [])
- for d in dependencies:
- cr.execute('insert into ir_module_module_dependency (module_id,name) values (%s, %s)', (mod_id, d))
- for module in known_modules:
- terp = mod_obj.get_module_info(module)
- if terp.get('installable', True):
- for mod in all_mods:
- if mod['name'] == module and mod['state'] == 'uninstallable':
- mod_obj.write(cr, uid, [mod['id']], {'state': 'uninstalled'})
- return {}
+ def watch_dir(self, cr, uid, data, context):
+ mod_obj = pooler.get_pool(cr.dbname).get('ir.module.module')
+ all_mods = mod_obj.read(cr, uid, mod_obj.search(cr, uid, []), ['name', 'state'])
+ known_modules = [x['name'] for x in all_mods]
+ ls_ad = glob.glob(os.path.join(tools.config['addons_path'], '*', '__terp__.py'))
+ modules = [module_name_re.match(name).group(1) for name in ls_ad]
+ for fname in os.listdir(tools.config['addons_path']):
+ if zipfile.is_zipfile(fname):
+ modules.append( fname.split('.')[0])
+ for module in modules:
+ if module in known_modules:
+ continue
+ terp = mod_obj.get_module_info(module)
+ if not terp.get('installable', True):
+ continue
+ imp.load_module(module, *imp.find_module(module))
+ mod_id = mod_obj.create(cr, uid, {
+ 'name': module,
+ 'state': 'uninstalled',
+ 'description': terp.get('description', ''),
+ 'shortdesc': terp.get('name', ''),
+ 'author': terp.get('author', 'Unknown')})
+ dependencies = terp.get('depends', [])
+ for d in dependencies:
+ cr.execute('insert into ir_module_module_dependency (module_id,name) values (%s, %s)', (mod_id, d))
+ for module in known_modules:
+ terp = mod_obj.get_module_info(module)
+ if terp.get('installable', True):
+ for mod in all_mods:
+ if mod['name'] == module and mod['state'] == 'uninstallable':
+ mod_obj.write(cr, uid, [mod['id']], {'state': 'uninstalled'})
+ return {}
- states = {
- 'init': {
- 'actions': [],
- 'result': {'type':'form', 'arch': _info_arch, 'fields': _info_fields, 'state':[('end','Cancel','gtk-cancel'),('addmod','Check new modules','gtk-ok')]}
- },
- 'addmod': {
- 'actions': [watch_dir],
- 'result': {'type':'state', 'state':'end'}
- },
- }
+ states = {
+ 'init': {
+ 'actions': [],
+ 'result': {'type':'form', 'arch': _info_arch, 'fields': _info_fields, 'state':[('end','Cancel','gtk-cancel'),('addmod','Check new modules','gtk-ok')]}
+ },
+ 'addmod': {
+ 'actions': [watch_dir],
+ 'result': {'type':'state', 'state':'end'}
+ },
+ }
wizard_install_module('module.module.scan')
diff --git a/bin/addons/base/module/wizard/wizard_export_lang.py b/bin/addons/base/module/wizard/wizard_export_lang.py
index 3f7fa8f99df..3a4a4e82ae9 100644
--- a/bin/addons/base/module/wizard/wizard_export_lang.py
+++ b/bin/addons/base/module/wizard/wizard_export_lang.py
@@ -40,114 +40,114 @@ from osv import fields,osv
'''
view_form_init="""<?xml version="1.0"?>
<form string="Export language">
- <image name="gtk-dialog-info" colspan="2"/>
- <group colspan="2" col="4">
- <separator string="Export translation file" colspan="4"/>
- <label align="0.0" string="Choose a language to export:" colspan="4"/>
- <field name="lang" colspan="4"/>
- </group>
+ <image name="gtk-dialog-info" colspan="2"/>
+ <group colspan="2" col="4">
+ <separator string="Export translation file" colspan="4"/>
+ <label align="0.0" string="Choose a language to export:" colspan="4"/>
+ <field name="lang" colspan="4"/>
+ </group>
</form>"""
view_form_finish="""<?xml version="1.0"?>
<form string="Export language">
- <image name="gtk-dialog-info" colspan="2"/>
- <group colspan="2" col="4">
- <separator string="Export done" colspan="4"/>
- <field name="data" readonly="1" colspan="3"/>
- <label align="0.0" string="Save this document to a .CSV file and open it with\n your favourite spreadsheet software. The file\n encoding is UTF-8. You have to translate the latest\n column before reimporting it." colspan="4"/>
- </group>
+ <image name="gtk-dialog-info" colspan="2"/>
+ <group colspan="2" col="4">
+ <separator string="Export done" colspan="4"/>
+ <field name="data" readonly="1" colspan="3"/>
+ <label align="0.0" string="Save this document to a .CSV file and open it with\n your favourite spreadsheet software. The file\n encoding is UTF-8. You have to translate the latest\n column before reimporting it." colspan="4"/>
+ </group>
</form>"""
class wizard_export_lang(wizard.interface):
- def _get_language(self, cr, uid, context):
- lang_obj=pooler.get_pool(cr.dbname).get('res.lang')
- ids=lang_obj.search(cr, uid, [('active', '=', True),])
- langs=lang_obj.browse(cr, uid, ids)
- return [(lang.code, lang.translatable and lang.name or _('New language')) for lang in langs]
+ def _get_language(self, cr, uid, context):
+ lang_obj=pooler.get_pool(cr.dbname).get('res.lang')
+ ids=lang_obj.search(cr, uid, [('active', '=', True),])
+ langs=lang_obj.browse(cr, uid, ids)
+ return [(lang.code, lang.translatable and lang.name or _('New language')) for lang in langs]
- def _get_file(self, cr, uid, data, context):
- file=tools.trans_generate(data['form']['lang'], 'all', dbname=cr.dbname)
- buf=StringIO.StringIO()
- writer=csv.writer(buf, 'UNIX')
- for row in file:
- writer.writerow(row)
- del file
- out=base64.encodestring(buf.getvalue())
- buf.close()
- return {'data': out}
+ def _get_file(self, cr, uid, data, context):
+ file=tools.trans_generate(data['form']['lang'], 'all', dbname=cr.dbname)
+ buf=StringIO.StringIO()
+ writer=csv.writer(buf, 'UNIX')
+ for row in file:
+ writer.writerow(row)
+ del file
+ out=base64.encodestring(buf.getvalue())
+ buf.close()
+ return {'data': out}
- fields_form={
- 'lang': {'string':'Language', 'type':'selection', 'selection':_get_language,},
- }
- fields_form_finish={
- 'data': {'string':'File', 'type':'binary', 'readonly': True,},
- }
- states={
- 'init':{
- 'actions': [],
- 'result': {'type': 'form', 'arch': view_form_init, 'fields': fields_form,
- 'state': [
- ('end', 'Cancel', 'gtk-cancel'),
- ('finish', 'Ok', 'gtk-ok', True)
- ]
- }
- },
- 'finish':{
- 'actions': [_get_file],
- 'result': {'type': 'form', 'arch': view_form_finish,
- 'fields': fields_form_finish,
- 'state': [
- ('end', 'Close', 'gtk-cancel', True)
- ]
- }
- },
- }
+ fields_form={
+ 'lang': {'string':'Language', 'type':'selection', 'selection':_get_language,},
+ }
+ fields_form_finish={
+ 'data': {'string':'File', 'type':'binary', 'readonly': True,},
+ }
+ states={
+ 'init':{
+ 'actions': [],
+ 'result': {'type': 'form', 'arch': view_form_init, 'fields': fields_form,
+ 'state': [
+ ('end', 'Cancel', 'gtk-cancel'),
+ ('finish', 'Ok', 'gtk-ok', True)
+ ]
+ }
+ },
+ 'finish':{
+ 'actions': [_get_file],
+ 'result': {'type': 'form', 'arch': view_form_finish,
+ 'fields': fields_form_finish,
+ 'state': [
+ ('end', 'Close', 'gtk-cancel', True)
+ ]
+ }
+ },
+ }
wizard_export_lang('module.lang.export')
'''
class wizard_export_lang(osv.osv_memory):
- def _get_languages(self, cr, uid, context):
- lang_obj=pooler.get_pool(cr.dbname).get('res.lang')
- ids=lang_obj.search(cr, uid, [('active', '=', True),])
- langs=lang_obj.browse(cr, uid, ids)
- return [(lang.code, lang.translatable and lang.name or _('New language')) for lang in langs]
-
+ def _get_languages(self, cr, uid, context):
+ lang_obj=pooler.get_pool(cr.dbname).get('res.lang')
+ ids=lang_obj.search(cr, uid, [('active', '=', True),])
+ langs=lang_obj.browse(cr, uid, ids)
+ return [(lang.code, lang.translatable and lang.name or _('New language')) for lang in langs]
+
- def act_cancel(self, cr, uid, ids, context=None):
- #self.unlink(cr, uid, ids, context)
- return {'type':'ir.actions.act_window_close' }
+ def act_cancel(self, cr, uid, ids, context=None):
+ #self.unlink(cr, uid, ids, context)
+ return {'type':'ir.actions.act_window_close' }
- def act_destroy(self, *args):
- return {'type':'ir.actions.act_window_close' }
+ def act_destroy(self, *args):
+ return {'type':'ir.actions.act_window_close' }
- def act_getfile(self, cr, uid, ids, context=None):
- this = self.browse(cr, uid, ids)[0]
- mods = map(lambda m: m.name, this.modules)
- mods.sort()
- buf=StringIO.StringIO()
-
- tools.trans_export(this.lang, mods, buf, this.format, dbname=cr.dbname)
+ def act_getfile(self, cr, uid, ids, context=None):
+ this = self.browse(cr, uid, ids)[0]
+ mods = map(lambda m: m.name, this.modules)
+ mods.sort()
+ buf=StringIO.StringIO()
+
+ tools.trans_export(this.lang, mods, buf, this.format, dbname=cr.dbname)
- if this.format == 'csv':
- this.advice = _("Save this document to a .CSV file and open it with your favourite spreadsheet software. The file encoding is UTF-8. You have to translate the latest column before reimporting it.")
- elif this.format == 'po':
- this.advice = _("Save this document to a .po file and edit it with a specific software or a text editor. The file encoding is UTF-8.")
-
- out=base64.encodestring(buf.getvalue())
- buf.close()
- return self.write(cr, uid, ids, {'state':'get', 'data':out, 'advice':this.advice}, context=context)
+ if this.format == 'csv':
+ this.advice = _("Save this document to a .CSV file and open it with your favourite spreadsheet software. The file encoding is UTF-8. You have to translate the latest column before reimporting it.")
+ elif this.format == 'po':
+ this.advice = _("Save this document to a .po file and edit it with a specific software or a text editor. The file encoding is UTF-8.")
+
+ out=base64.encodestring(buf.getvalue())
+ buf.close()
+ return self.write(cr, uid, ids, {'state':'get', 'data':out, 'advice':this.advice}, context=context)
- _name = "wizard.module.lang.export"
- _columns = {
- 'lang': fields.selection(_get_languages, 'Language',required=True),
- 'format': fields.selection( ( ('csv','CSV File'), ('po','PO File') ), 'File Format', required=True),
- 'modules': fields.many2many('ir.module.module', 'rel_modules_langexport', 'wiz_id', 'module_id', 'Modules', domain=[('state','=','installed')]),
- 'data': fields.binary('File', readonly=True),
- 'advice': fields.text('', readonly=True),
- 'state': fields.selection( ( ('choose','choose'), # choose language
- ('get','get'), # get the file
- ) ),
- }
- _defaults = { 'state': lambda *a: 'choose', }
+ _name = "wizard.module.lang.export"
+ _columns = {
+ 'lang': fields.selection(_get_languages, 'Language',required=True),
+ 'format': fields.selection( ( ('csv','CSV File'), ('po','PO File') ), 'File Format', required=True),
+ 'modules': fields.many2many('ir.module.module', 'rel_modules_langexport', 'wiz_id', 'module_id', 'Modules', domain=[('state','=','installed')]),
+ 'data': fields.binary('File', readonly=True),
+ 'advice': fields.text('', readonly=True),
+ 'state': fields.selection( ( ('choose','choose'), # choose language
+ ('get','get'), # get the file
+ ) ),
+ }
+ _defaults = { 'state': lambda *a: 'choose', }
wizard_export_lang()
diff --git a/bin/addons/base/module/wizard/wizard_import_lang.py b/bin/addons/base/module/wizard/wizard_import_lang.py
index 9134e64433a..df0bee1310c 100644
--- a/bin/addons/base/module/wizard/wizard_import_lang.py
+++ b/bin/addons/base/module/wizard/wizard_import_lang.py
@@ -36,53 +36,53 @@ from tempfile import TemporaryFile
view_form="""<?xml version="1.0"?>
<form string="Import language">
- <image name="gtk-dialog-info" colspan="2"/>
- <group colspan="2" col="4">
- <separator string="Import new language" colspan="4"/>
- <field name="name"/>
- <field name="code"/>
- <field name="data" colspan="3"/>
- <label string="You have to import a .CSV file wich is encoded in UTF-8.\nPlease check that the first line of your file is:" colspan="4" align="0.0"/>
- <label string="type,name,res_id,src,value" colspan="4"/>
- </group>
+ <image name="gtk-dialog-info" colspan="2"/>
+ <group colspan="2" col="4">
+ <separator string="Import new language" colspan="4"/>
+ <field name="name"/>
+ <field name="code"/>
+ <field name="data" colspan="3"/>
+ <label string="You have to import a .CSV file wich is encoded in UTF-8.\nPlease check that the first line of your file is:" colspan="4" align="0.0"/>
+ <label string="type,name,res_id,src,value" colspan="4"/>
+ </group>
</form>"""
fields_form={
- 'name':{'string':'Language name', 'type':'char', 'size':64, 'required':True},
- 'code':{'string':'Code (eg:en__US)', 'type':'char', 'size':5, 'required':True},
- 'data':{'string':'File', 'type':'binary', 'required':True},
+ 'name':{'string':'Language name', 'type':'char', 'size':64, 'required':True},
+ 'code':{'string':'Code (eg:en__US)', 'type':'char', 'size':5, 'required':True},
+ 'data':{'string':'File', 'type':'binary', 'required':True},
}
class wizard_import_lang(wizard.interface):
- def _import_lang(self, cr, uid, data, context):
- form=data['form']
- fileobj = TemporaryFile('w+')
- fileobj.write( base64.decodestring(form['data']) )
+ def _import_lang(self, cr, uid, data, context):
+ form=data['form']
+ fileobj = TemporaryFile('w+')
+ fileobj.write( base64.decodestring(form['data']) )
- # now we determine the file format
- fileobj.seek(0)
- first_line = fileobj.readline().strip()
- fileformat = first_line.endswith("type,name,res_id,src,value") and 'csv' or 'po'
- fileobj.seek(0)
+ # now we determine the file format
+ fileobj.seek(0)
+ first_line = fileobj.readline().strip()
+ fileformat = first_line.endswith("type,name,res_id,src,value") and 'csv' or 'po'
+ fileobj.seek(0)
- tools.trans_load_data(cr.dbname, fileobj, fileformat, form['code'], lang_name=form['name'])
- fileobj.close()
- return {}
+ tools.trans_load_data(cr.dbname, fileobj, fileformat, form['code'], lang_name=form['name'])
+ fileobj.close()
+ return {}
- states={
- 'init':{
- 'actions': [],
- 'result': {'type': 'form', 'arch': view_form, 'fields': fields_form,
- 'state':[
- ('end', 'Cancel', 'gtk-cancel'),
- ('finish', 'Ok', 'gtk-ok', True)
- ]
- }
- },
- 'finish':{
- 'actions':[],
- 'result':{'type':'action', 'action':_import_lang, 'state':'end'}
- },
- }
+ states={
+ 'init':{
+ 'actions': [],
+ 'result': {'type': 'form', 'arch': view_form, 'fields': fields_form,
+ 'state':[
+ ('end', 'Cancel', 'gtk-cancel'),
+ ('finish', 'Ok', 'gtk-ok', True)
+ ]
+ }
+ },
+ 'finish':{
+ 'actions':[],
+ 'result':{'type':'action', 'action':_import_lang, 'state':'end'}
+ },
+ }
wizard_import_lang('module.lang.import')
diff --git a/bin/addons/base/module/wizard/wizard_module_import.py b/bin/addons/base/module/wizard/wizard_module_import.py
index d59c635cd30..394389dd68f 100644
--- a/bin/addons/base/module/wizard/wizard_module_import.py
+++ b/bin/addons/base/module/wizard/wizard_module_import.py
@@ -40,82 +40,82 @@ import base64
finish_form ='''<?xml version="1.0"?>
<form string="Module import">
- <label string="Module successfully imported !" colspan="4"/>
+ <label string="Module successfully imported !" colspan="4"/>
</form>
'''
ask_form ='''<?xml version="1.0"?>
<form string="Module import">
- <separator string="Module import" colspan="4"/>
- <label string="Please give your module .ZIP file to import." colspan="4"/>
- <field name="module_file"/>
+ <separator string="Module import" colspan="4"/>
+ <label string="Please give your module .ZIP file to import." colspan="4"/>
+ <field name="module_file"/>
</form>
'''
ask_fields = {
- 'module_file': {'string': 'Module .ZIP file', 'type': 'binary', 'required': True},
+ 'module_file': {'string': 'Module .ZIP file', 'type': 'binary', 'required': True},
}
class move_module_wizard(wizard.interface):
- def importzip(self, cr, uid, data, context):
- module_obj=pooler.get_pool(cr.dbname).get('ir.module.module')
- module_data = data['form']['module_file']
+ def importzip(self, cr, uid, data, context):
+ module_obj=pooler.get_pool(cr.dbname).get('ir.module.module')
+ module_data = data['form']['module_file']
- val =base64.decodestring(module_data)
- fp = StringIO.StringIO(val)
- fdata = zipfile.ZipFile(fp, 'r')
- fname = fdata.namelist()[0]
- module_name = os.path.split(fname)[0]
+ val =base64.decodestring(module_data)
+ fp = StringIO.StringIO(val)
+ fdata = zipfile.ZipFile(fp, 'r')
+ fname = fdata.namelist()[0]
+ module_name = os.path.split(fname)[0]
- ad = tools.config['addons_path']
+ ad = tools.config['addons_path']
- fname = os.path.join(ad,module_name+'.zip')
- try:
- fp = file(fname, 'wb')
- fp.write(val)
- fp.close()
- except IOError, e:
- raise wizard.except_wizard(_('Error !'), _('Can not create the module file: %s !') % (fname,) )
+ fname = os.path.join(ad,module_name+'.zip')
+ try:
+ fp = file(fname, 'wb')
+ fp.write(val)
+ fp.close()
+ except IOError, e:
+ raise wizard.except_wizard(_('Error !'), _('Can not create the module file: %s !') % (fname,) )
- pooler.get_pool(cr.dbname).get('ir.module.module').update_list(cr, uid)
- return {'module_name': module_name}
+ pooler.get_pool(cr.dbname).get('ir.module.module').update_list(cr, uid)
+ return {'module_name': module_name}
- def _action_module_open(self, cr, uid, data, context):
- return {
- 'domain': str([('name', '=', data['form']['module_name'])]),
- 'name': 'Module List',
- 'view_type': 'form',
- 'view_mode': 'tree,form',
- 'res_model': 'ir.module.module',
- 'view_id': False,
- 'type': 'ir.actions.act_window'
- }
+ def _action_module_open(self, cr, uid, data, context):
+ return {
+ 'domain': str([('name', '=', data['form']['module_name'])]),
+ 'name': 'Module List',
+ 'view_type': 'form',
+ 'view_mode': 'tree,form',
+ 'res_model': 'ir.module.module',
+ 'view_id': False,
+ 'type': 'ir.actions.act_window'
+ }
- states = {
- 'init': {
- 'actions': [],
- 'result': {
- 'type': 'form',
- 'arch': ask_form,
- 'fields': ask_fields,
- 'state': [
- ('end', 'Cancel', 'gtk-cancel'),
- ('import', 'Import module', 'gtk-ok', True)
- ]
- }
- },
- 'import': {
- 'actions': [importzip],
- 'result': {
- 'type':'form',
- 'arch':finish_form,
- 'fields':{},
- 'state':[('open_window','Close')]
- }
- },
- 'open_window': {
- 'actions': [],
- 'result': {'type': 'action', 'action': _action_module_open, 'state':'end'}
- },
- }
+ states = {
+ 'init': {
+ 'actions': [],
+ 'result': {
+ 'type': 'form',
+ 'arch': ask_form,
+ 'fields': ask_fields,
+ 'state': [
+ ('end', 'Cancel', 'gtk-cancel'),
+ ('import', 'Import module', 'gtk-ok', True)
+ ]
+ }
+ },
+ 'import': {
+ 'actions': [importzip],
+ 'result': {
+ 'type':'form',
+ 'arch':finish_form,
+ 'fields':{},
+ 'state':[('open_window','Close')]
+ }
+ },
+ 'open_window': {
+ 'actions': [],
+ 'result': {'type': 'action', 'action': _action_module_open, 'state':'end'}
+ },
+ }
move_module_wizard('base.module.import')
diff --git a/bin/addons/base/module/wizard/wizard_module_lang_install.py b/bin/addons/base/module/wizard/wizard_module_lang_install.py
index a53da5b0463..95064b0d043 100644
--- a/bin/addons/base/module/wizard/wizard_module_lang_install.py
+++ b/bin/addons/base/module/wizard/wizard_module_lang_install.py
@@ -33,59 +33,59 @@ import tools
view_form_end = """<?xml version="1.0"?>
<form string="Language file loaded.">
- <image name="gtk-dialog-info" colspan="2"/>
- <group colspan="2" col="4">
- <separator string="Installation done" colspan="4"/>
- <label align="0.0" string="The selected language has been successfully installed.\nYou must change the preferences of the user and open a new menu to view changes." colspan="4"/>
- </group>
+ <image name="gtk-dialog-info" colspan="2"/>
+ <group colspan="2" col="4">
+ <separator string="Installation done" colspan="4"/>
+ <label align="0.0" string="The selected language has been successfully installed.\nYou must change the preferences of the user and open a new menu to view changes." colspan="4"/>
+ </group>
</form>"""
view_form = """<?xml version="1.0"?>
<form string="System Upgrade">
- <image name="gtk-dialog-info" colspan="2"/>
- <group colspan="2" col="4">
- <separator string="System Upgrade" colspan="4"/>
- <label align="0.0" string="Choose a language to install:" colspan="4"/>
- <field name="lang" colspan="4"/>
- <label align="0.0" string="Note that this operation may take a few minutes." colspan="4"/>
- </group>
+ <image name="gtk-dialog-info" colspan="2"/>
+ <group colspan="2" col="4">
+ <separator string="System Upgrade" colspan="4"/>
+ <label align="0.0" string="Choose a language to install:" colspan="4"/>
+ <field name="lang" colspan="4"/>
+ <label align="0.0" string="Note that this operation may take a few minutes." colspan="4"/>
+ </group>
</form>"""
class wizard_lang_install(wizard.interface):
- def _lang_install(self, cr, uid, data, context):
- lang = data['form']['lang']
- if lang and lang != 'en_US':
- filename = tools.config["root_path"] + "/i18n/" + lang + ".csv"
- tools.trans_load(cr.dbname, filename, lang)
- return {}
+ def _lang_install(self, cr, uid, data, context):
+ lang = data['form']['lang']
+ if lang and lang != 'en_US':
+ filename = tools.config["root_path"] + "/i18n/" + lang + ".csv"
+ tools.trans_load(cr.dbname, filename, lang)
+ return {}
- def _get_language(sel, cr, uid, context):
- return tools.scan_languages()
+ def _get_language(sel, cr, uid, context):
+ return tools.scan_languages()
- fields_form = {
- 'lang': {'string':'Language', 'type':'selection', 'selection':_get_language,
- },
- }
+ fields_form = {
+ 'lang': {'string':'Language', 'type':'selection', 'selection':_get_language,
+ },
+ }
- states = {
- 'init': {
- 'actions': [],
- 'result': {'type': 'form', 'arch': view_form, 'fields': fields_form,
- 'state': [
- ('end', 'Cancel', 'gtk-cancel'),
- ('start', 'Start installation', 'gtk-ok', True)
- ]
- }
- },
- 'start': {
- 'actions': [_lang_install],
- 'result': {'type': 'form', 'arch': view_form_end, 'fields': {},
- 'state': [
- ('end', 'Ok', 'gtk-ok', True)
- ]
- }
- },
- }
+ states = {
+ 'init': {
+ 'actions': [],
+ 'result': {'type': 'form', 'arch': view_form, 'fields': fields_form,
+ 'state': [
+ ('end', 'Cancel', 'gtk-cancel'),
+ ('start', 'Start installation', 'gtk-ok', True)
+ ]
+ }
+ },
+ 'start': {
+ 'actions': [_lang_install],
+ 'result': {'type': 'form', 'arch': view_form_end, 'fields': {},
+ 'state': [
+ ('end', 'Ok', 'gtk-ok', True)
+ ]
+ }
+ },
+ }
wizard_lang_install('module.lang.install')
diff --git a/bin/addons/base/module/wizard/wizard_module_upgrade.py b/bin/addons/base/module/wizard/wizard_module_upgrade.py
index 752c40a5358..482f2bb048e 100644
--- a/bin/addons/base/module/wizard/wizard_module_upgrade.py
+++ b/bin/addons/base/module/wizard/wizard_module_upgrade.py
@@ -35,121 +35,121 @@ import tools
view_form_end = """<?xml version="1.0"?>
<form string="System upgrade done">
- <separator string="System upgrade done"/>
- <label align="0.0" string="The modules have been upgraded / installed !" colspan="4"/>
- <label align="0.0" string="You may have to reinstall some language pack." colspan="4"/>
- <label align="0.0" string="We suggest you to reload the menu tab (Ctrl+t Ctrl+r)." colspan="4"/>
+ <separator string="System upgrade done"/>
+ <label align="0.0" string="The modules have been upgraded / installed !" colspan="4"/>
+ <label align="0.0" string="You may have to reinstall some language pack." colspan="4"/>
+ <label align="0.0" string="We suggest you to reload the menu tab (Ctrl+t Ctrl+r)." colspan="4"/>
</form>"""
view_form = """<?xml version="1.0"?>
<form string="System Upgrade">
- <image name="gtk-dialog-info" colspan="2"/>
- <group colspan="2" col="4">
- <label align="0.0" string="Your system will be upgraded." colspan="4"/>
- <label align="0.0" string="Note that this operation my take a few minutes." colspan="4"/>
- <separator string="Modules to update"/>
- <field name="module_info" nolabel="1" colspan="4"/>
- <separator string="Modules to download"/>
- <field name="module_download" nolabel="1" colspan="4"/>
- </group>
+ <image name="gtk-dialog-info" colspan="2"/>
+ <group colspan="2" col="4">
+ <label align="0.0" string="Your system will be upgraded." colspan="4"/>
+ <label align="0.0" string="Note that this operation my take a few minutes." colspan="4"/>
+ <separator string="Modules to update"/>
+ <field name="module_info" nolabel="1" colspan="4"/>
+ <separator string="Modules to download"/>
+ <field name="module_download" nolabel="1" colspan="4"/>
+ </group>
</form>"""
view_field = {
- "module_info": {'type': 'text', 'string': 'Modules to update',
- 'readonly': True},
- "module_download": {'type': 'text', 'string': 'Modules to download',
- 'readonly': True},
+ "module_info": {'type': 'text', 'string': 'Modules to update',
+ 'readonly': True},
+ "module_download": {'type': 'text', 'string': 'Modules to download',
+ 'readonly': True},
}
class wizard_info_get(wizard.interface):
- def _get_install(self, cr, uid, data, context):
- pool=pooler.get_pool(cr.dbname)
- mod_obj = pool.get('ir.module.module')
- ids = mod_obj.search(cr, uid, [
- ('state', 'in', ['to upgrade', 'to remove', 'to install'])])
- res = mod_obj.read(cr, uid, ids, ['name','state'], context)
- url = mod_obj.download(cr, uid, ids, download=False, context=context)
- return {'module_info': '\n'.join(map(lambda x: x['name']+' : '+x['state'], res)),
- 'module_download': '\n'.join(url)}
+ def _get_install(self, cr, uid, data, context):
+ pool=pooler.get_pool(cr.dbname)
+ mod_obj = pool.get('ir.module.module')
+ ids = mod_obj.search(cr, uid, [
+ ('state', 'in', ['to upgrade', 'to remove', 'to install'])])
+ res = mod_obj.read(cr, uid, ids, ['name','state'], context)
+ url = mod_obj.download(cr, uid, ids, download=False, context=context)
+ return {'module_info': '\n'.join(map(lambda x: x['name']+' : '+x['state'], res)),
+ 'module_download': '\n'.join(url)}
- def _check_upgrade_module(self,cr,uid,data,context):
- db, pool = pooler.get_db_and_pool(cr.dbname)
- cr = db.cursor()
- mod_obj = pool.get('ir.module.module')
- ids = mod_obj.search(cr, uid, [
- ('state', 'in', ['to upgrade', 'to remove', 'to install'])])
- if ids and len(ids):
- return 'next'
- else:
- return 'end'
+ def _check_upgrade_module(self,cr,uid,data,context):
+ db, pool = pooler.get_db_and_pool(cr.dbname)
+ cr = db.cursor()
+ mod_obj = pool.get('ir.module.module')
+ ids = mod_obj.search(cr, uid, [
+ ('state', 'in', ['to upgrade', 'to remove', 'to install'])])
+ if ids and len(ids):
+ return 'next'
+ else:
+ return 'end'
- def _upgrade_module(self, cr, uid, data, context):
- db, pool = pooler.get_db_and_pool(cr.dbname)
- cr = db.cursor()
- mod_obj = pool.get('ir.module.module')
- ids = mod_obj.search(cr, uid, [
- ('state', 'in', ['to upgrade', 'to remove', 'to install'])])
- mod_obj.download(cr, uid, ids, context=context)
- cr.commit()
- db, pool = pooler.restart_pool(cr.dbname, update_module=True)
+ def _upgrade_module(self, cr, uid, data, context):
+ db, pool = pooler.get_db_and_pool(cr.dbname)
+ cr = db.cursor()
+ mod_obj = pool.get('ir.module.module')
+ ids = mod_obj.search(cr, uid, [
+ ('state', 'in', ['to upgrade', 'to remove', 'to install'])])
+ mod_obj.download(cr, uid, ids, context=context)
+ cr.commit()
+ db, pool = pooler.restart_pool(cr.dbname, update_module=True)
- lang_obj=pool.get('res.lang')
- lang_ids=lang_obj.search(cr, uid, [])
- langs=lang_obj.browse(cr, uid, lang_ids)
- for lang in langs:
- if lang.code and lang.code != 'en_US':
- filename=os.path.join(tools.config["root_path"], "i18n", lang.code + ".csv")
- tools.trans_load(cr.dbname, filename, lang.code)
- return {}
+ lang_obj=pool.get('res.lang')
+ lang_ids=lang_obj.search(cr, uid, [])
+ langs=lang_obj.browse(cr, uid, lang_ids)
+ for lang in langs:
+ if lang.code and lang.code != 'en_US':
+ filename=os.path.join(tools.config["root_path"], "i18n", lang.code + ".csv")
+ tools.trans_load(cr.dbname, filename, lang.code)
+ return {}
- def _config(self, cr, uid, data, context=None):
- return {
+ def _config(self, cr, uid, data, context=None):
+ return {
'view_type': 'form',
"view_mode": 'form',
- 'res_model': 'ir.module.module.configuration.wizard',
- 'type': 'ir.actions.act_window',
- 'target':'new',
+ 'res_model': 'ir.module.module.configuration.wizard',
+ 'type': 'ir.actions.act_window',
+ 'target':'new',
}
- states = {
- 'init': {
- 'actions': [],
- 'result' : {'type': 'choice', 'next_state': _check_upgrade_module }
- },
- 'next': {
- 'actions': [_get_install],
- 'result': {'type':'form', 'arch':view_form, 'fields': view_field,
- 'state':[
- ('end', 'Cancel', 'gtk-cancel'),
- ('start', 'Start Upgrade', 'gtk-ok', True)
- ]
- }
- },
- 'start': {
- 'actions': [_upgrade_module],
- 'result': {'type':'form', 'arch':view_form_end, 'fields': {},
- 'state':[
- ('end', 'Close', 'gtk-close', True),
- ('config', 'Start configuration', 'gtk-ok', True)
- ]
- }
- },
- 'end': {
- 'actions': [],
- 'result': {'type':'form', 'arch':view_form_end, 'fields': {},
- 'state':[
- ('end', 'Close', 'gtk-close', True),
- ('config', 'Start configuration', 'gtk-ok', True)
- ]
- }
- },
- 'config':{
+ states = {
+ 'init': {
+ 'actions': [],
+ 'result' : {'type': 'choice', 'next_state': _check_upgrade_module }
+ },
+ 'next': {
+ 'actions': [_get_install],
+ 'result': {'type':'form', 'arch':view_form, 'fields': view_field,
+ 'state':[
+ ('end', 'Cancel', 'gtk-cancel'),
+ ('start', 'Start Upgrade', 'gtk-ok', True)
+ ]
+ }
+ },
+ 'start': {
+ 'actions': [_upgrade_module],
+ 'result': {'type':'form', 'arch':view_form_end, 'fields': {},
+ 'state':[
+ ('end', 'Close', 'gtk-close', True),
+ ('config', 'Start configuration', 'gtk-ok', True)
+ ]
+ }
+ },
+ 'end': {
+ 'actions': [],
+ 'result': {'type':'form', 'arch':view_form_end, 'fields': {},
+ 'state':[
+ ('end', 'Close', 'gtk-close', True),
+ ('config', 'Start configuration', 'gtk-ok', True)
+ ]
+ }
+ },
+ 'config':{
'result': {
'type': 'action',
'action': _config,
'state': 'end',
},
- }
- }
+ }
+ }
wizard_info_get('module.upgrade')
diff --git a/bin/addons/base/module/wizard/wizard_update_module.py b/bin/addons/base/module/wizard/wizard_update_module.py
index 94e12d28bad..924fec3eb46 100644
--- a/bin/addons/base/module/wizard/wizard_update_module.py
+++ b/bin/addons/base/module/wizard/wizard_update_module.py
@@ -34,70 +34,70 @@ import pooler
class wizard_update_module(wizard.interface):
- arch = '''<?xml version="1.0"?>
- <form string="Scan for new modules">
- <label string="This function will check for new modules in the 'addons' path and on module repositories:" colspan="4" align="0.0"/>
- <field name="repositories" colspan="4" nolabel="1"/>
- </form>'''
- fields = {
- 'repositories': {'type': 'text', 'string': 'Repositories', 'readonly': True},
- }
+ arch = '''<?xml version="1.0"?>
+ <form string="Scan for new modules">
+ <label string="This function will check for new modules in the 'addons' path and on module repositories:" colspan="4" align="0.0"/>
+ <field name="repositories" colspan="4" nolabel="1"/>
+ </form>'''
+ fields = {
+ 'repositories': {'type': 'text', 'string': 'Repositories', 'readonly': True},
+ }
- arch_module = '''<?xml version="1.0"?>
- <form string="New modules">
- <field name="update" colspan="4"/>
- <field name="add" colspan="4"/>
- </form>'''
+ arch_module = '''<?xml version="1.0"?>
+ <form string="New modules">
+ <field name="update" colspan="4"/>
+ <field name="add" colspan="4"/>
+ </form>'''
- fields_module = {
- 'update': {'type': 'integer', 'string': 'Number of modules updated', 'readonly': True},
- 'add': {'type': 'integer', 'string': 'Number of modules added', 'readonly': True},
- }
+ fields_module = {
+ 'update': {'type': 'integer', 'string': 'Number of modules updated', 'readonly': True},
+ 'add': {'type': 'integer', 'string': 'Number of modules added', 'readonly': True},
+ }
- def _update_module(self, cr, uid, data, context):
- update, add = pooler.get_pool(cr.dbname).get('ir.module.module').update_list(cr, uid)
- return {'update': update, 'add': add}
+ def _update_module(self, cr, uid, data, context):
+ update, add = pooler.get_pool(cr.dbname).get('ir.module.module').update_list(cr, uid)
+ return {'update': update, 'add': add}
- def _action_module_open(self, cr, uid, data, context):
- return {
- 'domain': str([]),
- 'name': 'Module List',
- 'view_type': 'form',
- 'view_mode': 'tree,form',
- 'res_model': 'ir.module.module',
- 'view_id': False,
- 'type': 'ir.actions.act_window'
- }
+ def _action_module_open(self, cr, uid, data, context):
+ return {
+ 'domain': str([]),
+ 'name': 'Module List',
+ 'view_type': 'form',
+ 'view_mode': 'tree,form',
+ 'res_model': 'ir.module.module',
+ 'view_id': False,
+ 'type': 'ir.actions.act_window'
+ }
- def _get_repositories(self, cr, uid, data, context):
- pool = pooler.get_pool(cr.dbname)
- repository_obj = pool.get('ir.module.repository')
- ids = repository_obj.search(cr, uid, [])
- res = repository_obj.read(cr, uid, ids, ['name', 'url'], context)
- return {'repositories': '\n'.join(map(lambda x: x['name']+': '+x['url'], res))}
+ def _get_repositories(self, cr, uid, data, context):
+ pool = pooler.get_pool(cr.dbname)
+ repository_obj = pool.get('ir.module.repository')
+ ids = repository_obj.search(cr, uid, [])
+ res = repository_obj.read(cr, uid, ids, ['name', 'url'], context)
+ return {'repositories': '\n'.join(map(lambda x: x['name']+': '+x['url'], res))}
- states = {
- 'init': {
- 'actions': [_get_repositories],
- 'result': {'type': 'form', 'arch': arch, 'fields': fields,
- 'state': [
- ('end', 'Cancel', 'gtk-cancel'),
- ('update', 'Check new modules', 'gtk-ok', True)
- ]
- }
- },
- 'update': {
- 'actions': [_update_module],
- 'result': {'type': 'form', 'arch': arch_module, 'fields': fields_module,
- 'state': [
- ('open_window', 'Ok', 'gtk-ok', True)
- ]
- }
- },
- 'open_window': {
- 'actions': [],
- 'result': {'type': 'action', 'action': _action_module_open, 'state':'end'}
- }
- }
+ states = {
+ 'init': {
+ 'actions': [_get_repositories],
+ 'result': {'type': 'form', 'arch': arch, 'fields': fields,
+ 'state': [
+ ('end', 'Cancel', 'gtk-cancel'),
+ ('update', 'Check new modules', 'gtk-ok', True)
+ ]
+ }
+ },
+ 'update': {
+ 'actions': [_update_module],
+ 'result': {'type': 'form', 'arch': arch_module, 'fields': fields_module,
+ 'state': [
+ ('open_window', 'Ok', 'gtk-ok', True)
+ ]
+ }
+ },
+ 'open_window': {
+ 'actions': [],
+ 'result': {'type': 'action', 'action': _action_module_open, 'state':'end'}
+ }
+ }
wizard_update_module('module.module.update')
diff --git a/bin/addons/base/res/bank.py b/bin/addons/base/res/bank.py
index 0917abc398a..dcae2f90b57 100644
--- a/bin/addons/base/res/bank.py
+++ b/bin/addons/base/res/bank.py
@@ -32,27 +32,27 @@ from osv import fields, osv
class Bank(osv.osv):
- _description='Bank'
- _name = 'res.bank'
- _columns = {
- 'name': fields.char('Name', size=128, required=True),
- 'code': fields.char('Code', size=64),
- 'street': fields.char('Street', size=128),
- 'street2': fields.char('Street2', size=128),
- 'zip': fields.char('Zip', change_default=True, size=24),
- 'city': fields.char('City', size=128),
- 'state': fields.many2one("res.country.state", 'State',
- domain="[('country_id', '=', country)]"),
- 'country': fields.many2one('res.country', 'Country'),
- 'email': fields.char('E-Mail', size=64),
- 'phone': fields.char('Phone', size=64),
- 'fax': fields.char('Fax', size=64),
- 'active': fields.boolean('Active'),
- 'bic': fields.char('BIC/Swift code', size=11,
- help="Bank Identifier Code"),
- }
- _defaults = {
- 'active': lambda *a: 1,
- }
+ _description='Bank'
+ _name = 'res.bank'
+ _columns = {
+ 'name': fields.char('Name', size=128, required=True),
+ 'code': fields.char('Code', size=64),
+ 'street': fields.char('Street', size=128),
+ 'street2': fields.char('Street2', size=128),
+ 'zip': fields.char('Zip', change_default=True, size=24),
+ 'city': fields.char('City', size=128),
+ 'state': fields.many2one("res.country.state", 'State',
+ domain="[('country_id', '=', country)]"),
+ 'country': fields.many2one('res.country', 'Country'),
+ 'email': fields.char('E-Mail', size=64),
+ 'phone': fields.char('Phone', size=64),
+ 'fax': fields.char('Fax', size=64),
+ 'active': fields.boolean('Active'),
+ 'bic': fields.char('BIC/Swift code', size=11,
+ help="Bank Identifier Code"),
+ }
+ _defaults = {
+ 'active': lambda *a: 1,
+ }
Bank()
diff --git a/bin/addons/base/res/country.py b/bin/addons/base/res/country.py
index 4a9d946bd04..603ee6fb5f4 100644
--- a/bin/addons/base/res/country.py
+++ b/bin/addons/base/res/country.py
@@ -32,76 +32,76 @@ from osv import fields, osv
class Country(osv.osv):
- _name = 'res.country'
- _description = 'Country'
- _columns = {
- 'name': fields.char('Country Name', size=64,
- help='The full name of the country.', required=True),
- 'code': fields.char('Country Code', size=2,
- help='The ISO country code in two chars.\n'
- 'You can use this field for quick search.', required=True),
- }
- _sql_constraints = [
- ('name_uniq', 'unique (name)',
- 'The name of the country must be unique !'),
- ('code_uniq', 'unique (code)',
- 'The code of the country must be unique !')
- ]
+ _name = 'res.country'
+ _description = 'Country'
+ _columns = {
+ 'name': fields.char('Country Name', size=64,
+ help='The full name of the country.', required=True),
+ 'code': fields.char('Country Code', size=2,
+ help='The ISO country code in two chars.\n'
+ 'You can use this field for quick search.', required=True),
+ }
+ _sql_constraints = [
+ ('name_uniq', 'unique (name)',
+ 'The name of the country must be unique !'),
+ ('code_uniq', 'unique (code)',
+ 'The code of the country must be unique !')
+ ]
- def name_search(self, cr, user, name='', args=None, operator='ilike',
- context=None, limit=80):
- if not args:
- args=[]
- if not context:
- context={}
- ids = False
- if len(name) == 2:
- ids = self.search(cr, user, [('code', '=', name.upper())] + args,
- limit=limit, context=context)
- if not ids:
- ids = self.search(cr, user, [('name', operator, name)] + args,
- limit=limit, context=context)
- return self.name_get(cr, user, ids, context)
- _order='name'
+ def name_search(self, cr, user, name='', args=None, operator='ilike',
+ context=None, limit=80):
+ if not args:
+ args=[]
+ if not context:
+ context={}
+ ids = False
+ if len(name) == 2:
+ ids = self.search(cr, user, [('code', '=', name.upper())] + args,
+ limit=limit, context=context)
+ if not ids:
+ ids = self.search(cr, user, [('name', operator, name)] + args,
+ limit=limit, context=context)
+ return self.name_get(cr, user, ids, context)
+ _order='name'
- def create(self, cursor, user, vals, context=None):
- if 'code' in vals:
- vals['code'] = vals['code'].upper()
- return super(Country, self).create(cursor, user, vals,
- context=context)
+ def create(self, cursor, user, vals, context=None):
+ if 'code' in vals:
+ vals['code'] = vals['code'].upper()
+ return super(Country, self).create(cursor, user, vals,
+ context=context)
- def write(self, cursor, user, ids, vals, context=None):
- if 'code' in vals:
- vals['code'] = vals['code'].upper()
- return super(Country, self).write(cursor, user, ids, vals,
- context=context)
+ def write(self, cursor, user, ids, vals, context=None):
+ if 'code' in vals:
+ vals['code'] = vals['code'].upper()
+ return super(Country, self).write(cursor, user, ids, vals,
+ context=context)
Country()
class CountryState(osv.osv):
- _description="Country state"
- _name = 'res.country.state'
- _columns = {
- 'country_id': fields.many2one('res.country', 'Country',
- required=True),
- 'name': fields.char('State Name', size=64, required=True),
- 'code': fields.char('State Code', size=3, required=True),
- }
- def name_search(self, cr, user, name='', args=None, operator='ilike',
- context=None, limit=80):
- if not args:
- args = []
- if not context:
- context = {}
- ids = self.search(cr, user, [('code', '=', name)] + args, limit=limit,
- context=context)
- if not ids:
- ids = self.search(cr, user, [('name', operator, name)] + args,
- limit=limit, context=context)
- return self.name_get(cr, user, ids, context)
+ _description="Country state"
+ _name = 'res.country.state'
+ _columns = {
+ 'country_id': fields.many2one('res.country', 'Country',
+ required=True),
+ 'name': fields.char('State Name', size=64, required=True),
+ 'code': fields.char('State Code', size=3, required=True),
+ }
+ def name_search(self, cr, user, name='', args=None, operator='ilike',
+ context=None, limit=80):
+ if not args:
+ args = []
+ if not context:
+ context = {}
+ ids = self.search(cr, user, [('code', '=', name)] + args, limit=limit,
+ context=context)
+ if not ids:
+ ids = self.search(cr, user, [('name', operator, name)] + args,
+ limit=limit, context=context)
+ return self.name_get(cr, user, ids, context)
- _order = 'code'
+ _order = 'code'
CountryState()
diff --git a/bin/addons/base/res/ir_property.py b/bin/addons/base/res/ir_property.py
index 6ab36df6cf1..57f5c54db83 100644
--- a/bin/addons/base/res/ir_property.py
+++ b/bin/addons/base/res/ir_property.py
@@ -34,52 +34,52 @@ from osv import osv,fields
# -------------------------------------------------------------------------
def _models_get2(self, cr, uid, context={}):
- obj = self.pool.get('ir.model.fields')
- ids = obj.search(cr, uid, [('view_load','=',1)])
- res = []
- done = {}
- for o in obj.browse(cr, uid, ids, context=context):
- if o.relation not in done:
- res.append( [o.relation, o.relation])
- done[o.relation] = True
- return res
+ obj = self.pool.get('ir.model.fields')
+ ids = obj.search(cr, uid, [('view_load','=',1)])
+ res = []
+ done = {}
+ for o in obj.browse(cr, uid, ids, context=context):
+ if o.relation not in done:
+ res.append( [o.relation, o.relation])
+ done[o.relation] = True
+ return res
def _models_get(self, cr, uid, context={}):
- obj = self.pool.get('ir.model.fields')
- ids = obj.search(cr, uid, [('view_load','=',1)])
- res = []
- done = {}
- for o in obj.browse(cr, uid, ids, context=context):
- if o.model_id.id not in done:
- res.append( [o.model_id.model, o.model_id.name])
- done[o.model_id.id] = True
- return res
+ obj = self.pool.get('ir.model.fields')
+ ids = obj.search(cr, uid, [('view_load','=',1)])
+ res = []
+ done = {}
+ for o in obj.browse(cr, uid, ids, context=context):
+ if o.model_id.id not in done:
+ res.append( [o.model_id.model, o.model_id.name])
+ done[o.model_id.id] = True
+ return res
class ir_property(osv.osv):
- _name = 'ir.property'
- _columns = {
- 'name': fields.char('Name', size=128),
- 'value': fields.reference('Value', selection=_models_get2, size=128),
- 'res_id': fields.reference('Resource', selection=_models_get, size=128),
- 'company_id': fields.many2one('res.company', 'Company'),
- 'fields_id': fields.many2one('ir.model.fields', 'Fields', ondelete='cascade', required=True)
- }
- def unlink(self, cr, uid, ids, context={}):
- if ids:
- cr.execute('delete from ir_model_fields where id in (select fields_id from ir_property where (fields_id is not null) and (id in ('+','.join(map(str,ids))+')))')
- res = super(ir_property, self).unlink(cr, uid, ids, context)
- return res
+ _name = 'ir.property'
+ _columns = {
+ 'name': fields.char('Name', size=128),
+ 'value': fields.reference('Value', selection=_models_get2, size=128),
+ 'res_id': fields.reference('Resource', selection=_models_get, size=128),
+ 'company_id': fields.many2one('res.company', 'Company'),
+ 'fields_id': fields.many2one('ir.model.fields', 'Fields', ondelete='cascade', required=True)
+ }
+ def unlink(self, cr, uid, ids, context={}):
+ if ids:
+ cr.execute('delete from ir_model_fields where id in (select fields_id from ir_property where (fields_id is not null) and (id in ('+','.join(map(str,ids))+')))')
+ res = super(ir_property, self).unlink(cr, uid, ids, context)
+ return res
- def get(self, cr, uid, name, model, res_id=False, context={}):
- cr.execute('select id from ir_model_fields where name=%s and model=%s', (name, model))
- res = cr.fetchone()
- if res:
- ucid = self.pool.get('res.users').browse(cr, uid, uid).company_id.id
- nid = self.search(cr, uid, [('fields_id','=',res[0]),('res_id','=',res_id),('company_id','=',ucid)])
- if nid:
- d = self.browse(cr, uid, nid[0], context).value
- return (d and int(d.split(',')[1])) or False
- return False
+ def get(self, cr, uid, name, model, res_id=False, context={}):
+ cr.execute('select id from ir_model_fields where name=%s and model=%s', (name, model))
+ res = cr.fetchone()
+ if res:
+ ucid = self.pool.get('res.users').browse(cr, uid, uid).company_id.id
+ nid = self.search(cr, uid, [('fields_id','=',res[0]),('res_id','=',res_id),('company_id','=',ucid)])
+ if nid:
+ d = self.browse(cr, uid, nid[0], context).value
+ return (d and int(d.split(',')[1])) or False
+ return False
ir_property()
diff --git a/bin/addons/base/res/partner/crm.py b/bin/addons/base/res/partner/crm.py
index 3bac895fed4..3fecb9a3388 100644
--- a/bin/addons/base/res/partner/crm.py
+++ b/bin/addons/base/res/partner/crm.py
@@ -35,72 +35,72 @@ from osv import fields,osv
# Sale/Purchase Canal, Media
#
class res_partner_canal(osv.osv):
- _name = "res.partner.canal"
- _description = "Channels"
- _columns = {
- 'name': fields.char('Channel Name',size=64, required=True),
- 'active': fields.boolean('Active'),
- }
- _defaults = {
- 'active': lambda *a: 1,
- }
+ _name = "res.partner.canal"
+ _description = "Channels"
+ _columns = {
+ 'name': fields.char('Channel Name',size=64, required=True),
+ 'active': fields.boolean('Active'),
+ }
+ _defaults = {
+ 'active': lambda *a: 1,
+ }
res_partner_canal()
#
# Partner: State of Mind
#
class res_partner_som(osv.osv):
- _name = "res.partner.som"
- _columns = {
- 'name': fields.char('State of Mind',size=64, required=True),
- 'factor': fields.float('Factor', required=True)
- }
+ _name = "res.partner.som"
+ _columns = {
+ 'name': fields.char('State of Mind',size=64, required=True),
+ 'factor': fields.float('Factor', required=True)
+ }
res_partner_som()
def _links_get(self, cr, uid, context={}):
- obj = self.pool.get('res.request.link')
- ids = obj.search(cr, uid, [])
- res = obj.read(cr, uid, ids, ['object', 'name'], context)
- return [(r['object'], r['name']) for r in res]
+ obj = self.pool.get('res.request.link')
+ ids = obj.search(cr, uid, [])
+ res = obj.read(cr, uid, ids, ['object', 'name'], context)
+ return [(r['object'], r['name']) for r in res]
class res_partner_event(osv.osv):
- _name = "res.partner.event"
- _columns = {
- 'name': fields.char('Events',size=64, required=True),
- 'som': fields.many2one('res.partner.som', 'State of Mind'),
- 'description': fields.text('Description'),
- 'planned_cost': fields.float('Planned Cost'),
- 'planned_revenue': fields.float('Planned Revenue'),
- 'probability': fields.float('Probability (0.50)'),
- 'document': fields.reference('Document', selection=_links_get, size=128),
- 'partner_id': fields.many2one('res.partner', 'Partner', select=True),
- 'date': fields.datetime('Date', size=16),
- 'user_id': fields.many2one('res.users', 'User'),
- 'canal_id': fields.many2one('res.partner.canal', 'Channel'),
- 'partner_type': fields.selection([('customer','Customer'),('retailer','Retailer'),('prospect','Commercial Prospect')], 'Partner Relation'),
- 'type': fields.selection([('sale','Sale Opportunity'),('purchase','Purchase Offer'),('prospect','Prospect Contact')], 'Type of Event'),
- 'event_ical_id': fields.char('iCal id', size=64),
- }
- _order = 'date desc'
- _defaults = {
- 'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
- }
+ _name = "res.partner.event"
+ _columns = {
+ 'name': fields.char('Events',size=64, required=True),
+ 'som': fields.many2one('res.partner.som', 'State of Mind'),
+ 'description': fields.text('Description'),
+ 'planned_cost': fields.float('Planned Cost'),
+ 'planned_revenue': fields.float('Planned Revenue'),
+ 'probability': fields.float('Probability (0.50)'),
+ 'document': fields.reference('Document', selection=_links_get, size=128),
+ 'partner_id': fields.many2one('res.partner', 'Partner', select=True),
+ 'date': fields.datetime('Date', size=16),
+ 'user_id': fields.many2one('res.users', 'User'),
+ 'canal_id': fields.many2one('res.partner.canal', 'Channel'),
+ 'partner_type': fields.selection([('customer','Customer'),('retailer','Retailer'),('prospect','Commercial Prospect')], 'Partner Relation'),
+ 'type': fields.selection([('sale','Sale Opportunity'),('purchase','Purchase Offer'),('prospect','Prospect Contact')], 'Type of Event'),
+ 'event_ical_id': fields.char('iCal id', size=64),
+ }
+ _order = 'date desc'
+ _defaults = {
+ 'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
+ }
res_partner_event()
class res_partner_event_type(osv.osv):
- _name = "res.partner.event.type"
- _description = "Partner Events"
- _columns = {
- 'name': fields.char('Event Type',size=64, required=True),
- 'key': fields.char('Key', size=64, required=True),
- 'active': fields.boolean('Active'),
- }
- _defaults = {
- 'active': lambda *a: 1
- }
- def check(self, cr, uid, key, context={}):
- return self.search(cr, uid, [('key','=',key)])
+ _name = "res.partner.event.type"
+ _description = "Partner Events"
+ _columns = {
+ 'name': fields.char('Event Type',size=64, required=True),
+ 'key': fields.char('Key', size=64, required=True),
+ 'active': fields.boolean('Active'),
+ }
+ _defaults = {
+ 'active': lambda *a: 1
+ }
+ def check(self, cr, uid, key, context={}):
+ return self.search(cr, uid, [('key','=',key)])
res_partner_event_type()
diff --git a/bin/addons/base/res/partner/partner.py b/bin/addons/base/res/partner/partner.py
index 833237b883f..c0edc509da2 100644
--- a/bin/addons/base/res/partner/partner.py
+++ b/bin/addons/base/res/partner/partner.py
@@ -35,399 +35,399 @@ import ir
import pooler
class res_partner_function(osv.osv):
- _name = 'res.partner.function'
- _description = 'Function of the contact'
- _columns = {
- 'name': fields.char('Function name', size=64, required=True),
- 'code': fields.char('Code', size=8),
- }
- _order = 'name'
+ _name = 'res.partner.function'
+ _description = 'Function of the contact'
+ _columns = {
+ 'name': fields.char('Function name', size=64, required=True),
+ 'code': fields.char('Code', size=8),
+ }
+ _order = 'name'
res_partner_function()
class res_payterm(osv.osv):
- _description = 'Payment term'
- _name = 'res.payterm'
- _columns = {
- 'name': fields.char('Payment term (short name)', size=64),
- }
+ _description = 'Payment term'
+ _name = 'res.payterm'
+ _columns = {
+ 'name': fields.char('Payment term (short name)', size=64),
+ }
res_payterm()
class res_partner_category(osv.osv):
- def name_get(self, cr, uid, ids, context={}):
- if not len(ids):
- return []
- reads = self.read(cr, uid, ids, ['name','parent_id'], context)
- res = []
- for record in reads:
- name = record['name']
- if record['parent_id']:
- name = record['parent_id'][1]+' / '+name
- res.append((record['id'], name))
- return res
-
- def _name_get_fnc(self, cr, uid, ids, prop, unknow_none, unknow_dict):
- res = self.name_get(cr, uid, ids)
- return dict(res)
- def _check_recursion(self, cr, uid, ids):
- level = 100
- while len(ids):
- cr.execute('select distinct parent_id from res_partner_category where id in ('+','.join(map(str,ids))+')')
- ids = filter(None, map(lambda x:x[0], cr.fetchall()))
- if not level:
- return False
- level -= 1
- return True
-
- _description='Partner Categories'
- _name = 'res.partner.category'
- _columns = {
- 'name': fields.char('Category Name', required=True, size=64),
- 'parent_id': fields.many2one('res.partner.category', 'Parent Category', select=True),
- 'complete_name': fields.function(_name_get_fnc, method=True, type="char", string='Name'),
- 'child_ids': fields.one2many('res.partner.category', 'parent_id', 'Childs Category'),
- 'active' : fields.boolean('Active', help="The active field allows you to hide the category, without removing it."),
- }
- _constraints = [
- (_check_recursion, 'Error ! You can not create recursive categories.', ['parent_id'])
- ]
- _defaults = {
- 'active' : lambda *a: 1,
- }
- _order = 'parent_id,name'
+ def name_get(self, cr, uid, ids, context={}):
+ if not len(ids):
+ return []
+ reads = self.read(cr, uid, ids, ['name','parent_id'], context)
+ res = []
+ for record in reads:
+ name = record['name']
+ if record['parent_id']:
+ name = record['parent_id'][1]+' / '+name
+ res.append((record['id'], name))
+ return res
+
+ def _name_get_fnc(self, cr, uid, ids, prop, unknow_none, unknow_dict):
+ res = self.name_get(cr, uid, ids)
+ return dict(res)
+ def _check_recursion(self, cr, uid, ids):
+ level = 100
+ while len(ids):
+ cr.execute('select distinct parent_id from res_partner_category where id in ('+','.join(map(str,ids))+')')
+ ids = filter(None, map(lambda x:x[0], cr.fetchall()))
+ if not level:
+ return False
+ level -= 1
+ return True
+
+ _description='Partner Categories'
+ _name = 'res.partner.category'
+ _columns = {
+ 'name': fields.char('Category Name', required=True, size=64),
+ 'parent_id': fields.many2one('res.partner.category', 'Parent Category', select=True),
+ 'complete_name': fields.function(_name_get_fnc, method=True, type="char", string='Name'),
+ 'child_ids': fields.one2many('res.partner.category', 'parent_id', 'Childs Category'),
+ 'active' : fields.boolean('Active', help="The active field allows you to hide the category, without removing it."),
+ }
+ _constraints = [
+ (_check_recursion, 'Error ! You can not create recursive categories.', ['parent_id'])
+ ]
+ _defaults = {
+ 'active' : lambda *a: 1,
+ }
+ _order = 'parent_id,name'
res_partner_category()
class res_partner_title(osv.osv):
- _name = 'res.partner.title'
- _columns = {
- 'name': fields.char('Title', required=True, size=46, translate=True),
- 'shortcut': fields.char('Shortcut', required=True, size=16),
- 'domain': fields.selection([('partner','Partner'),('contact','Contact')], 'Domain', required=True, size=24)
- }
- _order = 'name'
+ _name = 'res.partner.title'
+ _columns = {
+ 'name': fields.char('Title', required=True, size=46, translate=True),
+ 'shortcut': fields.char('Shortcut', required=True, size=16),
+ 'domain': fields.selection([('partner','Partner'),('contact','Contact')], 'Domain', required=True, size=24)
+ }
+ _order = 'name'
res_partner_title()
def _contact_title_get(self, cr, uid, context={}):
- obj = self.pool.get('res.partner.title')
- ids = obj.search(cr, uid, [('domain', '=', 'contact')])
- res = obj.read(cr, uid, ids, ['shortcut','name'], context)
- return [(r['shortcut'], r['name']) for r in res]
+ obj = self.pool.get('res.partner.title')
+ ids = obj.search(cr, uid, [('domain', '=', 'contact')])
+ res = obj.read(cr, uid, ids, ['shortcut','name'], context)
+ return [(r['shortcut'], r['name']) for r in res]
def _partner_title_get(self, cr, uid, context={}):
- obj = self.pool.get('res.partner.title')
- ids = obj.search(cr, uid, [('domain', '=', 'partner')])
- res = obj.read(cr, uid, ids, ['shortcut','name'], context)
- return [(r['shortcut'], r['name']) for r in res]
+ obj = self.pool.get('res.partner.title')
+ ids = obj.search(cr, uid, [('domain', '=', 'partner')])
+ res = obj.read(cr, uid, ids, ['shortcut','name'], context)
+ return [(r['shortcut'], r['name']) for r in res]
def _lang_get(self, cr, uid, context={}):
- obj = self.pool.get('res.lang')
- ids = obj.search(cr, uid, [])
- res = obj.read(cr, uid, ids, ['code', 'name'], context)
- res = [(r['code'], r['name']) for r in res]
- return res + [(False, '')]
+ obj = self.pool.get('res.lang')
+ ids = obj.search(cr, uid, [])
+ res = obj.read(cr, uid, ids, ['code', 'name'], context)
+ res = [(r['code'], r['name']) for r in res]
+ return res + [(False, '')]
class res_partner(osv.osv):
- _description='Partner'
- _name = "res.partner"
- _order = "name"
- _columns = {
- 'name': fields.char('Name', size=128, required=True, select=True),
- 'date': fields.date('Date', select=1),
- 'title': fields.selection(_partner_title_get, 'Title', size=32),
- 'parent_id': fields.many2one('res.partner','Main Company', select=2),
- 'child_ids': fields.one2many('res.partner', 'parent_id', 'Partner Ref.'),
- 'ref': fields.char('Code', size=64),
- 'lang': fields.selection(_lang_get, 'Language', size=5),
- 'user_id': fields.many2one('res.users', 'Dedicated Salesman', help='The internal user that is in charge of communicating with this partner if any.'),
- 'responsible': fields.many2one('res.users', 'Users'),
- 'vat': fields.char('VAT',size=32 ,help="Value Added Tax number"),
- 'bank_ids': fields.one2many('res.partner.bank', 'partner_id', 'Banks'),
- 'website': fields.char('Website',size=64),
- 'comment': fields.text('Notes'),
- 'address': fields.one2many('res.partner.address', 'partner_id', 'Contacts'),
- 'category_id': fields.many2many('res.partner.category', 'res_partner_category_rel', 'partner_id', 'category_id', 'Categories'),
- 'events': fields.one2many('res.partner.event', 'partner_id', 'Events'),
- 'credit_limit': fields.float(string='Credit Limit'),
- 'ean13': fields.char('EAN13', size=13),
- 'active': fields.boolean('Active'),
- }
- _defaults = {
- 'active': lambda *a: 1,
- }
- _sql_constraints = [
- ('name_uniq', 'unique (name)', 'The name of the partner must be unique !')
- ]
-
- def copy(self, cr, uid, id, default=None, context={}):
- name = self.read(cr, uid, [id], ['name'])[0]['name']
- default.update({'name': name+' (copy)'})
- return super(res_partner, self).copy(cr, uid, id, default, context)
-
- def _check_ean_key(self, cr, uid, ids):
- for partner_o in pooler.get_pool(cr.dbname).get('res.partner').read(cr, uid, ids, ['ean13',]):
- thisean=partner_o['ean13']
- if thisean and thisean!='':
- if len(thisean)!=13:
- return False
- sum=0
- for i in range(12):
- if not (i % 2):
- sum+=int(thisean[i])
- else:
- sum+=3*int(thisean[i])
- if math.ceil(sum/10.0)*10-sum!=int(thisean[12]):
- return False
- return True
-
-# _constraints = [(_check_ean_key, 'Error: Invalid ean code', ['ean13'])]
-
- def name_get(self, cr, uid, ids, context={}):
- if not len(ids):
- return []
- if context.get('show_ref', False):
- rec_name = 'ref'
- else:
- rec_name = 'name'
-
- res = [(r['id'], r[rec_name]) for r in self.read(cr, uid, ids, [rec_name], context)]
- return res
-
- def name_search(self, cr, uid, name, args=None, operator='ilike', context=None, limit=80):
- if not args:
- args=[]
- if not context:
- context={}
- if name:
- ids = self.search(cr, uid, [('ref', '=', name)] + args, limit=limit, context=context)
- if not ids:
- ids = self.search(cr, uid, [('name', operator, name)] + args, limit=limit, context=context)
- else:
- ids = self.search(cr, uid, args, limit=limit, context=context)
- return self.name_get(cr, uid, ids, context)
-
- def _email_send(self, cr, uid, ids, email_from, subject, body, on_error=None):
- partners = self.browse(cr, uid, ids)
- for partner in partners:
- if len(partner.address):
- if partner.address[0].email:
- tools.email_send(email_from, [partner.address[0].email], subject, body, on_error)
- return True
-
- def email_send(self, cr, uid, ids, email_from, subject, body, on_error=''):
- while len(ids):
- self.pool.get('ir.cron').create(cr, uid, {
- 'name': 'Send Partner Emails',
- 'user_id': uid,
-# 'nextcall': False,
- 'model': 'res.partner',
- 'function': '_email_send',
- 'args': repr([ids[:16], email_from, subject, body, on_error])
- })
- ids = ids[16:]
- return True
-
- def address_get(self, cr, uid, ids, adr_pref=['default']):
- cr.execute('select type,id from res_partner_address where partner_id in ('+','.join(map(str,ids))+')')
- res = cr.fetchall()
- adr = dict(res)
- # get the id of the (first) default address if there is one,
- # otherwise get the id of the first address in the list
- if res:
- default_address = adr.get('default', res[0][1])
- else:
- default_address = False
- result = {}
- for a in adr_pref:
- result[a] = adr.get(a, default_address)
- return result
-
- def gen_next_ref(self, cr, uid, ids):
- if len(ids) != 1:
- return True
-
- # compute the next number ref
- cr.execute("select ref from res_partner where ref is not null order by char_length(ref) desc, ref desc limit 1")
- res = cr.dictfetchall()
- ref = res and res[0]['ref'] or '0'
- try:
- nextref = int(ref)+1
- except e:
- 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]))
- return True
+ _description='Partner'
+ _name = "res.partner"
+ _order = "name"
+ _columns = {
+ 'name': fields.char('Name', size=128, required=True, select=True),
+ 'date': fields.date('Date', select=1),
+ 'title': fields.selection(_partner_title_get, 'Title', size=32),
+ 'parent_id': fields.many2one('res.partner','Main Company', select=2),
+ 'child_ids': fields.one2many('res.partner', 'parent_id', 'Partner Ref.'),
+ 'ref': fields.char('Code', size=64),
+ 'lang': fields.selection(_lang_get, 'Language', size=5),
+ 'user_id': fields.many2one('res.users', 'Dedicated Salesman', help='The internal user that is in charge of communicating with this partner if any.'),
+ 'responsible': fields.many2one('res.users', 'Users'),
+ 'vat': fields.char('VAT',size=32 ,help="Value Added Tax number"),
+ 'bank_ids': fields.one2many('res.partner.bank', 'partner_id', 'Banks'),
+ 'website': fields.char('Website',size=64),
+ 'comment': fields.text('Notes'),
+ 'address': fields.one2many('res.partner.address', 'partner_id', 'Contacts'),
+ 'category_id': fields.many2many('res.partner.category', 'res_partner_category_rel', 'partner_id', 'category_id', 'Categories'),
+ 'events': fields.one2many('res.partner.event', 'partner_id', 'Events'),
+ 'credit_limit': fields.float(string='Credit Limit'),
+ 'ean13': fields.char('EAN13', size=13),
+ 'active': fields.boolean('Active'),
+ }
+ _defaults = {
+ 'active': lambda *a: 1,
+ }
+ _sql_constraints = [
+ ('name_uniq', 'unique (name)', 'The name of the partner must be unique !')
+ ]
+
+ def copy(self, cr, uid, id, default=None, context={}):
+ name = self.read(cr, uid, [id], ['name'])[0]['name']
+ default.update({'name': name+' (copy)'})
+ return super(res_partner, self).copy(cr, uid, id, default, context)
+
+ def _check_ean_key(self, cr, uid, ids):
+ for partner_o in pooler.get_pool(cr.dbname).get('res.partner').read(cr, uid, ids, ['ean13',]):
+ thisean=partner_o['ean13']
+ if thisean and thisean!='':
+ if len(thisean)!=13:
+ return False
+ sum=0
+ for i in range(12):
+ if not (i % 2):
+ sum+=int(thisean[i])
+ else:
+ sum+=3*int(thisean[i])
+ if math.ceil(sum/10.0)*10-sum!=int(thisean[12]):
+ return False
+ return True
+
+# _constraints = [(_check_ean_key, 'Error: Invalid ean code', ['ean13'])]
+
+ def name_get(self, cr, uid, ids, context={}):
+ if not len(ids):
+ return []
+ if context.get('show_ref', False):
+ rec_name = 'ref'
+ else:
+ rec_name = 'name'
+
+ res = [(r['id'], r[rec_name]) for r in self.read(cr, uid, ids, [rec_name], context)]
+ return res
+
+ def name_search(self, cr, uid, name, args=None, operator='ilike', context=None, limit=80):
+ if not args:
+ args=[]
+ if not context:
+ context={}
+ if name:
+ ids = self.search(cr, uid, [('ref', '=', name)] + args, limit=limit, context=context)
+ if not ids:
+ ids = self.search(cr, uid, [('name', operator, name)] + args, limit=limit, context=context)
+ else:
+ ids = self.search(cr, uid, args, limit=limit, context=context)
+ return self.name_get(cr, uid, ids, context)
+
+ def _email_send(self, cr, uid, ids, email_from, subject, body, on_error=None):
+ partners = self.browse(cr, uid, ids)
+ for partner in partners:
+ if len(partner.address):
+ if partner.address[0].email:
+ tools.email_send(email_from, [partner.address[0].email], subject, body, on_error)
+ return True
+
+ def email_send(self, cr, uid, ids, email_from, subject, body, on_error=''):
+ while len(ids):
+ self.pool.get('ir.cron').create(cr, uid, {
+ 'name': 'Send Partner Emails',
+ 'user_id': uid,
+# 'nextcall': False,
+ 'model': 'res.partner',
+ 'function': '_email_send',
+ 'args': repr([ids[:16], email_from, subject, body, on_error])
+ })
+ ids = ids[16:]
+ return True
+
+ def address_get(self, cr, uid, ids, adr_pref=['default']):
+ cr.execute('select type,id from res_partner_address where partner_id in ('+','.join(map(str,ids))+')')
+ res = cr.fetchall()
+ adr = dict(res)
+ # get the id of the (first) default address if there is one,
+ # otherwise get the id of the first address in the list
+ if res:
+ default_address = adr.get('default', res[0][1])
+ else:
+ default_address = False
+ result = {}
+ for a in adr_pref:
+ result[a] = adr.get(a, default_address)
+ return result
+
+ def gen_next_ref(self, cr, uid, ids):
+ if len(ids) != 1:
+ return True
+
+ # compute the next number ref
+ cr.execute("select ref from res_partner where ref is not null order by char_length(ref) desc, ref desc limit 1")
+ res = cr.dictfetchall()
+ ref = res and res[0]['ref'] or '0'
+ try:
+ nextref = int(ref)+1
+ except e:
+ 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]))
+ return True
res_partner()
class res_partner_address(osv.osv):
- _description ='Partner Contact'
- _name = 'res.partner.address'
- _order = 'id'
- _columns = {
- 'partner_id': fields.many2one('res.partner', 'Partner', required=True, ondelete='cascade', select=True),
- 'type': fields.selection( [ ('default','Default'),('invoice','Invoice'), ('delivery','Delivery'), ('contact','Contact'), ('other','Other') ],'Address Type'),
- 'function': fields.many2one('res.partner.function', 'Function'),
- 'title': fields.selection(_contact_title_get, 'Title', size=32),
- 'name': fields.char('Contact Name', size=64),
- 'street': fields.char('Street', size=128),
- 'street2': fields.char('Street2', size=128),
- 'zip': fields.char('Zip', change_default=True, size=24),
- 'city': fields.char('City', size=128),
- 'state_id': fields.many2one("res.country.state", 'State', change_default=True, domain="[('country_id','=',country_id)]"),
- 'country_id': fields.many2one('res.country', 'Country', change_default=True),
- 'email': fields.char('E-Mail', size=240),
- 'phone': fields.char('Phone', size=64),
- 'fax': fields.char('Fax', size=64),
- 'mobile': fields.char('Mobile', size=64),
- 'birthdate': fields.char('Birthdate', size=64),
- 'active': fields.boolean('Active'),
- }
- _defaults = {
- 'active': lambda *a: 1,
- }
-
- def name_get(self, cr, user, ids, context={}):
- if not len(ids):
- return []
- res = []
- for r in self.read(cr, user, ids, ['name','zip','city','partner_id', 'street']):
- if context.get('contact_display', 'contact')=='partner':
- res.append((r['id'], r['partner_id'][1]))
- else:
- addr = str(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 '')
- res.append((r['id'], addr.strip() or '/'))
- return res
-
- def name_search(self, cr, user, name, args=None, operator='ilike', context=None, limit=80):
- if not args:
- args=[]
- if not context:
- context={}
- if context.get('contact_display', 'contact')=='partner':
- ids = self.search(cr, user, [('partner_id',operator,name)], limit=limit, context=context)
- else:
- ids = self.search(cr, user, [('zip','=',name)] + args, limit=limit, context=context)
- if not ids:
- ids = self.search(cr, user, [('city',operator,name)] + args, limit=limit, context=context)
- if name:
- ids += self.search(cr, user, [('name',operator,name)] + args, limit=limit, context=context)
- ids += self.search(cr, user, [('partner_id',operator,name)] + args, limit=limit, context=context)
- return self.name_get(cr, user, ids, context=context)
+ _description ='Partner Contact'
+ _name = 'res.partner.address'
+ _order = 'id'
+ _columns = {
+ 'partner_id': fields.many2one('res.partner', 'Partner', required=True, ondelete='cascade', select=True),
+ 'type': fields.selection( [ ('default','Default'),('invoice','Invoice'), ('delivery','Delivery'), ('contact','Contact'), ('other','Other') ],'Address Type'),
+ 'function': fields.many2one('res.partner.function', 'Function'),
+ 'title': fields.selection(_contact_title_get, 'Title', size=32),
+ 'name': fields.char('Contact Name', size=64),
+ 'street': fields.char('Street', size=128),
+ 'street2': fields.char('Street2', size=128),
+ 'zip': fields.char('Zip', change_default=True, size=24),
+ 'city': fields.char('City', size=128),
+ 'state_id': fields.many2one("res.country.state", 'State', change_default=True, domain="[('country_id','=',country_id)]"),
+ 'country_id': fields.many2one('res.country', 'Country', change_default=True),
+ 'email': fields.char('E-Mail', size=240),
+ 'phone': fields.char('Phone', size=64),
+ 'fax': fields.char('Fax', size=64),
+ 'mobile': fields.char('Mobile', size=64),
+ 'birthdate': fields.char('Birthdate', size=64),
+ 'active': fields.boolean('Active'),
+ }
+ _defaults = {
+ 'active': lambda *a: 1,
+ }
+
+ def name_get(self, cr, user, ids, context={}):
+ if not len(ids):
+ return []
+ res = []
+ for r in self.read(cr, user, ids, ['name','zip','city','partner_id', 'street']):
+ if context.get('contact_display', 'contact')=='partner':
+ res.append((r['id'], r['partner_id'][1]))
+ else:
+ addr = str(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 '')
+ res.append((r['id'], addr.strip() or '/'))
+ return res
+
+ def name_search(self, cr, user, name, args=None, operator='ilike', context=None, limit=80):
+ if not args:
+ args=[]
+ if not context:
+ context={}
+ if context.get('contact_display', 'contact')=='partner':
+ ids = self.search(cr, user, [('partner_id',operator,name)], limit=limit, context=context)
+ else:
+ ids = self.search(cr, user, [('zip','=',name)] + args, limit=limit, context=context)
+ if not ids:
+ ids = self.search(cr, user, [('city',operator,name)] + args, limit=limit, context=context)
+ if name:
+ ids += self.search(cr, user, [('name',operator,name)] + args, limit=limit, context=context)
+ ids += self.search(cr, user, [('partner_id',operator,name)] + args, limit=limit, context=context)
+ return self.name_get(cr, user, ids, context=context)
res_partner_address()
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),
- 'code': fields.char('Code', size=64, required=True),
- 'field_ids': fields.one2many('res.partner.bank.type.field', 'bank_type_id', 'Type fields'),
- }
+ _description='Bank Account Type'
+ _name = 'res.partner.bank.type'
+ _columns = {
+ 'name': fields.char('Name', size=64, required=True),
+ 'code': fields.char('Code', size=64, required=True),
+ 'field_ids': fields.one2many('res.partner.bank.type.field', 'bank_type_id', 'Type fields'),
+ }
res_partner_bank_type()
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),
- 'bank_type_id': fields.many2one('res.partner.bank.type', 'Bank type', required=True, ondelete='cascade'),
- 'required': fields.boolean('Required'),
- 'readonly': fields.boolean('Readonly'),
- 'size': fields.integer('Max. Size'),
- }
+ _description='Bank type fields'
+ _name = 'res.partner.bank.type.field'
+ _columns = {
+ 'name': fields.char('Field name', size=64, required=True),
+ 'bank_type_id': fields.many2one('res.partner.bank.type', 'Bank type', required=True, ondelete='cascade'),
+ 'required': fields.boolean('Required'),
+ 'readonly': fields.boolean('Readonly'),
+ 'size': fields.integer('Max. Size'),
+ }
res_partner_bank_type_fields()
class res_partner_bank(osv.osv):
- '''Bank Accounts'''
- _name = "res.partner.bank"
- _rec_name = "state"
- _description = __doc__
- _order = 'sequence'
-
- def _bank_type_get(self, cr, uid, context=None):
- bank_type_obj = self.pool.get('res.partner.bank.type')
-
- result = []
- type_ids = bank_type_obj.search(cr, uid, [])
- bank_types = bank_type_obj.browse(cr, uid, type_ids)
- for bank_type in bank_types:
- result.append((bank_type.code, bank_type.name))
- return result
-
- def _default_value(self, cursor, user, field, context=None):
- if field in ('country_id', 'state_id'):
- value = False
- else:
- value = ''
- if not context.get('address', False):
- return value
- for ham, spam, address in context['address']:
- if address.get('type', False) == 'default':
- return address.get(field, value)
- elif not address.get('type', False):
- value = address.get(field, value)
- return value
-
- _columns = {
- 'name': fields.char('Description', size=128),
- 'acc_number': fields.char('Account number', size=64, required=False),
- 'bank': fields.many2one('res.bank', 'Bank'),
- 'owner_name': fields.char('Account owner', size=64),
- 'street': fields.char('Street', size=128),
- 'zip': fields.char('Zip', change_default=True, size=24),
- 'city': fields.char('City', size=128),
- 'country_id': fields.many2one('res.country', 'Country',
- change_default=True),
- 'state_id': fields.many2one("res.country.state", 'State',
- change_default=True, domain="[('country_id','=',country_id)]"),
- 'partner_id': fields.many2one('res.partner', 'Partner', required=True,
- ondelete='cascade', select=True),
- 'state': fields.selection(_bank_type_get, 'Bank type', required=True,
- change_default=True),
- 'sequence': fields.integer('Sequence'),
- 'state_id': fields.many2one('res.country.state', 'State',
- domain="[('country_id', '=', country_id)]"),
- }
- _defaults = {
- 'owner_name': lambda obj, cursor, user, context: obj._default_value(
- cursor, user, 'name', context=context),
- 'street': lambda obj, cursor, user, context: obj._default_value(
- cursor, user, 'street', context=context),
- 'city': lambda obj, cursor, user, context: obj._default_value(
- cursor, user, 'city', context=context),
- 'zip': lambda obj, cursor, user, context: obj._default_value(
- cursor, user, 'zip', context=context),
- 'country_id': lambda obj, cursor, user, context: obj._default_value(
- cursor, user, 'country_id', context=context),
- 'state_id': lambda obj, cursor, user, context: obj._default_value(
- cursor, user, 'state_id', context=context),
- }
-
- def fields_get(self, cr, uid, fields=None, context=None):
- res = super(res_partner_bank, self).fields_get(cr, uid, fields, context)
- bank_type_obj = self.pool.get('res.partner.bank.type')
- type_ids = bank_type_obj.search(cr, uid, [])
- types = bank_type_obj.browse(cr, uid, type_ids)
- for type in types:
- for field in type.field_ids:
- if field.name in res:
- res[field.name].setdefault('states', {})
- res[field.name]['states'][type.code] = [
- ('readonly', field.readonly),
- ('required', field.required)]
- return res
-
- def name_get(self, cr, uid, ids, context=None):
- if not len(ids):
- return []
- res = []
- for id in self.browse(cr, uid, ids):
- res.append((id.id,id.acc_number))
- return res
+ '''Bank Accounts'''
+ _name = "res.partner.bank"
+ _rec_name = "state"
+ _description = __doc__
+ _order = 'sequence'
+
+ def _bank_type_get(self, cr, uid, context=None):
+ bank_type_obj = self.pool.get('res.partner.bank.type')
+
+ result = []
+ type_ids = bank_type_obj.search(cr, uid, [])
+ bank_types = bank_type_obj.browse(cr, uid, type_ids)
+ for bank_type in bank_types:
+ result.append((bank_type.code, bank_type.name))
+ return result
+
+ def _default_value(self, cursor, user, field, context=None):
+ if field in ('country_id', 'state_id'):
+ value = False
+ else:
+ value = ''
+ if not context.get('address', False):
+ return value
+ for ham, spam, address in context['address']:
+ if address.get('type', False) == 'default':
+ return address.get(field, value)
+ elif not address.get('type', False):
+ value = address.get(field, value)
+ return value
+
+ _columns = {
+ 'name': fields.char('Description', size=128),
+ 'acc_number': fields.char('Account number', size=64, required=False),
+ 'bank': fields.many2one('res.bank', 'Bank'),
+ 'owner_name': fields.char('Account owner', size=64),
+ 'street': fields.char('Street', size=128),
+ 'zip': fields.char('Zip', change_default=True, size=24),
+ 'city': fields.char('City', size=128),
+ 'country_id': fields.many2one('res.country', 'Country',
+ change_default=True),
+ 'state_id': fields.many2one("res.country.state", 'State',
+ change_default=True, domain="[('country_id','=',country_id)]"),
+ 'partner_id': fields.many2one('res.partner', 'Partner', required=True,
+ ondelete='cascade', select=True),
+ 'state': fields.selection(_bank_type_get, 'Bank type', required=True,
+ change_default=True),
+ 'sequence': fields.integer('Sequence'),
+ 'state_id': fields.many2one('res.country.state', 'State',
+ domain="[('country_id', '=', country_id)]"),
+ }
+ _defaults = {
+ 'owner_name': lambda obj, cursor, user, context: obj._default_value(
+ cursor, user, 'name', context=context),
+ 'street': lambda obj, cursor, user, context: obj._default_value(
+ cursor, user, 'street', context=context),
+ 'city': lambda obj, cursor, user, context: obj._default_value(
+ cursor, user, 'city', context=context),
+ 'zip': lambda obj, cursor, user, context: obj._default_value(
+ cursor, user, 'zip', context=context),
+ 'country_id': lambda obj, cursor, user, context: obj._default_value(
+ cursor, user, 'country_id', context=context),
+ 'state_id': lambda obj, cursor, user, context: obj._default_value(
+ cursor, user, 'state_id', context=context),
+ }
+
+ def fields_get(self, cr, uid, fields=None, context=None):
+ res = super(res_partner_bank, self).fields_get(cr, uid, fields, context)
+ bank_type_obj = self.pool.get('res.partner.bank.type')
+ type_ids = bank_type_obj.search(cr, uid, [])
+ types = bank_type_obj.browse(cr, uid, type_ids)
+ for type in types:
+ for field in type.field_ids:
+ if field.name in res:
+ res[field.name].setdefault('states', {})
+ res[field.name]['states'][type.code] = [
+ ('readonly', field.readonly),
+ ('required', field.required)]
+ return res
+
+ def name_get(self, cr, uid, ids, context=None):
+ if not len(ids):
+ return []
+ res = []
+ for id in self.browse(cr, uid, ids):
+ res.append((id.id,id.acc_number))
+ return res
res_partner_bank()
diff --git a/bin/addons/base/res/partner/wizard/wizard_clear_ids.py b/bin/addons/base/res/partner/wizard/wizard_clear_ids.py
index b6dc6e5ccb0..457add8f688 100644
--- a/bin/addons/base/res/partner/wizard/wizard_clear_ids.py
+++ b/bin/addons/base/res/partner/wizard/wizard_clear_ids.py
@@ -31,16 +31,16 @@ import wizard
import netsvc
class wizard_clear_ids(wizard.interface):
- def _clear_ids(self, cr, uid, data, context):
- service = netsvc.LocalService("object_proxy")
- service.execute(cr.dbname, uid, 'res.partner', 'write', data['ids'], {'ref': False})
- return {}
-
- states = {
- 'init': {
- 'actions': [_clear_ids],
- 'result': {'type':'state', 'state':'end'}
- }
- }
+ def _clear_ids(self, cr, uid, data, context):
+ service = netsvc.LocalService("object_proxy")
+ service.execute(cr.dbname, uid, 'res.partner', 'write', data['ids'], {'ref': False})
+ return {}
+
+ states = {
+ 'init': {
+ 'actions': [_clear_ids],
+ 'result': {'type':'state', 'state':'end'}
+ }
+ }
wizard_clear_ids('res.partner.clear_ids')
diff --git a/bin/addons/base/res/partner/wizard/wizard_ean_check.py b/bin/addons/base/res/partner/wizard/wizard_ean_check.py
index dea3c55a120..52af65e528f 100644
--- a/bin/addons/base/res/partner/wizard/wizard_ean_check.py
+++ b/bin/addons/base/res/partner/wizard/wizard_ean_check.py
@@ -34,70 +34,70 @@ from tools.misc import UpdateableStr
import pooler
def _is_pair(x):
- return not x%2
+ return not x%2
def _get_ean_key(string):
- if not string or string=='':
- return '0'
- if len(string)!=12:
- return '0'
- sum=0
- for i in range(12):
- if _is_pair(i):
- sum+=int(string[i])
- else:
- sum+=3*int(string[i])
- return str(int(math.ceil(sum/10.0)*10-sum))
+ if not string or string=='':
+ return '0'
+ if len(string)!=12:
+ return '0'
+ sum=0
+ for i in range(12):
+ if _is_pair(i):
+ sum+=int(string[i])
+ else:
+ sum+=3*int(string[i])
+ return str(int(math.ceil(sum/10.0)*10-sum))
#FIXME: this is not concurrency safe !!!!
_check_arch = UpdateableStr()
_check_fields = {}
def _check_key(self, cr, uid, data, context):
- partner_table=pooler.get_pool(cr.dbname).get('res.partner')
- partners = partner_table.browse(cr, uid, data['ids'])
- _check_arch_lst=['<?xml version="1.0"?>', '<form string="Check EAN13">', '<label string=""/>', '<label string=""/>','<label string="Original" />', '<label string="Computed" />']
- for partner in partners:
- if partner['ean13'] and len(partner['ean13'])>11 and len(partner['ean13'])<14:
- _check_arch_lst.append('<label colspan="2" string="%s" />' % partner['ean13']);
- key=_get_ean_key(partner['ean13'][:12])
- _check_arch_lst.append('<label string=""/>')
- if len(partner['ean13'])==12:
- _check_arch_lst.append('<label string="" />');
- else:
- _check_arch_lst.append('<label string="%s" />' % partner['ean13'][12])
- _check_arch_lst.append('<label string="%s" />' % key)
- _check_arch_lst.append('</form>')
- _check_arch.string = '\n'.join(_check_arch_lst)
- return {}
+ partner_table=pooler.get_pool(cr.dbname).get('res.partner')
+ partners = partner_table.browse(cr, uid, data['ids'])
+ _check_arch_lst=['<?xml version="1.0"?>', '<form string="Check EAN13">', '<label string=""/>', '<label string=""/>','<label string="Original" />', '<label string="Computed" />']
+ for partner in partners:
+ if partner['ean13'] and len(partner['ean13'])>11 and len(partner['ean13'])<14:
+ _check_arch_lst.append('<label colspan="2" string="%s" />' % partner['ean13']);
+ key=_get_ean_key(partner['ean13'][:12])
+ _check_arch_lst.append('<label string=""/>')
+ if len(partner['ean13'])==12:
+ _check_arch_lst.append('<label string="" />');
+ else:
+ _check_arch_lst.append('<label string="%s" />' % partner['ean13'][12])
+ _check_arch_lst.append('<label string="%s" />' % key)
+ _check_arch_lst.append('</form>')
+ _check_arch.string = '\n'.join(_check_arch_lst)
+ return {}
def _update_ean(self, cr, uid, data, context):
- partner_table = pooler.get_pool(cr.dbname).get('res.partner')
- partners = partner_table.browse(cr, uid, data['ids'])
- for partner in partners:
- partner_table.write(cr, uid, data['ids'], {
- 'ean13': "%s%s" % (partner['ean13'][:12], _get_ean_key(partner['ean13'][:12]))
- })
- return {}
+ partner_table = pooler.get_pool(cr.dbname).get('res.partner')
+ partners = partner_table.browse(cr, uid, data['ids'])
+ for partner in partners:
+ partner_table.write(cr, uid, data['ids'], {
+ 'ean13': "%s%s" % (partner['ean13'][:12], _get_ean_key(partner['ean13'][:12]))
+ })
+ return {}
class wiz_ean_check(wizard.interface):
- states = {
- 'init': {
- 'actions': [_check_key],
- 'result': {
- 'type': 'form',
- 'arch': _check_arch,
- 'fields': _check_fields,
- 'state': (('end', 'Ignore'), ('correct', 'Correct EAN13'))
- }
- },
- 'correct' : {
- 'actions': [_update_ean],
- 'result': {
- 'type': 'state',
- 'state': 'end'
- }
- }
- }
+ states = {
+ 'init': {
+ 'actions': [_check_key],
+ 'result': {
+ 'type': 'form',
+ 'arch': _check_arch,
+ 'fields': _check_fields,
+ 'state': (('end', 'Ignore'), ('correct', 'Correct EAN13'))
+ }
+ },
+ 'correct' : {
+ 'actions': [_update_ean],
+ 'result': {
+ 'type': 'state',
+ 'state': 'end'
+ }
+ }
+ }
wiz_ean_check('res.partner.ean13')
diff --git a/bin/addons/base/res/partner/wizard/wizard_sms.py b/bin/addons/base/res/partner/wizard/wizard_sms.py
index c3391852abe..fbd671e9764 100644
--- a/bin/addons/base/res/partner/wizard/wizard_sms.py
+++ b/bin/addons/base/res/partner/wizard/wizard_sms.py
@@ -33,47 +33,47 @@ import tools
sms_send_form = '''<?xml version="1.0"?>
<form string="%s">
- <separator string="%s" colspan="4"/>
- <field name="app_id"/>
- <newline/>
- <field name="user"/>
- <field name="password"/>
- <newline/>
- <field name="text" colspan="4"/>
+ <separator string="%s" colspan="4"/>
+ <field name="app_id"/>
+ <newline/>
+ <field name="user"/>
+ <field name="password"/>
+ <newline/>
+ <field name="text" colspan="4"/>
</form>''' % ('SMS - Gateway: clickatell','Bulk SMS send')
sms_send_fields = {
- 'app_id': {'string':'API ID', 'type':'char', 'required':True},
- 'user': {'string':'Login', 'type':'char', 'required':True},
- 'password': {'string':'Password', 'type':'char', 'required':True},
- 'text': {'string':'SMS Message', 'type':'text', 'required':True}
+ 'app_id': {'string':'API ID', 'type':'char', 'required':True},
+ 'user': {'string':'Login', 'type':'char', 'required':True},
+ 'password': {'string':'Password', 'type':'char', 'required':True},
+ 'text': {'string':'SMS Message', 'type':'text', 'required':True}
}
def _sms_send(self, cr, uid, data, context):
- service = netsvc.LocalService("object_proxy")
+ service = netsvc.LocalService("object_proxy")
- res_ids = service.execute(cr.dbname, uid, 'res.partner.address', 'search', [('partner_id','in',data['ids']),('type','=','default')])
- res = service.execute(cr.dbname, uid, 'res.partner.address', 'read', res_ids, ['mobile'])
+ res_ids = service.execute(cr.dbname, uid, 'res.partner.address', 'search', [('partner_id','in',data['ids']),('type','=','default')])
+ res = service.execute(cr.dbname, uid, 'res.partner.address', 'read', res_ids, ['mobile'])
- nbr = 0
- for r in res:
- to = r['mobile']
- if to:
- tools.sms_send(data['form']['user'], data['form']['password'], data['form']['app_id'], unicode(data['form']['text'], 'utf-8').encode('latin1'), to)
- nbr += 1
- return {'sms_sent': nbr}
+ nbr = 0
+ for r in res:
+ to = r['mobile']
+ if to:
+ tools.sms_send(data['form']['user'], data['form']['password'], data['form']['app_id'], unicode(data['form']['text'], 'utf-8').encode('latin1'), to)
+ nbr += 1
+ return {'sms_sent': nbr}
class part_sms(wizard.interface):
- states = {
- 'init': {
- 'actions': [],
- 'result': {'type': 'form', 'arch':sms_send_form, 'fields': sms_send_fields, 'state':[('end','Cancel'), ('send','Send SMS')]}
- },
- 'send': {
- 'actions': [_sms_send],
- 'result': {'type': 'state', 'state':'end'}
- }
- }
+ states = {
+ 'init': {
+ 'actions': [],
+ 'result': {'type': 'form', 'arch':sms_send_form, 'fields': sms_send_fields, 'state':[('end','Cancel'), ('send','Send SMS')]}
+ },
+ 'send': {
+ 'actions': [_sms_send],
+ 'result': {'type': 'state', 'state':'end'}
+ }
+ }
part_sms('res.partner.sms_send')
diff --git a/bin/addons/base/res/partner/wizard/wizard_spam.py b/bin/addons/base/res/partner/wizard/wizard_spam.py
index 95508f4c35b..c5353021264 100644
--- a/bin/addons/base/res/partner/wizard/wizard_spam.py
+++ b/bin/addons/base/res/partner/wizard/wizard_spam.py
@@ -33,48 +33,48 @@ import tools
email_send_form = '''<?xml version="1.0"?>
<form string="Mass Mailing">
- <field name="from"/>
- <newline/>
- <field name="subject"/>
- <newline/>
- <field name="text"/>
+ <field name="from"/>
+ <newline/>
+ <field name="subject"/>
+ <newline/>
+ <field name="text"/>
</form>'''
email_send_fields = {
- 'from': {'string':"Sender's email", 'type':'char', 'size':64, 'required':True},
- 'subject': {'string':'Subject', 'type':'char', 'size':64, 'required':True},
- 'text': {'string':'Message', 'type':'text_tag', 'required':True}
+ 'from': {'string':"Sender's email", 'type':'char', 'size':64, 'required':True},
+ 'subject': {'string':'Subject', 'type':'char', 'size':64, 'required':True},
+ 'text': {'string':'Message', 'type':'text_tag', 'required':True}
}
# this sends an email to ALL the addresses of the selected partners.
def _mass_mail_send(self, cr, uid, data, context):
- nbr = 0
- partners = pooler.get_pool(cr.dbname).get('res.partner').browse(cr, uid, data['ids'], context)
- for partner in partners:
- for adr in partner.address:
- if adr.email:
- name = adr.name or partner.name
- to = '%s <%s>' % (name, adr.email)
+ nbr = 0
+ partners = pooler.get_pool(cr.dbname).get('res.partner').browse(cr, uid, data['ids'], context)
+ for partner in partners:
+ for adr in partner.address:
+ if adr.email:
+ name = adr.name or partner.name
+ to = '%s <%s>' % (name, adr.email)
#TODO: add some tests to check for invalid email addresses
#CHECKME: maybe we should use res.partner/email_send
- tools.email_send(data['form']['from'], [to], data['form']['subject'], data['form']['text'])
- nbr += 1
- pooler.get_pool(cr.dbname).get('res.partner.event').create(cr, uid,
- {'name': 'Email sent through mass mailing',
- 'partner_id': partner.id,
- 'description': data['form']['text'], })
+ tools.email_send(data['form']['from'], [to], data['form']['subject'], data['form']['text'])
+ nbr += 1
+ pooler.get_pool(cr.dbname).get('res.partner.event').create(cr, uid,
+ {'name': 'Email sent through mass mailing',
+ 'partner_id': partner.id,
+ 'description': data['form']['text'], })
#TODO: log number of message sent
- return {'email_sent': nbr}
+ return {'email_sent': nbr}
class part_email(wizard.interface):
- states = {
- 'init': {
- 'actions': [],
- 'result': {'type': 'form', 'arch': email_send_form, 'fields': email_send_fields, 'state':[('end','Cancel'), ('send','Send Email')]}
- },
- 'send': {
- 'actions': [_mass_mail_send],
- 'result': {'type': 'state', 'state':'end'}
- }
- }
+ states = {
+ 'init': {
+ 'actions': [],
+ 'result': {'type': 'form', 'arch': email_send_form, 'fields': email_send_fields, 'state':[('end','Cancel'), ('send','Send Email')]}
+ },
+ 'send': {
+ 'actions': [_mass_mail_send],
+ 'result': {'type': 'state', 'state':'end'}
+ }
+ }
part_email('res.partner.spam_send')
diff --git a/bin/addons/base/res/res_company.py b/bin/addons/base/res/res_company.py
index 88b3c1779f7..1c5776dda88 100644
--- a/bin/addons/base/res/res_company.py
+++ b/bin/addons/base/res/res_company.py
@@ -31,152 +31,152 @@ from osv import fields,osv
import tools
class res_company(osv.osv):
- _name = "res.company"
-
- _columns = {
- 'name': fields.char('Company Name', size=64, required=True),
- 'parent_id': fields.many2one('res.company', 'Parent Company', select=True),
- 'child_ids': fields.one2many('res.company', 'parent_id', 'Childs Company'),
- 'partner_id': fields.many2one('res.partner', 'Partner', required=True),
- 'rml_header1': fields.char('Report Header', size=200),
- 'rml_footer1': fields.char('Report Footer 1', size=200),
- 'rml_footer2': fields.char('Report Footer 2', size=200),
- 'rml_header' : fields.text('RML Header'),
- 'rml_header2' : fields.text('RML Internal Header'),
- 'logo' : fields.binary('Logo'),
- 'currency_id': fields.many2one('res.currency', 'Currency', required=True),
- }
-
- def _get_child_ids(self, cr, uid, uid2, context={}):
- company = self.pool.get('res.users').company_get(cr, uid, uid2)
- ids = self._get_company_children(cr, uid, company)
- return ids
-
- def _get_company_children(self, cr, uid=None, company=None):
- if not company:
- return []
- ids = self.search(cr, uid, [('parent_id','child_of',[company])])
- return ids
- _get_company_children = tools.cache()(_get_company_children)
-
- def _get_partner_hierarchy(self, cr, uid, company_id, context={}):
- if company_id:
- parent_id = self.browse(cr, uid, company_id)['parent_id']
- if parent_id:
- return self._get_partner_hierarchy(cr, uid, parent_id.id, context)
- else:
- return self._get_partner_descendance(cr, uid, company_id, [], context)
- return []
-
- def _get_partner_descendance(self, cr, uid, company_id, descendance, context={}):
- descendance.append(self.browse(cr, uid, company_id).partner_id.id)
- for child_id in self._get_company_children(cr, uid, company_id):
- if child_id != company_id:
- descendance = self._get_partner_descendance(cr, uid, child_id, descendance)
- return descendance
-
- def __init__(self, *args, **argv):
- return super(res_company, self).__init__(*args, **argv)
-
- #
- # This function restart the cache on the _get_company_children method
- #
- def cache_restart(self, uid=None):
- self._get_company_children()
-
- def create(self, *args, **argv):
- self.cache_restart()
- return super(res_company, self).create(*args, **argv)
-
- def write(self, *args, **argv):
- self.cache_restart()
- # Restart the cache on the company_get method
- self.pool.get('ir.rule').domain_get()
- return super(res_company, self).write(*args, **argv)
-
- def _get_euro(self, cr, uid, context={}):
- try:
- return self.pool.get('res.currency').search(cr, uid, [('rate', '=', 1.0),])[0]
- except:
- return 1
-
- def _check_recursion(self, cr, uid, ids):
- level = 100
- while len(ids):
- cr.execute('select distinct parent_id from res_company where id in ('+','.join(map(str,ids))+')')
- ids = filter(None, map(lambda x:x[0], cr.fetchall()))
- if not level:
- return False
- level -= 1
- return True
-
- def _get_header2(self,cr,uid,ids):
- return """
- <header>
- <pageTemplate>
- <frame id="first" x1="1.3cm" y1="1.5cm" width="18.4cm" height="26.5cm"/>
- <pageGraphics>
- <fill color="black"/>
- <stroke color="black"/>
- <setFont name="Helvetica" size="8"/>
- <drawString x="1.3cm" y="28.3cm"> [[ formatLang(time.strftime("%Y-%m-%d"), date=True) ]] [[ time.strftime("%H:%M") ]]</drawString>
- <setFont name="Helvetica-Bold" size="10"/>
- <drawString x="9.8cm" y="28.3cm">[[ company.partner_id.name ]]</drawString>
- <setFont name="Helvetica" size="8"/>
- <drawRightString x="19.7cm" y="28.3cm"><pageNumber/> / </drawRightString>
- <drawString x="19.8cm" y="28.3cm"><pageCount/></drawString>
- <stroke color="#aaaaaa"/>
- <lines>1.3cm 28.1cm 20cm 28.1cm</lines>
- </pageGraphics>
- </pageTemplate>
+ _name = "res.company"
+
+ _columns = {
+ 'name': fields.char('Company Name', size=64, required=True),
+ 'parent_id': fields.many2one('res.company', 'Parent Company', select=True),
+ 'child_ids': fields.one2many('res.company', 'parent_id', 'Childs Company'),
+ 'partner_id': fields.many2one('res.partner', 'Partner', required=True),
+ 'rml_header1': fields.char('Report Header', size=200),
+ 'rml_footer1': fields.char('Report Footer 1', size=200),
+ 'rml_footer2': fields.char('Report Footer 2', size=200),
+ 'rml_header' : fields.text('RML Header'),
+ 'rml_header2' : fields.text('RML Internal Header'),
+ 'logo' : fields.binary('Logo'),
+ 'currency_id': fields.many2one('res.currency', 'Currency', required=True),
+ }
+
+ def _get_child_ids(self, cr, uid, uid2, context={}):
+ company = self.pool.get('res.users').company_get(cr, uid, uid2)
+ ids = self._get_company_children(cr, uid, company)
+ return ids
+
+ def _get_company_children(self, cr, uid=None, company=None):
+ if not company:
+ return []
+ ids = self.search(cr, uid, [('parent_id','child_of',[company])])
+ return ids
+ _get_company_children = tools.cache()(_get_company_children)
+
+ def _get_partner_hierarchy(self, cr, uid, company_id, context={}):
+ if company_id:
+ parent_id = self.browse(cr, uid, company_id)['parent_id']
+ if parent_id:
+ return self._get_partner_hierarchy(cr, uid, parent_id.id, context)
+ else:
+ return self._get_partner_descendance(cr, uid, company_id, [], context)
+ return []
+
+ def _get_partner_descendance(self, cr, uid, company_id, descendance, context={}):
+ descendance.append(self.browse(cr, uid, company_id).partner_id.id)
+ for child_id in self._get_company_children(cr, uid, company_id):
+ if child_id != company_id:
+ descendance = self._get_partner_descendance(cr, uid, child_id, descendance)
+ return descendance
+
+ def __init__(self, *args, **argv):
+ return super(res_company, self).__init__(*args, **argv)
+
+ #
+ # This function restart the cache on the _get_company_children method
+ #
+ def cache_restart(self, uid=None):
+ self._get_company_children()
+
+ def create(self, *args, **argv):
+ self.cache_restart()
+ return super(res_company, self).create(*args, **argv)
+
+ def write(self, *args, **argv):
+ self.cache_restart()
+ # Restart the cache on the company_get method
+ self.pool.get('ir.rule').domain_get()
+ return super(res_company, self).write(*args, **argv)
+
+ def _get_euro(self, cr, uid, context={}):
+ try:
+ return self.pool.get('res.currency').search(cr, uid, [('rate', '=', 1.0),])[0]
+ except:
+ return 1
+
+ def _check_recursion(self, cr, uid, ids):
+ level = 100
+ while len(ids):
+ cr.execute('select distinct parent_id from res_company where id in ('+','.join(map(str,ids))+')')
+ ids = filter(None, map(lambda x:x[0], cr.fetchall()))
+ if not level:
+ return False
+ level -= 1
+ return True
+
+ def _get_header2(self,cr,uid,ids):
+ return """
+ <header>
+ <pageTemplate>
+ <frame id="first" x1="1.3cm" y1="1.5cm" width="18.4cm" height="26.5cm"/>
+ <pageGraphics>
+ <fill color="black"/>
+ <stroke color="black"/>
+ <setFont name="Helvetica" size="8"/>
+ <drawString x="1.3cm" y="28.3cm"> [[ formatLang(time.strftime("%Y-%m-%d"), date=True) ]] [[ time.strftime("%H:%M") ]]</drawString>
+ <setFont name="Helvetica-Bold" size="10"/>
+ <drawString x="9.8cm" y="28.3cm">[[ company.partner_id.name ]]</drawString>
+ <setFont name="Helvetica" size="8"/>
+ <drawRightString x="19.7cm" y="28.3cm"><pageNumber/> / </drawRightString>
+ <drawString x="19.8cm" y="28.3cm"><pageCount/></drawString>
+ <stroke color="#aaaaaa"/>
+ <lines>1.3cm 28.1cm 20cm 28.1cm</lines>
+ </pageGraphics>
+ </pageTemplate>
</header>"""
- def _get_header(self,cr,uid,ids):
- try :
- return tools.file_open('custom/corporate_rml_header.rml').read()
- except:
- return """
- <header>
- <pageTemplate>
- <frame id="first" x1="1.3cm" y1="2.5cm" height="23.0cm" width="19cm"/>
- <pageGraphics>
- <!-- You Logo - Change X,Y,Width and Height -->
- <image x="1.3cm" y="27.6cm" height="40.0" >[[company.logo]]</image>
- <setFont name="Helvetica" size="8"/>
- <fill color="black"/>
- <stroke color="black"/>
- <lines>1.3cm 27.7cm 20cm 27.7cm</lines>
-
- <drawRightString x="20cm" y="27.8cm">[[ company.rml_header1 ]]</drawRightString>
-
-
- <drawString x="1.3cm" y="27.2cm">[[ company.partner_id.name ]]</drawString>
- <drawString x="1.3cm" y="26.8cm">[[ company.partner_id.address and company.partner_id.address[0].street ]]</drawString>
- <drawString x="1.3cm" y="26.4cm">[[ company.partner_id.address and company.partner_id.address[0].zip ]] [[ company.partner_id.address and company.partner_id.address[0].city ]] - [[ company.partner_id.address and company.partner_id.address[0].country_id and company.partner_id.address[0].country_id.name ]]</drawString>
- <drawString x="1.3cm" y="26.0cm">Phone:</drawString>
- <drawRightString x="7cm" y="26.0cm">[[ company.partner_id.address and company.partner_id.address[0].phone ]]</drawRightString>
- <drawString x="1.3cm" y="25.6cm">Mail:</drawString>
- <drawRightString x="7cm" y="25.6cm">[[ company.partner_id.address and company.partner_id.address[0].email ]]</drawRightString>
- <lines>1.3cm 25.5cm 7cm 25.5cm</lines>
-
- <!--page bottom-->
-
- <lines>1.2cm 2.15cm 19.9cm 2.15cm</lines>
-
- <drawCentredString x="10.5cm" y="1.7cm">[[ company.rml_footer1 ]]</drawCentredString>
- <drawCentredString x="10.5cm" y="1.25cm">[[ company.rml_footer2 ]]</drawCentredString>
- <drawCentredString x="10.5cm" y="0.8cm">Contact : [[ user.name ]] - Page: <pageNumber/></drawCentredString>
- </pageGraphics>
- </pageTemplate>
+ def _get_header(self,cr,uid,ids):
+ try :
+ return tools.file_open('custom/corporate_rml_header.rml').read()
+ except:
+ return """
+ <header>
+ <pageTemplate>
+ <frame id="first" x1="1.3cm" y1="2.5cm" height="23.0cm" width="19cm"/>
+ <pageGraphics>
+ <!-- You Logo - Change X,Y,Width and Height -->
+ <image x="1.3cm" y="27.6cm" height="40.0" >[[company.logo]]</image>
+ <setFont name="Helvetica" size="8"/>
+ <fill color="black"/>
+ <stroke color="black"/>
+ <lines>1.3cm 27.7cm 20cm 27.7cm</lines>
+
+ <drawRightString x="20cm" y="27.8cm">[[ company.rml_header1 ]]</drawRightString>
+
+
+ <drawString x="1.3cm" y="27.2cm">[[ company.partner_id.name ]]</drawString>
+ <drawString x="1.3cm" y="26.8cm">[[ company.partner_id.address and company.partner_id.address[0].street ]]</drawString>
+ <drawString x="1.3cm" y="26.4cm">[[ company.partner_id.address and company.partner_id.address[0].zip ]] [[ company.partner_id.address and company.partner_id.address[0].city ]] - [[ company.partner_id.address and company.partner_id.address[0].country_id and company.partner_id.address[0].country_id.name ]]</drawString>
+ <drawString x="1.3cm" y="26.0cm">Phone:</drawString>
+ <drawRightString x="7cm" y="26.0cm">[[ company.partner_id.address and company.partner_id.address[0].phone ]]</drawRightString>
+ <drawString x="1.3cm" y="25.6cm">Mail:</drawString>
+ <drawRightString x="7cm" y="25.6cm">[[ company.partner_id.address and company.partner_id.address[0].email ]]</drawRightString>
+ <lines>1.3cm 25.5cm 7cm 25.5cm</lines>
+
+ <!--page bottom-->
+
+ <lines>1.2cm 2.15cm 19.9cm 2.15cm</lines>
+
+ <drawCentredString x="10.5cm" y="1.7cm">[[ company.rml_footer1 ]]</drawCentredString>
+ <drawCentredString x="10.5cm" y="1.25cm">[[ company.rml_footer2 ]]</drawCentredString>
+ <drawCentredString x="10.5cm" y="0.8cm">Contact : [[ user.name ]] - Page: <pageNumber/></drawCentredString>
+ </pageGraphics>
+ </pageTemplate>
</header>"""
- _defaults = {
- 'currency_id': _get_euro,
- 'rml_header':_get_header,
- 'rml_header2': _get_header2
- }
-
- _constraints = [
- (_check_recursion, 'Error! You can not create recursive companies.', ['parent_id'])
- ]
+ _defaults = {
+ 'currency_id': _get_euro,
+ 'rml_header':_get_header,
+ 'rml_header2': _get_header2
+ }
+
+ _constraints = [
+ (_check_recursion, 'Error! You can not create recursive companies.', ['parent_id'])
+ ]
res_company()
diff --git a/bin/addons/base/res/res_currency.py b/bin/addons/base/res/res_currency.py
index 30b61e0f0ac..6f6a84cb0d1 100644
--- a/bin/addons/base/res/res_currency.py
+++ b/bin/addons/base/res/res_currency.py
@@ -39,90 +39,90 @@ import mx.DateTime
from mx.DateTime import RelativeDateTime, now, DateTime, localtime
class res_currency(osv.osv):
- def _current_rate(self, cr, uid, ids, name, arg, context={}):
- res={}
- if 'date' in context:
- date=context['date']
- else:
- date=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))
- if cr.rowcount:
- id, rate=cr.fetchall()[0]
- res[id]=rate
- else:
- res[id]=0
- return res
- _name = "res.currency"
- _description = "Currency"
- _columns = {
- 'name': fields.char('Currency', size=32, required=True),
- 'code': fields.char('Code', size=3),
- 'rate': fields.function(_current_rate, method=True, string='Current rate', digits=(12,6),
- help='The rate of the currency to the currency of rate 1'),
- 'rate_ids': fields.one2many('res.currency.rate', 'currency_id', 'Rates'),
- 'accuracy': fields.integer('Computational Accuracy'),
- 'rounding': fields.float('Rounding factor', digits=(12,6)),
- 'active': fields.boolean('Active'),
- }
- _defaults = {
- 'active': lambda *a: 1,
- }
- _order = "code"
+ def _current_rate(self, cr, uid, ids, name, arg, context={}):
+ res={}
+ if 'date' in context:
+ date=context['date']
+ else:
+ date=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))
+ if cr.rowcount:
+ id, rate=cr.fetchall()[0]
+ res[id]=rate
+ else:
+ res[id]=0
+ return res
+ _name = "res.currency"
+ _description = "Currency"
+ _columns = {
+ 'name': fields.char('Currency', size=32, required=True),
+ 'code': fields.char('Code', size=3),
+ 'rate': fields.function(_current_rate, method=True, string='Current rate', digits=(12,6),
+ help='The rate of the currency to the currency of rate 1'),
+ 'rate_ids': fields.one2many('res.currency.rate', 'currency_id', 'Rates'),
+ 'accuracy': fields.integer('Computational Accuracy'),
+ 'rounding': fields.float('Rounding factor', digits=(12,6)),
+ 'active': fields.boolean('Active'),
+ }
+ _defaults = {
+ 'active': lambda *a: 1,
+ }
+ _order = "code"
- def round(self, cr, uid, currency, amount):
- return round(amount / currency.rounding) * currency.rounding
+ def round(self, cr, uid, currency, amount):
+ return round(amount / currency.rounding) * currency.rounding
- def is_zero(self, cr, uid, currency, amount):
- return abs(self.round(cr, uid, currency, amount)) < currency.rounding
+ def is_zero(self, cr, uid, currency, amount):
+ return abs(self.round(cr, uid, currency, amount)) < currency.rounding
- def compute(self, cr, uid, from_currency_id, to_currency_id, from_amount, round=True, context={}):
- if not from_currency_id:
- from_currency_id = to_currency_id
- xc=self.browse(cr, uid, [from_currency_id,to_currency_id], context=context)
- from_currency = (xc[0].id == from_currency_id and xc[0]) or xc[1]
- to_currency = (xc[0].id == to_currency_id and xc[0]) or xc[1]
- if from_currency['rate'] == 0 or to_currency['rate'] == 0:
- date = context.get('date', time.strftime('%Y-%m-%d'))
- if from_currency['rate'] == 0:
- code = from_currency.code
- else:
- code = to_currency.code
- raise osv.except_osv(_('Error'), _('No rate found \n' \
- 'for the currency: %s \n' \
- 'at the date: %s') % (code, date))
- if to_currency_id==from_currency_id:
- if round:
- return self.round(cr, uid, to_currency, from_amount)
- else:
- return from_amount
- else:
- if round:
- return self.round(cr, uid, to_currency, from_amount * to_currency.rate/from_currency.rate)
- else:
- return (from_amount * to_currency.rate/from_currency.rate)
- def name_search(self, cr, uid, name, args=[], operator='ilike', context={}, limit=80):
- args2 = args[:]
- if name:
- args += [('name', operator, name)]
- args2 += [('code', operator, name)]
- ids = self.search(cr, uid, args, limit=limit)
- ids += self.search(cr, uid, args2, limit=limit)
- res = self.name_get(cr, uid, ids, context)
- return res
+ def compute(self, cr, uid, from_currency_id, to_currency_id, from_amount, round=True, context={}):
+ if not from_currency_id:
+ from_currency_id = to_currency_id
+ xc=self.browse(cr, uid, [from_currency_id,to_currency_id], context=context)
+ from_currency = (xc[0].id == from_currency_id and xc[0]) or xc[1]
+ to_currency = (xc[0].id == to_currency_id and xc[0]) or xc[1]
+ if from_currency['rate'] == 0 or to_currency['rate'] == 0:
+ date = context.get('date', time.strftime('%Y-%m-%d'))
+ if from_currency['rate'] == 0:
+ code = from_currency.code
+ else:
+ code = to_currency.code
+ raise osv.except_osv(_('Error'), _('No rate found \n' \
+ 'for the currency: %s \n' \
+ 'at the date: %s') % (code, date))
+ if to_currency_id==from_currency_id:
+ if round:
+ return self.round(cr, uid, to_currency, from_amount)
+ else:
+ return from_amount
+ else:
+ if round:
+ return self.round(cr, uid, to_currency, from_amount * to_currency.rate/from_currency.rate)
+ else:
+ return (from_amount * to_currency.rate/from_currency.rate)
+ def name_search(self, cr, uid, name, args=[], operator='ilike', context={}, limit=80):
+ args2 = args[:]
+ if name:
+ args += [('name', operator, name)]
+ args2 += [('code', operator, name)]
+ ids = self.search(cr, uid, args, limit=limit)
+ ids += self.search(cr, uid, args2, limit=limit)
+ res = self.name_get(cr, uid, ids, context)
+ return res
res_currency()
class res_currency_rate(osv.osv):
- _name = "res.currency.rate"
- _description = "Currency Rate"
- _columns = {
- 'name': fields.date('Date', required=True, select=True),
- 'rate': fields.float('Rate', digits=(12,6), required=True,
- help='The rate of the currency to the currency of rate 1'),
- 'currency_id': fields.many2one('res.currency', 'Currency', readonly=True),
- }
- _defaults = {
- 'name': lambda *a: time.strftime('%Y-%m-%d'),
- }
- _order = "name desc"
+ _name = "res.currency.rate"
+ _description = "Currency Rate"
+ _columns = {
+ 'name': fields.date('Date', required=True, select=True),
+ 'rate': fields.float('Rate', digits=(12,6), required=True,
+ help='The rate of the currency to the currency of rate 1'),
+ 'currency_id': fields.many2one('res.currency', 'Currency', readonly=True),
+ }
+ _defaults = {
+ 'name': lambda *a: time.strftime('%Y-%m-%d'),
+ }
+ _order = "name desc"
res_currency_rate()
diff --git a/bin/addons/base/res/res_lang.py b/bin/addons/base/res/res_lang.py
index 9f3e1dcf5a9..7ef19b65078 100644
--- a/bin/addons/base/res/res_lang.py
+++ b/bin/addons/base/res/res_lang.py
@@ -30,19 +30,19 @@
from osv import fields, osv
class lang(osv.osv):
- _name = "res.lang"
- _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),
- }
- _defaults = {
- 'active': lambda *a: 1,
- 'translatable': lambda *a: 0,
- 'direction': lambda *a: 'ltr',
- }
+ _name = "res.lang"
+ _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),
+ }
+ _defaults = {
+ 'active': lambda *a: 1,
+ 'translatable': lambda *a: 0,
+ 'direction': lambda *a: 'ltr',
+ }
lang()
diff --git a/bin/addons/base/res/res_request.py b/bin/addons/base/res/res_request.py
index 790d0e7624f..539449246cc 100644
--- a/bin/addons/base/res/res_request.py
+++ b/bin/addons/base/res/res_request.py
@@ -31,97 +31,97 @@ from osv import osv, fields
import time
def _links_get(self, cr, uid, context={}):
- obj = self.pool.get('res.request.link')
- ids = obj.search(cr, uid, [])
- res = obj.read(cr, uid, ids, ['object', 'name'], context)
- return [(r['object'], r['name']) for r in res]
+ obj = self.pool.get('res.request.link')
+ ids = obj.search(cr, uid, [])
+ res = obj.read(cr, uid, ids, ['object', 'name'], context)
+ return [(r['object'], r['name']) for r in res]
class res_request(osv.osv):
- _name = 'res.request'
+ _name = 'res.request'
- 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,))
- values = cr.dictfetchone()
- if values['body'] and (len(values['body']) > 128):
- values['name'] = values['body'][:125] + '...'
- else:
- values['name'] = values['body'] or '/'
- values['req_id'] = id
- self.pool.get('res.request.history').create(cr, uid, values)
- return True
+ 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,))
+ values = cr.dictfetchone()
+ if values['body'] and (len(values['body']) > 128):
+ values['name'] = values['body'][:125] + '...'
+ else:
+ values['name'] = values['body'] or '/'
+ values['req_id'] = id
+ self.pool.get('res.request.history').create(cr, uid, values)
+ return True
- 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))
- return True
+ 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))
+ return True
- def request_close(self, cr, uid, ids, *args):
- self.write(cr, uid, ids, {'state':'closed', 'active':False})
- return True
+ def request_close(self, cr, uid, ids, *args):
+ self.write(cr, uid, ids, {'state':'closed', 'active':False})
+ 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')))
- 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')))
- ids2 = map(lambda x:x[0], cr.fetchall())
- return (ids, ids2)
+ 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')))
+ 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')))
+ ids2 = map(lambda x:x[0], cr.fetchall())
+ return (ids, ids2)
- _columns = {
- 'create_date': fields.datetime('Created date', readonly=True),
- 'name': fields.char('Subject', states={'waiting':[('readonly',True)],'active':[('readonly',True)],'closed':[('readonly',True)]}, required=True, size=128),
- 'active': fields.boolean('Active'),
- 'priority': fields.selection([('0','Low'),('1','Normal'),('2','High')], 'Priority', states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}, required=True),
- 'act_from': fields.many2one('res.users', 'From', required=True, readonly=True, states={'closed':[('readonly',True)]}),
- 'act_to': fields.many2one('res.users', 'To', required=True, states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}),
- 'body': fields.text('Request', states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}),
- 'date_sent': fields.datetime('Date', readonly=True),
- 'trigger_date': fields.datetime('Trigger Date', states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}),
- 'ref_partner_id':fields.many2one('res.partner', 'Partner Ref.', states={'closed':[('readonly',True)]}),
- 'ref_doc1':fields.reference('Document Ref 1', selection=_links_get, size=128, states={'closed':[('readonly',True)]}),
- 'ref_doc2':fields.reference('Document Ref 2', selection=_links_get, size=128, states={'closed':[('readonly',True)]}),
- 'state': fields.selection([('draft','draft'),('waiting','waiting'),('active','active'),('closed','closed')], 'State', required=True, readonly=True),
- 'history': fields.one2many('res.request.history','req_id', 'History')
- }
- _defaults = {
- 'act_from': lambda obj,cr,uid,context={}: uid,
- 'state': lambda obj,cr,uid,context={}: 'draft',
- 'active': lambda obj,cr,uid,context={}: True,
- 'priority': lambda obj,cr,uid,context={}: '1',
- }
- _order = 'priority desc, trigger_date, create_date desc'
- _table = 'res_request'
+ _columns = {
+ 'create_date': fields.datetime('Created date', readonly=True),
+ 'name': fields.char('Subject', states={'waiting':[('readonly',True)],'active':[('readonly',True)],'closed':[('readonly',True)]}, required=True, size=128),
+ 'active': fields.boolean('Active'),
+ 'priority': fields.selection([('0','Low'),('1','Normal'),('2','High')], 'Priority', states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}, required=True),
+ 'act_from': fields.many2one('res.users', 'From', required=True, readonly=True, states={'closed':[('readonly',True)]}),
+ 'act_to': fields.many2one('res.users', 'To', required=True, states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}),
+ 'body': fields.text('Request', states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}),
+ 'date_sent': fields.datetime('Date', readonly=True),
+ 'trigger_date': fields.datetime('Trigger Date', states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}),
+ 'ref_partner_id':fields.many2one('res.partner', 'Partner Ref.', states={'closed':[('readonly',True)]}),
+ 'ref_doc1':fields.reference('Document Ref 1', selection=_links_get, size=128, states={'closed':[('readonly',True)]}),
+ 'ref_doc2':fields.reference('Document Ref 2', selection=_links_get, size=128, states={'closed':[('readonly',True)]}),
+ 'state': fields.selection([('draft','draft'),('waiting','waiting'),('active','active'),('closed','closed')], 'State', required=True, readonly=True),
+ 'history': fields.one2many('res.request.history','req_id', 'History')
+ }
+ _defaults = {
+ 'act_from': lambda obj,cr,uid,context={}: uid,
+ 'state': lambda obj,cr,uid,context={}: 'draft',
+ 'active': lambda obj,cr,uid,context={}: True,
+ 'priority': lambda obj,cr,uid,context={}: '1',
+ }
+ _order = 'priority desc, trigger_date, create_date desc'
+ _table = 'res_request'
res_request()
class res_request_link(osv.osv):
- _name = 'res.request.link'
- _columns = {
- 'name': fields.char('Name', size=64, required=True, translate=True),
- 'object': fields.char('Object', size=64, required=True),
- 'priority': fields.integer('Priority'),
- }
- _defaults = {
- 'priority': lambda *a: 5,
- }
- _order = 'priority'
+ _name = 'res.request.link'
+ _columns = {
+ 'name': fields.char('Name', size=64, required=True, translate=True),
+ 'object': fields.char('Object', size=64, required=True),
+ 'priority': fields.integer('Priority'),
+ }
+ _defaults = {
+ 'priority': lambda *a: 5,
+ }
+ _order = 'priority'
res_request_link()
class res_request_history(osv.osv):
- _name = 'res.request.history'
- _columns = {
- 'name': fields.char('Summary', size=128, states={'active':[('readonly',True)],'waiting':[('readonly',True)]}, required=True),
- 'req_id': fields.many2one('res.request', 'Request', required=True, ondelete='cascade', select=True),
- 'act_from': fields.many2one('res.users', 'From', required=True, readonly=True),
- 'act_to': fields.many2one('res.users', 'To', required=True, states={'waiting':[('readonly',True)]}),
- 'body': fields.text('Body', states={'waiting':[('readonly',True)]}),
- 'date_sent': fields.datetime('Date sent', states={'waiting':[('readonly',True)]}, required=True)
- }
- _defaults = {
- 'name': lambda *a: 'NoName',
- 'act_from': lambda obj,cr,uid,context={}: uid,
- 'act_to': lambda obj,cr,uid,context={}: uid,
- 'date_sent': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
- }
+ _name = 'res.request.history'
+ _columns = {
+ 'name': fields.char('Summary', size=128, states={'active':[('readonly',True)],'waiting':[('readonly',True)]}, required=True),
+ 'req_id': fields.many2one('res.request', 'Request', required=True, ondelete='cascade', select=True),
+ 'act_from': fields.many2one('res.users', 'From', required=True, readonly=True),
+ 'act_to': fields.many2one('res.users', 'To', required=True, states={'waiting':[('readonly',True)]}),
+ 'body': fields.text('Body', states={'waiting':[('readonly',True)]}),
+ 'date_sent': fields.datetime('Date sent', states={'waiting':[('readonly',True)]}, required=True)
+ }
+ _defaults = {
+ 'name': lambda *a: 'NoName',
+ 'act_from': lambda obj,cr,uid,context={}: uid,
+ 'act_to': lambda obj,cr,uid,context={}: uid,
+ 'date_sent': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
+ }
res_request_history()
diff --git a/bin/addons/base/res/res_user.py b/bin/addons/base/res/res_user.py
index 24e16e6a03a..4b856dff182 100644
--- a/bin/addons/base/res/res_user.py
+++ b/bin/addons/base/res/res_user.py
@@ -32,243 +32,243 @@ import tools
import pytz
class groups(osv.osv):
- _name = "res.groups"
- _columns = {
- 'name': fields.char('Group Name', size=64, required=True),
- 'model_access': fields.one2many('ir.model.access', 'group_id', 'Access Controls'),
- 'rule_groups': fields.many2many('ir.rule.group', 'group_rule_group_rel',
- 'group_id', 'rule_group_id', 'Rules', domain="[('global', '<>', True)]"),
- 'menu_access': fields.many2many('ir.ui.menu', 'ir_ui_menu_group_rel', 'gid', 'menu_id', 'Access Menu'),
- 'comment' : fields.text('Comment',size=250),
- }
- _sql_constraints = [
- ('name_uniq', 'unique (name)', 'The name of the group must be unique !')
- ]
+ _name = "res.groups"
+ _columns = {
+ 'name': fields.char('Group Name', size=64, required=True),
+ 'model_access': fields.one2many('ir.model.access', 'group_id', 'Access Controls'),
+ 'rule_groups': fields.many2many('ir.rule.group', 'group_rule_group_rel',
+ 'group_id', 'rule_group_id', 'Rules', domain="[('global', '<>', True)]"),
+ 'menu_access': fields.many2many('ir.ui.menu', 'ir_ui_menu_group_rel', 'gid', 'menu_id', 'Access Menu'),
+ 'comment' : fields.text('Comment',size=250),
+ }
+ _sql_constraints = [
+ ('name_uniq', 'unique (name)', 'The name of the group must be unique !')
+ ]
- def write(self, cr, uid, ids, vals, context=None):
- if 'name' in vals:
- if vals['name'].startswith('-'):
- raise osv.except_osv(_('Error'),
- _('The name of the group can not start with "-"'))
- res = super(groups, self).write(cr, uid, ids, vals, context=context)
- # Restart the cache on the company_get method
- self.pool.get('ir.rule').domain_get()
- return res
+ def write(self, cr, uid, ids, vals, context=None):
+ if 'name' in vals:
+ if vals['name'].startswith('-'):
+ raise osv.except_osv(_('Error'),
+ _('The name of the group can not start with "-"'))
+ res = super(groups, self).write(cr, uid, ids, vals, context=context)
+ # Restart the cache on the company_get method
+ self.pool.get('ir.rule').domain_get()
+ return res
- def create(self, cr, uid, vals, context=None):
- if 'name' in vals:
- if vals['name'].startswith('-'):
- raise osv.except_osv(_('Error'),
- _('The name of the group can not start with "-"'))
- return super(groups, self).create(cr, uid, vals, context=context)
+ def create(self, cr, uid, vals, context=None):
+ if 'name' in vals:
+ if vals['name'].startswith('-'):
+ raise osv.except_osv(_('Error'),
+ _('The name of the group can not start with "-"'))
+ return super(groups, self).create(cr, uid, vals, context=context)
groups()
class roles(osv.osv):
- _name = "res.roles"
- _columns = {
- 'name': fields.char('Role Name', size=64, required=True),
- 'parent_id': fields.many2one('res.roles', 'Parent', select=True),
- 'child_id': fields.one2many('res.roles', 'parent_id', 'Childs')
- }
- _defaults = {
- }
- 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,))
- roles = cr.fetchone()[0]
- if roles:
- return self.check(cr, uid, ids, roles)
- return False
+ _name = "res.roles"
+ _columns = {
+ 'name': fields.char('Role Name', size=64, required=True),
+ 'parent_id': fields.many2one('res.roles', 'Parent', select=True),
+ 'child_id': fields.one2many('res.roles', 'parent_id', 'Childs')
+ }
+ _defaults = {
+ }
+ 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,))
+ roles = cr.fetchone()[0]
+ if roles:
+ return self.check(cr, uid, ids, roles)
+ return False
roles()
def _lang_get(self, cr, uid, context={}):
- obj = self.pool.get('res.lang')
- ids = obj.search(cr, uid, [])
- res = obj.read(cr, uid, ids, ['code', 'name'], context)
- res = [(r['code'], r['name']) for r in res]
- return res
+ obj = self.pool.get('res.lang')
+ ids = obj.search(cr, uid, [])
+ res = obj.read(cr, uid, ids, ['code', 'name'], context)
+ res = [(r['code'], r['name']) for r in res]
+ return res
def _tz_get(self,cr,uid, context={}):
- return [(x, x) for x in pytz.all_timezones]
+ return [(x, x) for x in pytz.all_timezones]
class users(osv.osv):
- _name = "res.users"
- _log_access = False
- _columns = {
- 'name': fields.char('Name', size=64, required=True, select=True),
- 'login': fields.char('Login', size=64, required=True),
- 'password': fields.char('Password', size=64, invisible=True),
- 'signature': fields.text('Signature', size=64),
- 'address_id': fields.many2one('res.partner.address', 'Address'),
- 'active': fields.boolean('Active'),
- 'action_id': fields.many2one('ir.actions.actions', 'Home Action'),
- 'menu_id': fields.many2one('ir.actions.actions', 'Menu Action'),
- 'groups_id': fields.many2many('res.groups', 'res_groups_users_rel', 'uid', 'gid', 'Groups'),
- 'roles_id': fields.many2many('res.roles', 'res_roles_users_rel', 'uid', 'rid', 'Roles'),
- 'company_id': fields.many2one('res.company', 'Company'),
- 'context_lang': fields.selection(_lang_get, 'Language', required=True),
- 'context_tz': fields.selection(_tz_get, 'Timezone', size=64)
- }
- def read(self,cr, uid, ids, fields=None, context=None, load='_classic_read'):
- result = super(users, self).read(cr, uid, ids, fields, context, load)
- canwrite = self.pool.get('ir.model.access').check(cr, uid, 'res.users', 'write', raise_exception=False)
- if not canwrite:
- for r in result:
- if 'password' in r:
- r['password'] = '********'
- return result
+ _name = "res.users"
+ _log_access = False
+ _columns = {
+ 'name': fields.char('Name', size=64, required=True, select=True),
+ 'login': fields.char('Login', size=64, required=True),
+ 'password': fields.char('Password', size=64, invisible=True),
+ 'signature': fields.text('Signature', size=64),
+ 'address_id': fields.many2one('res.partner.address', 'Address'),
+ 'active': fields.boolean('Active'),
+ 'action_id': fields.many2one('ir.actions.actions', 'Home Action'),
+ 'menu_id': fields.many2one('ir.actions.actions', 'Menu Action'),
+ 'groups_id': fields.many2many('res.groups', 'res_groups_users_rel', 'uid', 'gid', 'Groups'),
+ 'roles_id': fields.many2many('res.roles', 'res_roles_users_rel', 'uid', 'rid', 'Roles'),
+ 'company_id': fields.many2one('res.company', 'Company'),
+ 'context_lang': fields.selection(_lang_get, 'Language', required=True),
+ 'context_tz': fields.selection(_tz_get, 'Timezone', size=64)
+ }
+ def read(self,cr, uid, ids, fields=None, context=None, load='_classic_read'):
+ result = super(users, self).read(cr, uid, ids, fields, context, load)
+ canwrite = self.pool.get('ir.model.access').check(cr, uid, 'res.users', 'write', raise_exception=False)
+ if not canwrite:
+ for r in result:
+ if 'password' in r:
+ r['password'] = '********'
+ return result
- _sql_constraints = [
- ('login_key', 'UNIQUE (login)', 'You can not have two users with the same login !')
- ]
- def _get_action(self,cr, uid, context={}):
- ids = self.pool.get('ir.ui.menu').search(cr, uid, [('usage','=','menu')])
- return ids and ids[0] or False
+ _sql_constraints = [
+ ('login_key', 'UNIQUE (login)', 'You can not have two users with the same login !')
+ ]
+ def _get_action(self,cr, uid, context={}):
+ ids = self.pool.get('ir.ui.menu').search(cr, uid, [('usage','=','menu')])
+ return ids and ids[0] or False
- def _get_company(self,cr, uid, context={}):
- return self.pool.get('res.users').browse(cr, uid, uid, context).company_id.id
+ def _get_company(self,cr, uid, context={}):
+ return self.pool.get('res.users').browse(cr, uid, uid, context).company_id.id
- def _get_menu(self,cr, uid, context={}):
- ids = self.pool.get('ir.actions.act_window').search(cr, uid, [('usage','=','menu')])
- return ids and ids[0] or False
+ def _get_menu(self,cr, uid, context={}):
+ ids = self.pool.get('ir.actions.act_window').search(cr, uid, [('usage','=','menu')])
+ return ids and ids[0] or False
- _defaults = {
- 'password' : lambda obj,cr,uid,context={} : '',
- 'context_lang': lambda *args: 'en_US',
- 'active' : lambda obj,cr,uid,context={} : True,
- 'menu_id': _get_menu,
- 'action_id': _get_menu,
- 'company_id': _get_company,
- }
- def company_get(self, cr, uid, uid2):
- company_id = self.pool.get('res.users').browse(cr, uid, uid).company_id.id
- return company_id
- company_get = tools.cache()(company_get)
+ _defaults = {
+ 'password' : lambda obj,cr,uid,context={} : '',
+ 'context_lang': lambda *args: 'en_US',
+ 'active' : lambda obj,cr,uid,context={} : True,
+ 'menu_id': _get_menu,
+ 'action_id': _get_menu,
+ 'company_id': _get_company,
+ }
+ def company_get(self, cr, uid, uid2):
+ company_id = self.pool.get('res.users').browse(cr, uid, uid).company_id.id
+ return company_id
+ company_get = tools.cache()(company_get)
- def write(self, cr, uid, ids, values, *args, **argv):
- if (ids == [uid]):
- ok = True
- for k in values.keys():
- if k not in ('password','signature','action_id', 'context_lang', 'context_tz'):
- ok=False
- if ok:
- uid = 1
- res = super(users, self).write(cr, uid, ids, values, *args, **argv)
- self.company_get()
- # Restart the cache on the company_get method
- self.pool.get('ir.rule').domain_get()
- return res
+ def write(self, cr, uid, ids, values, *args, **argv):
+ if (ids == [uid]):
+ ok = True
+ for k in values.keys():
+ if k not in ('password','signature','action_id', 'context_lang', 'context_tz'):
+ ok=False
+ if ok:
+ uid = 1
+ res = super(users, self).write(cr, uid, ids, values, *args, **argv)
+ self.company_get()
+ # Restart the cache on the company_get method
+ self.pool.get('ir.rule').domain_get()
+ return res
- def unlink(self, cr, uid, ids):
- if 1 in ids:
- raise osv.except_osv(_('Can not remove root user!'), _('You can not remove the root user as it is used internally for resources created by Tiny ERP (updates, module installation, ...)'))
- return super(users, self).unlink(cr, uid, ids)
+ def unlink(self, cr, uid, ids):
+ if 1 in ids:
+ raise osv.except_osv(_('Can not remove root user!'), _('You can not remove the root user as it is used internally for resources created by Tiny ERP (updates, module installation, ...)'))
+ return super(users, self).unlink(cr, uid, ids)
- def name_search(self, cr, user, name='', args=None, operator='ilike', context=None, limit=80):
- if not args:
- args=[]
- if not context:
- context={}
- ids = []
- if name:
- ids = self.search(cr, user, [('login','=',name)]+ args, limit=limit)
- if not ids:
- ids = self.search(cr, user, [('name',operator,name)]+ args, limit=limit)
- return self.name_get(cr, user, ids)
+ def name_search(self, cr, user, name='', args=None, operator='ilike', context=None, limit=80):
+ if not args:
+ args=[]
+ if not context:
+ context={}
+ ids = []
+ if name:
+ ids = self.search(cr, user, [('login','=',name)]+ args, limit=limit)
+ if not ids:
+ ids = self.search(cr, user, [('name',operator,name)]+ args, limit=limit)
+ return self.name_get(cr, user, ids)
- def copy(self, cr, uid, id, default=None, context={}):
- login = self.read(cr, uid, [id], ['login'])[0]['login']
- default.update({'login': login+' (copy)'})
- return super(users, self).copy(cr, uid, id, default, context)
+ def copy(self, cr, uid, id, default=None, context={}):
+ login = self.read(cr, uid, [id], ['login'])[0]['login']
+ default.update({'login': login+' (copy)'})
+ return super(users, self).copy(cr, uid, id, default, context)
- def context_get(self, cr, uid, context={}):
- user = self.browse(cr, uid, uid, context)
- result = {}
- for k in self._columns.keys():
- if k.startswith('context_'):
- result[k[8:]] = getattr(user,k)
- return result
+ def context_get(self, cr, uid, context={}):
+ user = self.browse(cr, uid, uid, context)
+ result = {}
+ for k in self._columns.keys():
+ if k.startswith('context_'):
+ result[k[8:]] = getattr(user,k)
+ return result
- def action_get(self, cr, uid, context={}):
- dataobj = self.pool.get('ir.model.data')
- data_id = dataobj._get_id(cr, 1, 'base', 'action_res_users_my')
- return dataobj.browse(cr, uid, data_id, context).res_id
+ def action_get(self, cr, uid, context={}):
+ dataobj = self.pool.get('ir.model.data')
+ data_id = dataobj._get_id(cr, 1, 'base', 'action_res_users_my')
+ return dataobj.browse(cr, uid, data_id, context).res_id
- def action_next(self,cr,uid,ids,context=None):
- return{
- 'view_type': 'form',
- "view_mode": 'form',
- 'res_model': 'ir.module.module.configuration.wizard',
- 'type': 'ir.actions.act_window',
- 'target':'new',
- }
+ def action_next(self,cr,uid,ids,context=None):
+ return{
+ 'view_type': 'form',
+ "view_mode": 'form',
+ 'res_model': 'ir.module.module.configuration.wizard',
+ 'type': 'ir.actions.act_window',
+ 'target':'new',
+ }
- def action_continue(self,cr,uid,ids,context={}):
- return {
- 'view_type': 'form',
- "view_mode": 'form',
- 'res_model': 'ir.module.module.configuration.wizard',
- 'type': 'ir.actions.act_window',
- 'target':'new',
- }
- def action_new(self,cr,uid,ids,context={}):
- return {
- 'view_type': 'form',
- "view_mode": 'form',
- 'res_model': 'res.users',
- 'view_id':self.pool.get('ir.ui.view').search(cr,uid,[('name','=','res.users.confirm.form')]),
- 'type': 'ir.actions.act_window',
- 'target':'new',
- }
+ def action_continue(self,cr,uid,ids,context={}):
+ return {
+ 'view_type': 'form',
+ "view_mode": 'form',
+ 'res_model': 'ir.module.module.configuration.wizard',
+ 'type': 'ir.actions.act_window',
+ 'target':'new',
+ }
+ def action_new(self,cr,uid,ids,context={}):
+ return {
+ 'view_type': 'form',
+ "view_mode": 'form',
+ 'res_model': 'res.users',
+ 'view_id':self.pool.get('ir.ui.view').search(cr,uid,[('name','=','res.users.confirm.form')]),
+ 'type': 'ir.actions.act_window',
+ 'target':'new',
+ }
users()
class groups2(osv.osv):
- _inherit = 'res.groups'
- _columns = {
- 'users': fields.many2many('res.users', 'res_groups_users_rel', 'gid', 'uid', 'Users'),
- }
+ _inherit = 'res.groups'
+ _columns = {
+ 'users': fields.many2many('res.users', 'res_groups_users_rel', 'gid', 'uid', 'Users'),
+ }
groups2()
class res_config_view(osv.osv_memory):
- _name='res.config.view'
- _columns = {
- 'name':fields.char('Name', size=64),
- 'view': fields.selection([('simple','Simple'),('extended','Extended')], 'View', required=True ),
+ _name='res.config.view'
+ _columns = {
+ 'name':fields.char('Name', size=64),
+ 'view': fields.selection([('simple','Simple'),('extended','Extended')], 'View', required=True ),
}
- _defaults={
- 'view':lambda *args: 'simple',
- }
+ _defaults={
+ 'view':lambda *args: 'simple',
+ }
- def action_cancel(self,cr,uid,ids,conect=None):
- print ' Cancel action'
- return {
- 'view_type': 'form',
- "view_mode": 'form',
- 'res_model': 'ir.module.module.configuration.wizard',
- 'type': 'ir.actions.act_window',
- 'target':'new',
+ def action_cancel(self,cr,uid,ids,conect=None):
+ print ' Cancel action'
+ return {
+ 'view_type': 'form',
+ "view_mode": 'form',
+ 'res_model': 'ir.module.module.configuration.wizard',
+ 'type': 'ir.actions.act_window',
+ 'target':'new',
}
- def action_set(self, cr, uid, ids, context=None):
- res=self.read(cr,uid,ids)[0]
- users_obj = self.pool.get('res.users')
- group_obj=self.pool.get('res.groups')
- if 'view' in res and res['view'] and res['view']=='extended':
- group_ids=group_obj.search(cr,uid,[('name','=','Extended View')])
- if group_ids and len(group_ids):
- users_obj.write(cr, uid, [3],{
- 'groups_id':[(4,group_ids[0])]
- }, context=context)
- return {
- 'view_type': 'form',
- "view_mode": 'form',
- 'res_model': 'ir.module.module.configuration.wizard',
- 'type': 'ir.actions.act_window',
- 'target':'new',
- }
+ def action_set(self, cr, uid, ids, context=None):
+ res=self.read(cr,uid,ids)[0]
+ users_obj = self.pool.get('res.users')
+ group_obj=self.pool.get('res.groups')
+ if 'view' in res and res['view'] and res['view']=='extended':
+ group_ids=group_obj.search(cr,uid,[('name','=','Extended View')])
+ if group_ids and len(group_ids):
+ users_obj.write(cr, uid, [3],{
+ 'groups_id':[(4,group_ids[0])]
+ }, context=context)
+ return {
+ 'view_type': 'form',
+ "view_mode": 'form',
+ 'res_model': 'ir.module.module.configuration.wizard',
+ 'type': 'ir.actions.act_window',
+ 'target':'new',
+ }
res_config_view()
diff --git a/bin/addons/module_graph.py b/bin/addons/module_graph.py
index 6df397ac8af..a853eb8aa1f 100644
--- a/bin/addons/module_graph.py
+++ b/bin/addons/module_graph.py
@@ -45,13 +45,13 @@ done = []
print 'digraph G {'
while len(modules):
- f = modules.pop(0)
- done.append(f)
- if os.path.isfile(os.path.join(f,"__terp__.py")):
- info=eval(file(os.path.join(f,"__terp__.py")).read())
- if info.get('installable', True):
- for name in info['depends']:
- if name not in done+modules:
- modules.append(name)
- print '\t%s -> %s;' % (f, name)
+ f = modules.pop(0)
+ done.append(f)
+ if os.path.isfile(os.path.join(f,"__terp__.py")):
+ info=eval(file(os.path.join(f,"__terp__.py")).read())
+ if info.get('installable', True):
+ for name in info['depends']:
+ if name not in done+modules:
+ modules.append(name)
+ print '\t%s -> %s;' % (f, name)
print '}'
diff --git a/bin/ir/ir.py b/bin/ir/ir.py
index 1c7854bb39d..d745ee3b33a 100644
--- a/bin/ir/ir.py
+++ b/bin/ir/ir.py
@@ -31,14 +31,14 @@ import osv
import pooler
def ir_set(cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=None):
- obj = pooler.get_pool(cr.dbname).get('ir.values')
- return obj.set(cr, uid, key, key2, name, models, value, replace, isobject, meta)
+ obj = pooler.get_pool(cr.dbname).get('ir.values')
+ return obj.set(cr, uid, key, key2, name, models, value, replace, isobject, meta)
def ir_del(cr, uid, id):
- obj = pooler.get_pool(cr.dbname).get('ir.values')
- return obj.unlink(cr, uid, [id])
+ obj = pooler.get_pool(cr.dbname).get('ir.values')
+ return obj.unlink(cr, uid, [id])
def ir_get(cr, uid, key, key2, models, meta=False, context={}, res_id_req=False):
- obj = pooler.get_pool(cr.dbname).get('ir.values')
- res = obj.get(cr, uid, key, key2, models, meta=meta, context=context, res_id_req=res_id_req)
- return res
+ obj = pooler.get_pool(cr.dbname).get('ir.values')
+ res = obj.get(cr, uid, key, key2, models, meta=meta, context=context, res_id_req=res_id_req)
+ return res
diff --git a/bin/netsvc.py b/bin/netsvc.py
index d014288a9e7..b6cc5d06ff9 100644
--- a/bin/netsvc.py
+++ b/bin/netsvc.py
@@ -42,97 +42,97 @@ _res_id=1
_res={}
class ServiceEndPointCall(object):
- def __init__(self,id,method):
- self._id=id
- self._meth=method
- def __call__(self,*args):
- _res[self._id]=self._meth(*args)
- return self._id
+ def __init__(self,id,method):
+ self._id=id
+ self._meth=method
+ def __call__(self,*args):
+ _res[self._id]=self._meth(*args)
+ return self._id
class ServiceEndPoint(object):
- def __init__(self, name, id):
- self._id = id
- self._meth={}
- s=_service[name]
- for m in s._method:
- self._meth[m]=s._method[m]
- def __getattr__(self, name):
- return ServiceEndPointCall(self._id, self._meth[name])
+ def __init__(self, name, id):
+ self._id = id
+ self._meth={}
+ s=_service[name]
+ for m in s._method:
+ self._meth[m]=s._method[m]
+ def __getattr__(self, name):
+ return ServiceEndPointCall(self._id, self._meth[name])
class Service(object):
- _serviceEndPointID = 0
- def __init__(self, name, audience=''):
- _service[name]=self
- self.__name=name
- self._method={}
- self.exportedMethods=None
- self._response_process=None
- self._response_process_id=None
- self._response=None
-
- def joinGroup(self,name):
- if not name in _group:
- _group[name]={}
- _group[name][self.__name]=self
-
- def exportMethod(self, m):
- if callable(m):
- self._method[m.__name__]=m
-
- def serviceEndPoint(self,s):
- if Service._serviceEndPointID >= 2**16:
- Service._serviceEndPointID = 0
- Service._serviceEndPointID += 1
- return ServiceEndPoint(s, self._serviceEndPointID)
-
- def conversationId(self):
- return 1
-
- def processResponse(self,s,id):
- self._response_process, self._response_process_id = s, id
-
- def processFailure(self,s,id):
- pass
-
- def resumeResponse(self,s):
- pass
-
- def cancelResponse(self,s):
- pass
-
- def suspendResponse(self,s):
- if self._response_process:
- self._response_process(self._response_process_id,
- _res[self._response_process_id])
- self._response_process=None
- self._response=s(self._response_process_id)
-
- def abortResponse(self, error, description, origin, details):
- import tools
- if not tools.config['debug_mode']:
- raise Exception("%s -- %s\n\n%s"%(origin,description,details))
- else:
- raise
-
- def currentFailure(self,s):
- pass
+ _serviceEndPointID = 0
+ def __init__(self, name, audience=''):
+ _service[name]=self
+ self.__name=name
+ self._method={}
+ self.exportedMethods=None
+ self._response_process=None
+ self._response_process_id=None
+ self._response=None
+
+ def joinGroup(self,name):
+ if not name in _group:
+ _group[name]={}
+ _group[name][self.__name]=self
+
+ def exportMethod(self, m):
+ if callable(m):
+ self._method[m.__name__]=m
+
+ def serviceEndPoint(self,s):
+ if Service._serviceEndPointID >= 2**16:
+ Service._serviceEndPointID = 0
+ Service._serviceEndPointID += 1
+ return ServiceEndPoint(s, self._serviceEndPointID)
+
+ def conversationId(self):
+ return 1
+
+ def processResponse(self,s,id):
+ self._response_process, self._response_process_id = s, id
+
+ def processFailure(self,s,id):
+ pass
+
+ def resumeResponse(self,s):
+ pass
+
+ def cancelResponse(self,s):
+ pass
+
+ def suspendResponse(self,s):
+ if self._response_process:
+ self._response_process(self._response_process_id,
+ _res[self._response_process_id])
+ self._response_process=None
+ self._response=s(self._response_process_id)
+
+ def abortResponse(self, error, description, origin, details):
+ import tools
+ if not tools.config['debug_mode']:
+ raise Exception("%s -- %s\n\n%s"%(origin,description,details))
+ else:
+ raise
+
+ def currentFailure(self,s):
+ pass
class LocalService(Service):
- def __init__(self, name):
- self.__name=name
- s=_service[name]
- self._service=s
- for m in s._method:
- setattr(self,m,s._method[m])
+ def __init__(self, name):
+ self.__name=name
+ s=_service[name]
+ self._service=s
+ for m in s._method:
+ setattr(self,m,s._method[m])
class ServiceUnavailable(Exception):
- pass
+ pass
def service_exist(name):
- return (name in _service) and bool(_service[name])
+ return (name in _service) and bool(_service[name])
def get_rpc_paths():
- return map(lambda s: '/xmlrpc/%s' % s, _service)
+ return map(lambda s: '/xmlrpc/%s' % s, _service)
LOG_DEBUG='debug'
LOG_INFO='info'
@@ -141,269 +141,269 @@ LOG_ERROR='error'
LOG_CRITICAL='critical'
def init_logger():
- from tools import config
- import os
-
- if config['logfile']:
- logf = config['logfile']
- # test if the directories exist, else create them
- try:
- if not os.path.exists(os.path.dirname(logf)):
- os.makedirs(os.path.dirname(logf))
- try:
- fd = open(logf, 'a')
- handler = logging.StreamHandler(fd)
- except IOError:
- sys.stderr.write("ERROR: couldn't open the logfile\n")
- handler = logging.StreamHandler(sys.stdout)
- except OSError:
- sys.stderr.write("ERROR: couldn't create the logfile directory\n")
- handler = logging.StreamHandler(sys.stdout)
- else:
- handler = logging.StreamHandler(sys.stdout)
-
- # create a format for log messages and dates
- formatter = logging.Formatter('[%(asctime)s] %(levelname)s:%(name)s:%(message)s', '%a %b %d %H:%M:%S %Y')
-
- # tell the handler to use this format
- handler.setFormatter(formatter)
-
- # add the handler to the root logger
- logging.getLogger().addHandler(handler)
- logging.getLogger().setLevel(logging.INFO)
+ from tools import config
+ import os
+
+ if config['logfile']:
+ logf = config['logfile']
+ # test if the directories exist, else create them
+ try:
+ if not os.path.exists(os.path.dirname(logf)):
+ os.makedirs(os.path.dirname(logf))
+ try:
+ fd = open(logf, 'a')
+ handler = logging.StreamHandler(fd)
+ except IOError:
+ sys.stderr.write("ERROR: couldn't open the logfile\n")
+ handler = logging.StreamHandler(sys.stdout)
+ except OSError:
+ sys.stderr.write("ERROR: couldn't create the logfile directory\n")
+ handler = logging.StreamHandler(sys.stdout)
+ else:
+ handler = logging.StreamHandler(sys.stdout)
+
+ # create a format for log messages and dates
+ formatter = logging.Formatter('[%(asctime)s] %(levelname)s:%(name)s:%(message)s', '%a %b %d %H:%M:%S %Y')
+
+ # tell the handler to use this format
+ handler.setFormatter(formatter)
+
+ # add the handler to the root logger
+ logging.getLogger().addHandler(handler)
+ logging.getLogger().setLevel(logging.INFO)
class Logger(object):
- def notifyChannel(self,name,level,msg):
- log = logging.getLogger(name)
- getattr(log,level)(msg)
+ def notifyChannel(self,name,level,msg):
+ log = logging.getLogger(name)
+ getattr(log,level)(msg)
class Agent(object):
- _timers = []
- _logger = Logger()
-
- def setAlarm(self, fn, dt, args=None, kwargs=None):
- if not args:
- args=[]
- if not kwargs:
- kwargs={}
- wait = dt - time.time()
- if wait > 0:
- self._logger.notifyChannel('timers', LOG_DEBUG, "Job scheduled in %s seconds for %s.%s" % (wait, fn.im_class.__name__, fn.func_name))
- timer = threading.Timer(wait, fn, args, kwargs)
- timer.start()
- self._timers.append(timer)
- for timer in self._timers[:]:
- if not timer.isAlive():
- self._timers.remove(timer)
-
- def quit(cls):
- for timer in cls._timers:
- timer.cancel()
- quit=classmethod(quit)
+ _timers = []
+ _logger = Logger()
+
+ def setAlarm(self, fn, dt, args=None, kwargs=None):
+ if not args:
+ args=[]
+ if not kwargs:
+ kwargs={}
+ wait = dt - time.time()
+ if wait > 0:
+ self._logger.notifyChannel('timers', LOG_DEBUG, "Job scheduled in %s seconds for %s.%s" % (wait, fn.im_class.__name__, fn.func_name))
+ timer = threading.Timer(wait, fn, args, kwargs)
+ timer.start()
+ self._timers.append(timer)
+ for timer in self._timers[:]:
+ if not timer.isAlive():
+ self._timers.remove(timer)
+
+ def quit(cls):
+ for timer in cls._timers:
+ timer.cancel()
+ quit=classmethod(quit)
class RpcGateway(object):
- def __init__(self, name):
- self.name=name
+ def __init__(self, name):
+ self.name=name
class Dispatcher(object):
- def __init__(self):
- pass
- def monitor(self,signal):
- pass
- def run(self):
- pass
+ def __init__(self):
+ pass
+ def monitor(self,signal):
+ pass
+ def run(self):
+ pass
class xmlrpc(object):
- class RpcGateway(object):
- def __init__(self, name):
- self.name=name
+ class RpcGateway(object):
+ def __init__(self, name):
+ self.name=name
class GenericXMLRPCRequestHandler:
- def _dispatch(self, method, params):
- import traceback
- try:
- n=self.path.split("/")[-1]
- s=LocalService(n)
- m=getattr(s,method)
- s._service._response=None
- r=m(*params)
- res=s._service._response
- if res!=None:
- r=res
- return r
- except Exception, e:
- tb_s = reduce(lambda x, y: x+y, traceback.format_exception(
- sys.exc_type, sys.exc_value, sys.exc_traceback))
- s=str(e)
- import tools
- if tools.config['debug_mode']:
- import pdb
- tb = sys.exc_info()[2]
- pdb.post_mortem(tb)
- raise xmlrpclib.Fault(s, tb_s)
+ def _dispatch(self, method, params):
+ import traceback
+ try:
+ n=self.path.split("/")[-1]
+ s=LocalService(n)
+ m=getattr(s,method)
+ s._service._response=None
+ r=m(*params)
+ res=s._service._response
+ if res!=None:
+ r=res
+ return r
+ except Exception, e:
+ tb_s = reduce(lambda x, y: x+y, traceback.format_exception(
+ sys.exc_type, sys.exc_value, sys.exc_traceback))
+ s=str(e)
+ import tools
+ if tools.config['debug_mode']:
+ import pdb
+ tb = sys.exc_info()[2]
+ pdb.post_mortem(tb)
+ raise xmlrpclib.Fault(s, tb_s)
class SimpleXMLRPCRequestHandler(GenericXMLRPCRequestHandler,
- SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
- SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.rpc_paths = get_rpc_paths()
+ SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
+ SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.rpc_paths = get_rpc_paths()
class SimpleThreadedXMLRPCServer(SocketServer.ThreadingMixIn,
- SimpleXMLRPCServer.SimpleXMLRPCServer):
+ SimpleXMLRPCServer.SimpleXMLRPCServer):
- def server_bind(self):
- self.socket.setsockopt(socket.SOL_SOCKET,
- socket.SO_REUSEADDR, 1)
- SimpleXMLRPCServer.SimpleXMLRPCServer.server_bind(self)
+ def server_bind(self):
+ self.socket.setsockopt(socket.SOL_SOCKET,
+ socket.SO_REUSEADDR, 1)
+ SimpleXMLRPCServer.SimpleXMLRPCServer.server_bind(self)
class HttpDaemon(threading.Thread):
- def __init__(self, interface,port, secure=False):
- threading.Thread.__init__(self)
- self.__port=port
- self.__interface=interface
- self.secure = secure
- if secure:
- from ssl import SecureXMLRPCServer
- class SecureXMLRPCRequestHandler(GenericXMLRPCRequestHandler,
- SecureXMLRPCServer.SecureXMLRPCRequestHandler):
- SecureXMLRPCServer.SecureXMLRPCRequestHandler.rpc_paths = get_rpc_paths()
- class SecureThreadedXMLRPCServer(SocketServer.ThreadingMixIn,
- SecureXMLRPCServer.SecureXMLRPCServer):
-
- def server_bind(self):
- self.socket.setsockopt(socket.SOL_SOCKET,
- socket.SO_REUSEADDR, 1)
- SecureXMLRPCServer.SecureXMLRPCServer.server_bind(self)
-
- self.server = SecureThreadedXMLRPCServer((interface, port),
- SecureXMLRPCRequestHandler,0)
- else:
- self.server = SimpleThreadedXMLRPCServer((interface, port),
- SimpleXMLRPCRequestHandler,0)
-
- def attach(self,path,gw):
- pass
-
- def stop(self):
- self.running = False
- if os.name <> 'nt':
- if hasattr(socket, 'SHUT_RDWR'):
- if self.secure:
- self.server.socket.sock_shutdown(socket.SHUT_RDWR)
- else:
- self.server.socket.shutdown(socket.SHUT_RDWR)
- else:
- if self.secure:
- self.server.socket.sock_shutdown(2)
- else:
- self.server.socket.shutdown(2)
- self.server.socket.close()
-
- def run(self):
- self.server.register_introspection_functions()
-
- self.running = True
- while self.running:
- self.server.handle_request()
- return True
-
- # If the server need to be run recursively
- #
- #signal.signal(signal.SIGALRM, self.my_handler)
- #signal.alarm(6)
- #while True:
- # self.server.handle_request()
- #signal.alarm(0) # Disable the alarm
+ def __init__(self, interface,port, secure=False):
+ threading.Thread.__init__(self)
+ self.__port=port
+ self.__interface=interface
+ self.secure = secure
+ if secure:
+ from ssl import SecureXMLRPCServer
+ class SecureXMLRPCRequestHandler(GenericXMLRPCRequestHandler,
+ SecureXMLRPCServer.SecureXMLRPCRequestHandler):
+ SecureXMLRPCServer.SecureXMLRPCRequestHandler.rpc_paths = get_rpc_paths()
+ class SecureThreadedXMLRPCServer(SocketServer.ThreadingMixIn,
+ SecureXMLRPCServer.SecureXMLRPCServer):
+
+ def server_bind(self):
+ self.socket.setsockopt(socket.SOL_SOCKET,
+ socket.SO_REUSEADDR, 1)
+ SecureXMLRPCServer.SecureXMLRPCServer.server_bind(self)
+
+ self.server = SecureThreadedXMLRPCServer((interface, port),
+ SecureXMLRPCRequestHandler,0)
+ else:
+ self.server = SimpleThreadedXMLRPCServer((interface, port),
+ SimpleXMLRPCRequestHandler,0)
+
+ def attach(self,path,gw):
+ pass
+
+ def stop(self):
+ self.running = False
+ if os.name <> 'nt':
+ if hasattr(socket, 'SHUT_RDWR'):
+ if self.secure:
+ self.server.socket.sock_shutdown(socket.SHUT_RDWR)
+ else:
+ self.server.socket.shutdown(socket.SHUT_RDWR)
+ else:
+ if self.secure:
+ self.server.socket.sock_shutdown(2)
+ else:
+ self.server.socket.shutdown(2)
+ self.server.socket.close()
+
+ def run(self):
+ self.server.register_introspection_functions()
+
+ self.running = True
+ while self.running:
+ self.server.handle_request()
+ return True
+
+ # If the server need to be run recursively
+ #
+ #signal.signal(signal.SIGALRM, self.my_handler)
+ #signal.alarm(6)
+ #while True:
+ # self.server.handle_request()
+ #signal.alarm(0) # Disable the alarm
import tiny_socket
class TinySocketClientThread(threading.Thread):
- def __init__(self, sock, threads):
- threading.Thread.__init__(self)
- self.sock = sock
- self.threads = threads
-
- def run(self):
- import traceback
- import time
- import select
- self.running = True
- try:
- ts = tiny_socket.mysocket(self.sock)
- except:
- self.sock.close()
- self.threads.remove(self)
- return False
- while self.running:
- try:
- msg = ts.myreceive()
- except:
- self.sock.close()
- self.threads.remove(self)
- return False
- try:
- s=LocalService(msg[0])
- m=getattr(s,msg[1])
- s._service._response=None
- r=m(*msg[2:])
- res=s._service._response
- if res!=None:
- r=res
- ts.mysend(r)
- except Exception, e:
- tb_s = reduce(lambda x, y: x+y, traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback))
- s=str(e)
- import tools
- if tools.config['debug_mode']:
- import pdb
- tb = sys.exc_info()[2]
- pdb.post_mortem(tb)
- ts.mysend(e, exception=True, traceback=tb_s)
- except:
- pass
- self.sock.close()
- self.threads.remove(self)
- return True
-
- def stop(self):
- self.running = False
+ def __init__(self, sock, threads):
+ threading.Thread.__init__(self)
+ self.sock = sock
+ self.threads = threads
+
+ def run(self):
+ import traceback
+ import time
+ import select
+ self.running = True
+ try:
+ ts = tiny_socket.mysocket(self.sock)
+ except:
+ self.sock.close()
+ self.threads.remove(self)
+ return False
+ while self.running:
+ try:
+ msg = ts.myreceive()
+ except:
+ self.sock.close()
+ self.threads.remove(self)
+ return False
+ try:
+ s=LocalService(msg[0])
+ m=getattr(s,msg[1])
+ s._service._response=None
+ r=m(*msg[2:])
+ res=s._service._response
+ if res!=None:
+ r=res
+ ts.mysend(r)
+ except Exception, e:
+ tb_s = reduce(lambda x, y: x+y, traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback))
+ s=str(e)
+ import tools
+ if tools.config['debug_mode']:
+ import pdb
+ tb = sys.exc_info()[2]
+ pdb.post_mortem(tb)
+ ts.mysend(e, exception=True, traceback=tb_s)
+ except:
+ pass
+ self.sock.close()
+ self.threads.remove(self)
+ return True
+
+ def stop(self):
+ self.running = False
class TinySocketServerThread(threading.Thread):
- def __init__(self, interface, port, secure=False):
- threading.Thread.__init__(self)
- self.__port=port
- self.__interface=interface
- self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- self.socket.bind((self.__interface, self.__port))
- self.socket.listen(5)
- self.threads = []
-
- def run(self):
- import select
- try:
- self.running = True
- while self.running:
- (clientsocket, address) = self.socket.accept()
- ct = TinySocketClientThread(clientsocket, self.threads)
- self.threads.append(ct)
- ct.start()
- self.socket.close()
- except Exception, e:
- self.socket.close()
- return False
-
- def stop(self):
- self.running=False
- for t in self.threads:
- t.stop()
- try:
- if hasattr(socket, 'SHUT_RDWR'):
- self.socket.shutdown(socket.SHUT_RDWR)
- else:
- self.socket.shutdown(2)
- self.socket.close()
- except:
- return False
+ def __init__(self, interface, port, secure=False):
+ threading.Thread.__init__(self)
+ self.__port=port
+ self.__interface=interface
+ self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ self.socket.bind((self.__interface, self.__port))
+ self.socket.listen(5)
+ self.threads = []
+
+ def run(self):
+ import select
+ try:
+ self.running = True
+ while self.running:
+ (clientsocket, address) = self.socket.accept()
+ ct = TinySocketClientThread(clientsocket, self.threads)
+ self.threads.append(ct)
+ ct.start()
+ self.socket.close()
+ except Exception, e:
+ self.socket.close()
+ return False
+
+ def stop(self):
+ self.running=False
+ for t in self.threads:
+ t.stop()
+ try:
+ if hasattr(socket, 'SHUT_RDWR'):
+ self.socket.shutdown(socket.SHUT_RDWR)
+ else:
+ self.socket.shutdown(2)
+ self.socket.close()
+ except:
+ return False
# vim:noexpandtab:
diff --git a/bin/osv/fields.py b/bin/osv/fields.py
index 8f6ee185ad8..ab10cf9ade5 100644
--- a/bin/osv/fields.py
+++ b/bin/osv/fields.py
@@ -49,149 +49,149 @@ import warnings
import tools
def _symbol_set(symb):
- if symb==None or symb==False:
- return None
- elif isinstance(symb, unicode):
- return symb.encode('utf-8')
- return str(symb)
+ if symb==None or symb==False:
+ return None
+ elif isinstance(symb, unicode):
+ return symb.encode('utf-8')
+ return str(symb)
class _column(object):
- _classic_read = True
- _classic_write = True
- _properties = False
- _type = 'unknown'
- _obj = None
- _symbol_c = '%s'
- _symbol_f = _symbol_set
- _symbol_set = (_symbol_c, _symbol_f)
- _symbol_get = None
-
- def __init__(self, string='unknown', required=False, readonly=False, domain=None, context='', states=None, priority=0, change_default=False, size=None, ondelete="set null", translate=False, select=False, **args):
- self.states = states or {}
- self.string = string
- self.readonly = readonly
- self.required = required
- self.size = size
- self.help = args.get('help', '')
- self.priority = priority
- self.change_default = change_default
- self.ondelete = ondelete
- self.translate = translate
- self._domain = domain or []
- self.relate =False
- self._context = context
- self.group_name = False
- self.write = False
- self.read = False
- self.view_load = 0
- self.select=select
- for a in args:
- if args[a]:
- setattr(self, a, args[a])
- if self.relate:
- warnings.warn("The relate attribute doesn't work anymore, use act_window tag instead", DeprecationWarning)
-
- def restart(self):
- 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) )
- def set_memory(self, cr, obj, id, name, value, user=None, context=None):
- raise Exception, _('Not implemented set_memory method !')
-
- def get_memory(self, cr, obj, ids, name, context=None, values=None):
- raise Exception, _('Not implemented get_memory method !')
- def get(self, cr, obj, ids, name, context=None, values=None):
- raise Exception, _('undefined get method !')
-
- def search(self, cr, obj, args, name, value, offset=0, limit=None, uid=None):
- ids = obj.search(cr, uid, args+self._domain+[(name,'ilike',value)], offset, limit)
- res = obj.read(cr, uid, ids, [name])
- return [x[name] for x in res]
- def search_memory(self, cr, obj, args, name, value, offset=0, limit=None, uid=None, context=None):
- raise Exception, _('Not implemented search_memory method !')
+ _classic_read = True
+ _classic_write = True
+ _properties = False
+ _type = 'unknown'
+ _obj = None
+ _symbol_c = '%s'
+ _symbol_f = _symbol_set
+ _symbol_set = (_symbol_c, _symbol_f)
+ _symbol_get = None
+
+ def __init__(self, string='unknown', required=False, readonly=False, domain=None, context='', states=None, priority=0, change_default=False, size=None, ondelete="set null", translate=False, select=False, **args):
+ self.states = states or {}
+ self.string = string
+ self.readonly = readonly
+ self.required = required
+ self.size = size
+ self.help = args.get('help', '')
+ self.priority = priority
+ self.change_default = change_default
+ self.ondelete = ondelete
+ self.translate = translate
+ self._domain = domain or []
+ self.relate =False
+ self._context = context
+ self.group_name = False
+ self.write = False
+ self.read = False
+ self.view_load = 0
+ self.select=select
+ for a in args:
+ if args[a]:
+ setattr(self, a, args[a])
+ if self.relate:
+ warnings.warn("The relate attribute doesn't work anymore, use act_window tag instead", DeprecationWarning)
+
+ def restart(self):
+ 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) )
+ def set_memory(self, cr, obj, id, name, value, user=None, context=None):
+ raise Exception, _('Not implemented set_memory method !')
+
+ def get_memory(self, cr, obj, ids, name, context=None, values=None):
+ raise Exception, _('Not implemented get_memory method !')
+ def get(self, cr, obj, ids, name, context=None, values=None):
+ raise Exception, _('undefined get method !')
+
+ def search(self, cr, obj, args, name, value, offset=0, limit=None, uid=None):
+ ids = obj.search(cr, uid, args+self._domain+[(name,'ilike',value)], offset, limit)
+ res = obj.read(cr, uid, ids, [name])
+ return [x[name] for x in res]
+ def search_memory(self, cr, obj, args, name, value, offset=0, limit=None, uid=None, context=None):
+ raise Exception, _('Not implemented search_memory method !')
# ---------------------------------------------------------
# Simple fields
# ---------------------------------------------------------
class boolean(_column):
- _type = 'boolean'
- _symbol_c = '%s'
- _symbol_f = lambda x: x and 'True' or 'False'
- _symbol_set = (_symbol_c, _symbol_f)
+ _type = 'boolean'
+ _symbol_c = '%s'
+ _symbol_f = lambda x: x and 'True' or 'False'
+ _symbol_set = (_symbol_c, _symbol_f)
class integer(_column):
- _type = 'integer'
- _symbol_c = '%d'
- _symbol_f = lambda x: int(x or 0)
- _symbol_set = (_symbol_c, _symbol_f)
+ _type = 'integer'
+ _symbol_c = '%d'
+ _symbol_f = lambda x: int(x or 0)
+ _symbol_set = (_symbol_c, _symbol_f)
class reference(_column):
- _type = 'reference'
- def __init__(self, string, selection, size, **args):
- _column.__init__(self, string=string, size=size, selection=selection, **args)
+ _type = 'reference'
+ def __init__(self, string, selection, size, **args):
+ _column.__init__(self, string=string, size=size, selection=selection, **args)
class char(_column):
- _type = 'char'
-
- def __init__(self, string, size, **args):
- _column.__init__(self, string=string, size=size, **args)
- self._symbol_set = (self._symbol_c, self._symbol_set_char)
-
- # takes a string (encoded in utf8) and returns a string (encoded in utf8)
- def _symbol_set_char(self, symb):
- #TODO:
- # * we need to remove the "symb==False" from the next line BUT
- # for now too many things rely on this broken behavior
- # * the symb==None test should be common to all data types
- if symb==None or symb==False:
- return None
-
- # we need to convert the string to a unicode object to be able
- # to evaluate its length (and possibly truncate it) reliably
- if isinstance(symb, str):
- u_symb = unicode(symb, 'utf8')
- elif isinstance(symb, unicode):
- u_symb = symb
- else:
- u_symb = unicode(symb)
- return u_symb.encode('utf8')[:self.size]
+ _type = 'char'
+
+ def __init__(self, string, size, **args):
+ _column.__init__(self, string=string, size=size, **args)
+ self._symbol_set = (self._symbol_c, self._symbol_set_char)
+
+ # takes a string (encoded in utf8) and returns a string (encoded in utf8)
+ def _symbol_set_char(self, symb):
+ #TODO:
+ # * we need to remove the "symb==False" from the next line BUT
+ # for now too many things rely on this broken behavior
+ # * the symb==None test should be common to all data types
+ if symb==None or symb==False:
+ return None
+
+ # we need to convert the string to a unicode object to be able
+ # to evaluate its length (and possibly truncate it) reliably
+ if isinstance(symb, str):
+ u_symb = unicode(symb, 'utf8')
+ elif isinstance(symb, unicode):
+ u_symb = symb
+ else:
+ u_symb = unicode(symb)
+ return u_symb.encode('utf8')[:self.size]
class text(_column):
- _type = 'text'
+ _type = 'text'
import __builtin__
class float(_column):
- _type = 'float'
- _symbol_c = '%f'
- _symbol_f = lambda x: __builtin__.float(x or 0.0)
- _symbol_set = (_symbol_c, _symbol_f)
- def __init__(self, string='unknown', digits=None, **args):
- _column.__init__(self, string=string, **args)
- self.digits = digits
+ _type = 'float'
+ _symbol_c = '%f'
+ _symbol_f = lambda x: __builtin__.float(x or 0.0)
+ _symbol_set = (_symbol_c, _symbol_f)
+ def __init__(self, string='unknown', digits=None, **args):
+ _column.__init__(self, string=string, **args)
+ self.digits = digits
class date(_column):
- _type = 'date'
+ _type = 'date'
class datetime(_column):
- _type = 'datetime'
+ _type = 'datetime'
class time(_column):
- _type = 'time'
+ _type = 'time'
class binary(_column):
- _type = 'binary'
- _symbol_c = '%s'
- _symbol_f = lambda symb: symb and psycopg.Binary(symb) or None
- _symbol_set = (_symbol_c, _symbol_f)
+ _type = 'binary'
+ _symbol_c = '%s'
+ _symbol_f = lambda symb: symb and psycopg.Binary(symb) or None
+ _symbol_set = (_symbol_c, _symbol_f)
class selection(_column):
- _type = 'selection'
-
- def __init__(self, selection, string='unknown', **args):
- _column.__init__(self, string=string, **args)
- self.selection = selection
+ _type = 'selection'
+
+ def __init__(self, selection, string='unknown', **args):
+ _column.__init__(self, string=string, **args)
+ self.selection = selection
# ---------------------------------------------------------
# Relationals fields
@@ -207,208 +207,208 @@ class selection(_column):
#
#CHECKME: dans la pratique c'est quoi la syntaxe utilisee pour le 5? (5) ou (5, 0)?
class one2one(_column):
- _classic_read = False
- _classic_write = True
- _type = 'one2one'
-
- def __init__(self, obj, string='unknown', **args):
- warnings.warn("The one2one field doesn't work anymore", DeprecationWarning)
- _column.__init__(self, string=string, **args)
- self._obj = obj
-
- def set(self, cr, obj_src, id, field, act, user=None, context=None):
- if not context:
- context={}
- obj = obj_src.pool.get(self._obj)
- 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))
- else:
- cr.execute('select '+field+' from '+obj_src._table+' where id=%d', (act[0],))
- id =cr.fetchone()[0]
- obj.write(cr, user, [id] , act[1], context=context)
-
- 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)
+ _classic_read = False
+ _classic_write = True
+ _type = 'one2one'
+
+ def __init__(self, obj, string='unknown', **args):
+ warnings.warn("The one2one field doesn't work anymore", DeprecationWarning)
+ _column.__init__(self, string=string, **args)
+ self._obj = obj
+
+ def set(self, cr, obj_src, id, field, act, user=None, context=None):
+ if not context:
+ context={}
+ obj = obj_src.pool.get(self._obj)
+ 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))
+ else:
+ cr.execute('select '+field+' from '+obj_src._table+' where id=%d', (act[0],))
+ id =cr.fetchone()[0]
+ obj.write(cr, user, [id] , act[1], context=context)
+
+ 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)
class many2one(_column):
- _classic_read = False
- _classic_write = True
- _type = 'many2one'
-
- def __init__(self, obj, string='unknown', **args):
- _column.__init__(self, string=string, **args)
- self._obj = obj
-
- #
- # TODO: speed improvement
- #
- # name is the name of the relation field
- def get_memory(self, cr, obj, ids, name, user=None, context=None, values=None):
- result = {}
- for id in ids:
- result[id] = obj.datas[id][name]
- return result
-
- def get(self, cr, obj, ids, name, user=None, context=None, values=None):
- if not context:
- context={}
- if not values:
- values={}
- res = {}
- for r in values:
- res[r['id']] = r[name]
- for id in ids:
- res.setdefault(id, '')
- obj = obj.pool.get(self._obj)
- # build a dictionary of the form {'id_of_distant_resource': name_of_distant_resource}
- from orm import except_orm
- try:
- names = dict(obj.name_get(cr, user, filter(None, res.values()), context))
- except except_orm:
- names={}
-
- iids = filter(None, res.values())
- cr.execute('select id,'+obj._rec_name+' from '+obj._table+' where id in ('+','.join(map(str,iids))+')')
- for res22 in cr.fetchall():
- names[res22[0]] = res22[1]
-
- for r in res.keys():
- if res[r] and res[r] in names:
- res[r] = (res[r], names[res[r]])
- else:
- res[r] = False
- return res
-
- def set(self, cr, obj_src, id, field, values, user=None, context=None):
- if not context:
- context={}
- obj = obj_src.pool.get(self._obj)
- self._table = obj_src.pool.get(self._obj)._table
- if type(values)==type([]):
- 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))
- 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],))
- elif act[0]==3 or act[0]==5:
- cr.execute('update '+obj_src._table+' set '+field+'=null where id=%d', (id,))
- elif act[0]==4:
- cr.execute('update '+obj_src._table+' set '+field+'=%d where id=%d', (act[1],id))
- else:
- if values:
- cr.execute('update '+obj_src._table+' set '+field+'=%d where id=%d', (values,id))
- else:
- cr.execute('update '+obj_src._table+' set '+field+'=null where id=%d', (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)
+ _classic_read = False
+ _classic_write = True
+ _type = 'many2one'
+
+ def __init__(self, obj, string='unknown', **args):
+ _column.__init__(self, string=string, **args)
+ self._obj = obj
+
+ #
+ # TODO: speed improvement
+ #
+ # name is the name of the relation field
+ def get_memory(self, cr, obj, ids, name, user=None, context=None, values=None):
+ result = {}
+ for id in ids:
+ result[id] = obj.datas[id][name]
+ return result
+
+ def get(self, cr, obj, ids, name, user=None, context=None, values=None):
+ if not context:
+ context={}
+ if not values:
+ values={}
+ res = {}
+ for r in values:
+ res[r['id']] = r[name]
+ for id in ids:
+ res.setdefault(id, '')
+ obj = obj.pool.get(self._obj)
+ # build a dictionary of the form {'id_of_distant_resource': name_of_distant_resource}
+ from orm import except_orm
+ try:
+ names = dict(obj.name_get(cr, user, filter(None, res.values()), context))
+ except except_orm:
+ names={}
+
+ iids = filter(None, res.values())
+ cr.execute('select id,'+obj._rec_name+' from '+obj._table+' where id in ('+','.join(map(str,iids))+')')
+ for res22 in cr.fetchall():
+ names[res22[0]] = res22[1]
+
+ for r in res.keys():
+ if res[r] and res[r] in names:
+ res[r] = (res[r], names[res[r]])
+ else:
+ res[r] = False
+ return res
+
+ def set(self, cr, obj_src, id, field, values, user=None, context=None):
+ if not context:
+ context={}
+ obj = obj_src.pool.get(self._obj)
+ self._table = obj_src.pool.get(self._obj)._table
+ if type(values)==type([]):
+ 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))
+ 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],))
+ elif act[0]==3 or act[0]==5:
+ cr.execute('update '+obj_src._table+' set '+field+'=null where id=%d', (id,))
+ elif act[0]==4:
+ cr.execute('update '+obj_src._table+' set '+field+'=%d where id=%d', (act[1],id))
+ else:
+ if values:
+ cr.execute('update '+obj_src._table+' set '+field+'=%d where id=%d', (values,id))
+ else:
+ cr.execute('update '+obj_src._table+' set '+field+'=null where id=%d', (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)
class one2many(_column):
- _classic_read = False
- _classic_write = False
- _type = 'one2many'
-
- def __init__(self, obj, fields_id, string='unknown', limit=None, **args):
- _column.__init__(self, string=string, **args)
- self._obj = obj
- self._fields_id = fields_id
- self._limit = limit
- #one2many can't be used as condition for defaults
- assert(self.change_default != True)
-
- def get_memory(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None):
- if not context:
- context = {}
- if not values:
- values = {}
- res = {}
- for id in ids:
- res[id] = []
- ids2 = obj.pool.get(self._obj).search(cr, user, [(self._fields_id,'in',ids)], limit=self._limit)
- for r in obj.pool.get(self._obj).read(cr, user, ids2, [self._fields_id], context=context, load='_classic_write'):
- if r[self._fields_id] in res:
- res[r[self._fields_id]].append( r['id'] )
- return res
-
- def set_memory(self, cr, obj, id, field, values, user=None, context=None):
- if not context:
- context={}
- if not values:
- return
- obj = obj.pool.get(self._obj)
- for act in values:
- if act[0]==0:
- act[2][self._fields_id] = id
- obj.create(cr, user, act[2], context=context)
- 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:
- obj.datas[act[1]][self._fields_id] = False
- elif act[0]==4:
- obj.datas[act[1]] = id
- elif act[0]==5:
- for o in obj.datas.values():
- if o[self._fields_id]==id:
- o[self._fields_id] = False
- elif act[0]==6:
- for id2 in (act[2] or []):
- obj.datas[id2][self._fields_id] = id
-
- def search_memory(self, cr, obj, args, name, value, offset=0, limit=None, uid=None, operator='like', context=None):
- raise _('Not Implemented')
-
-
- def get(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None):
- if not context:
- context = {}
- if not values:
- values = {}
- res = {}
- for id in ids:
- res[id] = []
- ids2 = obj.pool.get(self._obj).search(cr, user, [(self._fields_id,'in',ids)], limit=self._limit)
- for r in obj.pool.get(self._obj)._read_flat(cr, user, ids2, [self._fields_id], context=context, load='_classic_write'):
- res[r[self._fields_id]].append( r['id'] )
- return res
-
- def set(self, cr, obj, id, field, values, user=None, context=None):
- if not context:
- context={}
- if not values:
- return
- _table = obj.pool.get(self._obj)._table
- obj = obj.pool.get(self._obj)
- for act in values:
- if act[0]==0:
- act[2][self._fields_id] = id
- obj.create(cr, user, act[2], context=context)
- 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('update '+_table+' set '+self._fields_id+'=null where id=%d', (act[1],))
- elif act[0]==4:
- cr.execute('update '+_table+' set '+self._fields_id+'=%d where id=%d', (id,act[1]))
- elif act[0]==5:
- cr.execute('update '+_table+' set '+self._fields_id+'=null where '+self._fields_id+'=%d', (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,))
- if act[2]:
- cr.execute('update '+_table+' set '+self._fields_id+'=%d 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)
+ _classic_read = False
+ _classic_write = False
+ _type = 'one2many'
+
+ def __init__(self, obj, fields_id, string='unknown', limit=None, **args):
+ _column.__init__(self, string=string, **args)
+ self._obj = obj
+ self._fields_id = fields_id
+ self._limit = limit
+ #one2many can't be used as condition for defaults
+ assert(self.change_default != True)
+
+ def get_memory(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None):
+ if not context:
+ context = {}
+ if not values:
+ values = {}
+ res = {}
+ for id in ids:
+ res[id] = []
+ ids2 = obj.pool.get(self._obj).search(cr, user, [(self._fields_id,'in',ids)], limit=self._limit)
+ for r in obj.pool.get(self._obj).read(cr, user, ids2, [self._fields_id], context=context, load='_classic_write'):
+ if r[self._fields_id] in res:
+ res[r[self._fields_id]].append( r['id'] )
+ return res
+
+ def set_memory(self, cr, obj, id, field, values, user=None, context=None):
+ if not context:
+ context={}
+ if not values:
+ return
+ obj = obj.pool.get(self._obj)
+ for act in values:
+ if act[0]==0:
+ act[2][self._fields_id] = id
+ obj.create(cr, user, act[2], context=context)
+ 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:
+ obj.datas[act[1]][self._fields_id] = False
+ elif act[0]==4:
+ obj.datas[act[1]] = id
+ elif act[0]==5:
+ for o in obj.datas.values():
+ if o[self._fields_id]==id:
+ o[self._fields_id] = False
+ elif act[0]==6:
+ for id2 in (act[2] or []):
+ obj.datas[id2][self._fields_id] = id
+
+ def search_memory(self, cr, obj, args, name, value, offset=0, limit=None, uid=None, operator='like', context=None):
+ raise _('Not Implemented')
+
+
+ def get(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None):
+ if not context:
+ context = {}
+ if not values:
+ values = {}
+ res = {}
+ for id in ids:
+ res[id] = []
+ ids2 = obj.pool.get(self._obj).search(cr, user, [(self._fields_id,'in',ids)], limit=self._limit)
+ for r in obj.pool.get(self._obj)._read_flat(cr, user, ids2, [self._fields_id], context=context, load='_classic_write'):
+ res[r[self._fields_id]].append( r['id'] )
+ return res
+
+ def set(self, cr, obj, id, field, values, user=None, context=None):
+ if not context:
+ context={}
+ if not values:
+ return
+ _table = obj.pool.get(self._obj)._table
+ obj = obj.pool.get(self._obj)
+ for act in values:
+ if act[0]==0:
+ act[2][self._fields_id] = id
+ obj.create(cr, user, act[2], context=context)
+ 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('update '+_table+' set '+self._fields_id+'=null where id=%d', (act[1],))
+ elif act[0]==4:
+ cr.execute('update '+_table+' set '+self._fields_id+'=%d where id=%d', (id,act[1]))
+ elif act[0]==5:
+ cr.execute('update '+_table+' set '+self._fields_id+'=null where '+self._fields_id+'=%d', (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,))
+ if act[2]:
+ cr.execute('update '+_table+' set '+self._fields_id+'=%d 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)
#
# Values: (0, 0, { fields }) create
@@ -420,107 +420,107 @@ class one2many(_column):
# (6, ?, ids) set a list of links
#
class many2many(_column):
- _classic_read = False
- _classic_write = False
- _type = 'many2many'
-
- def __init__(self, obj, rel, id1, id2, string='unknown', limit=None, **args):
- _column.__init__(self, string=string, **args)
- self._obj = obj
- self._rel = rel
- self._id1 = id1
- self._id2 = id2
- self._limit = limit
-
- def get(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None):
- if not context:
- context={}
- if not values:
- values={}
- res = {}
- if not ids:
- return res
- for id in ids:
- res[id] = []
- ids_s = ','.join(map(str,ids))
- limit_str = self._limit is not None and ' limit %d' % self._limit or ''
- obj = obj.pool.get(self._obj)
-
- d1, d2 = obj.pool.get('ir.rule').domain_get(cr, user, obj._name)
- if d1:
- d1 = ' and '+d1
-
- cr.execute('SELECT '+self._rel+'.'+self._id2+','+self._rel+'.'+self._id1+' \
- 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',
- d2+[offset])
- for r in cr.fetchall():
- res[r[1]].append(r[0])
- return res
-
- def set(self, cr, obj, id, name, values, user=None, context=None):
- if not context:
- context={}
- if not values:
- return
- obj = obj.pool.get(self._obj)
- 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))
- 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]))
- elif act[0]==4:
- cr.execute('insert into '+self._rel+' ('+self._id1+','+self._id2+') values (%d,%d)', (id,act[1]))
- elif act[0]==5:
- cr.execute('update '+self._rel+' set '+self._id2+'=null where '+self._id2+'=%d', (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 )
-
- for act_nbr in act[2]:
- cr.execute('insert into '+self._rel+' ('+self._id1+','+self._id2+') values (%d, %d)', (id, act_nbr))
-
- #
- # TODO: use a name_search
- #
- def search(self, cr, obj, args, name, value, offset=0, limit=None, uid=None, operator='like'):
- return obj.pool.get(self._obj).search(cr, uid, args+self._domain+[('name',operator,value)], offset, limit)
-
- def get_memory(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None):
- result = {}
- for id in ids:
- result[id] = obj.datas[id].get(name, [])
- return result
-
- def set_memory(self, cr, obj, id, name, values, user=None, context=None):
- if not values:
- return
- for act in values:
- # TODO: use constants instead of these magic numbers
- if act[0]==0:
- raise _('Not Implemented')
- elif act[0]==1:
- raise _('Not Implemented')
- elif act[0]==2:
- raise _('Not Implemented')
- elif act[0]==3:
- raise _('Not Implemented')
- elif act[0]==4:
- raise _('Not Implemented')
- elif act[0]==5:
- raise _('Not Implemented')
- elif act[0]==6:
- obj.datas[id][name] = act[2]
+ _classic_read = False
+ _classic_write = False
+ _type = 'many2many'
+
+ def __init__(self, obj, rel, id1, id2, string='unknown', limit=None, **args):
+ _column.__init__(self, string=string, **args)
+ self._obj = obj
+ self._rel = rel
+ self._id1 = id1
+ self._id2 = id2
+ self._limit = limit
+
+ def get(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None):
+ if not context:
+ context={}
+ if not values:
+ values={}
+ res = {}
+ if not ids:
+ return res
+ for id in ids:
+ res[id] = []
+ ids_s = ','.join(map(str,ids))
+ limit_str = self._limit is not None and ' limit %d' % self._limit or ''
+ obj = obj.pool.get(self._obj)
+
+ d1, d2 = obj.pool.get('ir.rule').domain_get(cr, user, obj._name)
+ if d1:
+ d1 = ' and '+d1
+
+ cr.execute('SELECT '+self._rel+'.'+self._id2+','+self._rel+'.'+self._id1+' \
+ 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',
+ d2+[offset])
+ for r in cr.fetchall():
+ res[r[1]].append(r[0])
+ return res
+
+ def set(self, cr, obj, id, name, values, user=None, context=None):
+ if not context:
+ context={}
+ if not values:
+ return
+ obj = obj.pool.get(self._obj)
+ 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))
+ 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]))
+ elif act[0]==4:
+ cr.execute('insert into '+self._rel+' ('+self._id1+','+self._id2+') values (%d,%d)', (id,act[1]))
+ elif act[0]==5:
+ cr.execute('update '+self._rel+' set '+self._id2+'=null where '+self._id2+'=%d', (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 )
+
+ for act_nbr in act[2]:
+ cr.execute('insert into '+self._rel+' ('+self._id1+','+self._id2+') values (%d, %d)', (id, act_nbr))
+
+ #
+ # TODO: use a name_search
+ #
+ def search(self, cr, obj, args, name, value, offset=0, limit=None, uid=None, operator='like'):
+ return obj.pool.get(self._obj).search(cr, uid, args+self._domain+[('name',operator,value)], offset, limit)
+
+ def get_memory(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None):
+ result = {}
+ for id in ids:
+ result[id] = obj.datas[id].get(name, [])
+ return result
+
+ def set_memory(self, cr, obj, id, name, values, user=None, context=None):
+ if not values:
+ return
+ for act in values:
+ # TODO: use constants instead of these magic numbers
+ if act[0]==0:
+ raise _('Not Implemented')
+ elif act[0]==1:
+ raise _('Not Implemented')
+ elif act[0]==2:
+ raise _('Not Implemented')
+ elif act[0]==3:
+ raise _('Not Implemented')
+ elif act[0]==4:
+ raise _('Not Implemented')
+ elif act[0]==5:
+ raise _('Not Implemented')
+ elif act[0]==6:
+ obj.datas[id][name] = act[2]
# ---------------------------------------------------------
@@ -528,151 +528,151 @@ class many2many(_column):
# ---------------------------------------------------------
class function(_column):
- _classic_read = False
- _classic_write = False
- _type = 'function'
- _properties = True
-
- def __init__(self, fnct, arg=None, fnct_inv=None, fnct_inv_arg=None, type='float', fnct_search=None, obj=None, method=False, store=False, **args):
- _column.__init__(self, **args)
- self._obj = obj
- self._method = method
- self._fnct = fnct
- self._fnct_inv = fnct_inv
- self._arg = arg
- if 'relation' in args:
- self._obj = args['relation']
- self._fnct_inv_arg = fnct_inv_arg
- if not fnct_inv:
- self.readonly = 1
- self._type = type
- self._fnct_search = fnct_search
- self.store = store
- 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)
-
- def search(self, cr, uid, obj, name, args):
- if not self._fnct_search:
- #CHECKME: should raise an exception
- return []
- return self._fnct_search(obj, cr, uid, obj, name, args)
-
- def get(self, cr, obj, ids, name, user=None, context=None, values=None):
- if not context:
- context={}
- if not values:
- values={}
- res = {}
- table = obj._table
- if self._method:
- # TODO get HAS to receive uid for permissions !
- return self._fnct(obj, cr, user, ids, name, self._arg, context)
- else:
- return self._fnct(cr, table, ids, name, self._arg, context)
-
- def set(self, cr, obj, id, name, value, user=None, context=None):
- if not context:
- context={}
- if self._fnct_inv:
- self._fnct_inv(obj, cr, user, id, name, value, self._fnct_inv_arg, context)
+ _classic_read = False
+ _classic_write = False
+ _type = 'function'
+ _properties = True
+
+ def __init__(self, fnct, arg=None, fnct_inv=None, fnct_inv_arg=None, type='float', fnct_search=None, obj=None, method=False, store=False, **args):
+ _column.__init__(self, **args)
+ self._obj = obj
+ self._method = method
+ self._fnct = fnct
+ self._fnct_inv = fnct_inv
+ self._arg = arg
+ if 'relation' in args:
+ self._obj = args['relation']
+ self._fnct_inv_arg = fnct_inv_arg
+ if not fnct_inv:
+ self.readonly = 1
+ self._type = type
+ self._fnct_search = fnct_search
+ self.store = store
+ 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)
+
+ def search(self, cr, uid, obj, name, args):
+ if not self._fnct_search:
+ #CHECKME: should raise an exception
+ return []
+ return self._fnct_search(obj, cr, uid, obj, name, args)
+
+ def get(self, cr, obj, ids, name, user=None, context=None, values=None):
+ if not context:
+ context={}
+ if not values:
+ values={}
+ res = {}
+ table = obj._table
+ if self._method:
+ # TODO get HAS to receive uid for permissions !
+ return self._fnct(obj, cr, user, ids, name, self._arg, context)
+ else:
+ return self._fnct(cr, table, ids, name, self._arg, context)
+
+ def set(self, cr, obj, id, name, value, user=None, context=None):
+ if not context:
+ context={}
+ if self._fnct_inv:
+ self._fnct_inv(obj, cr, user, id, name, value, self._fnct_inv_arg, context)
# ---------------------------------------------------------
# Serialized fields
# ---------------------------------------------------------
class serialized(_column):
- def __init__(self, string='unknown', serialize_func=repr, deserialize_func=eval, type='text', **args):
- self._serialize_func = serialize_func
- self._deserialize_func = deserialize_func
- self._type = type
- self._symbol_set = (self._symbol_c, self._serialize_func)
- self._symbol_get = self._deserialize_func
- super(serialized, self).__init__(string=string, **args)
+ def __init__(self, string='unknown', serialize_func=repr, deserialize_func=eval, type='text', **args):
+ self._serialize_func = serialize_func
+ self._deserialize_func = deserialize_func
+ self._type = type
+ self._symbol_set = (self._symbol_c, self._serialize_func)
+ self._symbol_get = self._deserialize_func
+ super(serialized, self).__init__(string=string, **args)
class property(function):
- def _fnct_write(self, obj, cr, uid, id, prop, id_val, val, context=None):
- if not context:
- context={}
- (obj_dest,) = val
- definition_id = self._field_get(cr, uid, obj._name, prop)
-
- property = obj.pool.get('ir.property')
- 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(),))
-
- nid = property.search(cr, uid, [('fields_id', '=', definition_id),
- ('res_id', '=', False)])
- default_val = False
- if nid:
- default_val = property.browse(cr, uid, nid[0], context).value
-
- company_id = obj.pool.get('res.users').company_get(cr, uid, uid)
- res = False
- newval = (id_val and obj_dest+','+str(id_val)) or False
- if (newval != default_val) and newval:
- propdef = obj.pool.get('ir.model.fields').browse(cr, uid,
- definition_id, context=context)
- res = property.create(cr, uid, {
- 'name': propdef.name,
- 'value': newval,
- 'res_id': obj._name+','+str(id),
- 'company_id': company_id,
- 'fields_id': definition_id
- }, context=context)
- return res
-
- def _fnct_read(self, obj, cr, uid, ids, prop, val, context=None):
- if not context:
- context={}
- property = obj.pool.get('ir.property')
- definition_id = self._field_get(cr, uid, obj._name, prop)
-
- nid = property.search(cr, uid, [('fields_id', '=', definition_id),
- ('res_id', '=', False)])
- default_val = False
- if nid:
- d = property.browse(cr, uid, nid[0], context).value
- default_val = (d and int(d.split(',')[1])) or False
-
- vids = [obj._name + ',' + str(id) for id in ids]
- nids = property.search(cr, uid, [('fields_id', '=', definition_id),
- ('res_id', 'in', vids)])
-
- res = {}
- for id in ids:
- res[id]= default_val
- for prop in property.browse(cr, uid, nids):
- res[int(prop.res_id.split(',')[1])] = (prop.value and \
- int(prop.value.split(',')[1])) or False
-
- obj = obj.pool.get(self._obj)
- names = dict(obj.name_get(cr, uid, filter(None, res.values()), context))
- for r in res.keys():
- if res[r] and res[r] in names:
- res[r] = (res[r], names[res[r]])
- else:
- res[r] = False
- return res
-
- def _field_get(self, cr, uid, model_name, prop):
- if not self.field_id.get(cr.dbname):
- cr.execute('SELECT id \
- FROM ir_model_fields \
- WHERE name=%s AND model=%s', (prop, model_name))
- res = cr.fetchone()
- self.field_id[cr.dbname] = res and res[0]
- return self.field_id[cr.dbname]
-
- def __init__(self, obj_prop, **args):
- self.field_id = {}
- function.__init__(self, self._fnct_read, False, self._fnct_write,
- (obj_prop, ), **args)
-
- def restart(self):
- self.field_id = {}
+ def _fnct_write(self, obj, cr, uid, id, prop, id_val, val, context=None):
+ if not context:
+ context={}
+ (obj_dest,) = val
+ definition_id = self._field_get(cr, uid, obj._name, prop)
+
+ property = obj.pool.get('ir.property')
+ 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(),))
+
+ nid = property.search(cr, uid, [('fields_id', '=', definition_id),
+ ('res_id', '=', False)])
+ default_val = False
+ if nid:
+ default_val = property.browse(cr, uid, nid[0], context).value
+
+ company_id = obj.pool.get('res.users').company_get(cr, uid, uid)
+ res = False
+ newval = (id_val and obj_dest+','+str(id_val)) or False
+ if (newval != default_val) and newval:
+ propdef = obj.pool.get('ir.model.fields').browse(cr, uid,
+ definition_id, context=context)
+ res = property.create(cr, uid, {
+ 'name': propdef.name,
+ 'value': newval,
+ 'res_id': obj._name+','+str(id),
+ 'company_id': company_id,
+ 'fields_id': definition_id
+ }, context=context)
+ return res
+
+ def _fnct_read(self, obj, cr, uid, ids, prop, val, context=None):
+ if not context:
+ context={}
+ property = obj.pool.get('ir.property')
+ definition_id = self._field_get(cr, uid, obj._name, prop)
+
+ nid = property.search(cr, uid, [('fields_id', '=', definition_id),
+ ('res_id', '=', False)])
+ default_val = False
+ if nid:
+ d = property.browse(cr, uid, nid[0], context).value
+ default_val = (d and int(d.split(',')[1])) or False
+
+ vids = [obj._name + ',' + str(id) for id in ids]
+ nids = property.search(cr, uid, [('fields_id', '=', definition_id),
+ ('res_id', 'in', vids)])
+
+ res = {}
+ for id in ids:
+ res[id]= default_val
+ for prop in property.browse(cr, uid, nids):
+ res[int(prop.res_id.split(',')[1])] = (prop.value and \
+ int(prop.value.split(',')[1])) or False
+
+ obj = obj.pool.get(self._obj)
+ names = dict(obj.name_get(cr, uid, filter(None, res.values()), context))
+ for r in res.keys():
+ if res[r] and res[r] in names:
+ res[r] = (res[r], names[res[r]])
+ else:
+ res[r] = False
+ return res
+
+ def _field_get(self, cr, uid, model_name, prop):
+ if not self.field_id.get(cr.dbname):
+ cr.execute('SELECT id \
+ FROM ir_model_fields \
+ WHERE name=%s AND model=%s', (prop, model_name))
+ res = cr.fetchone()
+ self.field_id[cr.dbname] = res and res[0]
+ return self.field_id[cr.dbname]
+
+ def __init__(self, obj_prop, **args):
+ self.field_id = {}
+ function.__init__(self, self._fnct_read, False, self._fnct_write,
+ (obj_prop, ), **args)
+
+ def restart(self):
+ self.field_id = {}
diff --git a/bin/osv/orm.py b/bin/osv/orm.py
index 789d2fa27f8..26fad04a900 100644
--- a/bin/osv/orm.py
+++ b/bin/osv/orm.py
@@ -68,2547 +68,2547 @@ ID_MAX = 1000
regex_order = re.compile('^([a-zA-Z0-9_]+( desc)?( asc)?,?)+$', re.I)
def intersect(la, lb):
- return filter(lambda x: x in lb, la)
+ return filter(lambda x: x in lb, la)
class except_orm(Exception):
- def __init__(self, name, value):
- self.name = name
- self.value = value
- self.args = (name, value)
+ def __init__(self, name, value):
+ self.name = name
+ self.value = value
+ self.args = (name, value)
# Readonly python database object browser
class browse_null(object):
- def __init__(self):
- self.id=False
+ def __init__(self):
+ self.id=False
- def __getitem__(self, name):
- return False
+ def __getitem__(self, name):
+ return False
- def __int__(self):
- return False
+ def __int__(self):
+ return False
- def __str__(self):
- return ''
+ def __str__(self):
+ return ''
- def __nonzero__(self):
- return False
+ def __nonzero__(self):
+ return False
#
# TODO: execute an object method on browse_record_list
#
class browse_record_list(list):
- def __init__(self, lst, context=None):
- if not context:
- context = {}
- super(browse_record_list, self).__init__(lst)
- self.context = context
+ def __init__(self, lst, context=None):
+ if not context:
+ context = {}
+ super(browse_record_list, self).__init__(lst)
+ self.context = context
class browse_record(object):
- def __init__(self, cr, uid, id, table, cache, context=None, list_class = None, fields_process={}):
- '''
- table : the object (inherited from orm)
- context : a dictionnary with an optionnal context
- '''
- if not context:
- context = {}
- assert id, _('Wrong ID for the browse record, got %s, expected an integer.') % str(id)
- self._list_class = list_class or browse_record_list
- self._cr = cr
- self._uid = uid
- self._id = id
- self._table = table
- self._table_name = self._table._name
- self._context = context
- self._fields_process = fields_process
-
- cache.setdefault(table._name, {})
- self._data = cache[table._name]
- if not id in self._data:
- self._data[id] = {'id':id}
- self._cache = cache
-
- def __getitem__(self, name):
- if name == 'id':
- return self._id
- if not self._data[self._id].has_key(name):
- # build the list of fields we will fetch
-
- # fetch the definition of the field which was asked for
- if name in self._table._columns:
- col = self._table._columns[name]
- elif name in self._table._inherit_fields:
- col = self._table._inherit_fields[name][2]
- elif hasattr(self._table, name):
- if isinstance( getattr(self._table, name), (types.MethodType,types.LambdaType,types.FunctionType)):
- return lambda *args, **argv: getattr(self._table, name)(self._cr, self._uid, [self._id], *args, **argv)
- else:
- return getattr(self._table, name)
- else:
- logger = netsvc.Logger()
- logger.notifyChannel('orm', netsvc.LOG_ERROR, "Programming error: field '%s' does not exist in object '%s' !" % (name, self._table._name))
- return False
-
- # if the field is a classic one or a many2one, we'll fetch all classic and many2one fields
- if col._classic_write:
- # gen the list of "local" (ie not inherited) fields which are classic or many2one
- ffields = filter(lambda x: x[1]._classic_write, self._table._columns.items())
- # gen the list of inherited fields
- inherits = map(lambda x: (x[0], x[1][2]), self._table._inherit_fields.items())
- # complete the field list with the inherited fields which are classic or many2one
- ffields += filter(lambda x: x[1]._classic_write, inherits)
- # otherwise we fetch only that field
- else:
- ffields = [(name,col)]
- ids = filter(lambda id: not self._data[id].has_key(name), self._data.keys())
- # read the data
- fffields = map(lambda x: x[0], ffields)
- datas = self._table.read(self._cr, self._uid, ids, fffields, context=self._context, load="_classic_write")
- if self._fields_process:
- for n,f in ffields:
- if f._type in self._fields_process:
- for d in datas:
- d[n] = self._fields_process[f._type](d[n])
- d[n].set_value(d[n], self, f)
-
-
- # create browse records for 'remote' objects
- for data in datas:
- for n,f in ffields:
- if f._type in ('many2one', 'one2one'):
- if data[n]:
- obj = self._table.pool.get(f._obj)
- compids=False
- if not f._classic_write:
- ids2 = data[n][0]
- else:
- ids2 = data[n]
- if ids2:
- data[n] = browse_record(self._cr, self._uid, ids2, obj, self._cache, context=self._context, list_class=self._list_class, fields_process=self._fields_process)
- else:
- data[n] = browse_null()
- else:
- data[n] = browse_null()
- elif f._type in ('one2many', 'many2many') and len(data[n]):
- data[n] = self._list_class([browse_record(self._cr,self._uid,id,self._table.pool.get(f._obj),self._cache, context=self._context, list_class=self._list_class, fields_process=self._fields_process) for id in data[n]], self._context)
- self._data[data['id']].update(data)
- return self._data[self._id][name]
-
- def __getattr__(self, name):
-# raise an AttributeError exception.
- return self[name]
-
- def __contains__(self, name):
- return (name in self._table._columns) or (name in self._table._inherit_fields) or hasattr(self._table, name)
-
- def __hasattr__(self, name):
- return name in self
-
- def __int__(self):
- return self._id
-
- def __str__(self):
- return "browse_record(%s, %d)" % (self._table_name, self._id)
-
- def __eq__(self, other):
- return (self._table_name, self._id) == (other._table_name, other._id)
-
- def __ne__(self, other):
- return (self._table_name, self._id) != (other._table_name, other._id)
-
- # we need to define __unicode__ even though we've already defined __str__
- # because we have overridden __getattr__
- def __unicode__(self):
- return unicode(str(self))
-
- def __hash__(self):
- return hash((self._table_name, self._id))
-
- __repr__ = __str__
+ def __init__(self, cr, uid, id, table, cache, context=None, list_class = None, fields_process={}):
+ '''
+ table : the object (inherited from orm)
+ context : a dictionnary with an optionnal context
+ '''
+ if not context:
+ context = {}
+ assert id, _('Wrong ID for the browse record, got %s, expected an integer.') % str(id)
+ self._list_class = list_class or browse_record_list
+ self._cr = cr
+ self._uid = uid
+ self._id = id
+ self._table = table
+ self._table_name = self._table._name
+ self._context = context
+ self._fields_process = fields_process
+
+ cache.setdefault(table._name, {})
+ self._data = cache[table._name]
+ if not id in self._data:
+ self._data[id] = {'id':id}
+ self._cache = cache
+
+ def __getitem__(self, name):
+ if name == 'id':
+ return self._id
+ if not self._data[self._id].has_key(name):
+ # build the list of fields we will fetch
+
+ # fetch the definition of the field which was asked for
+ if name in self._table._columns:
+ col = self._table._columns[name]
+ elif name in self._table._inherit_fields:
+ col = self._table._inherit_fields[name][2]
+ elif hasattr(self._table, name):
+ if isinstance( getattr(self._table, name), (types.MethodType,types.LambdaType,types.FunctionType)):
+ return lambda *args, **argv: getattr(self._table, name)(self._cr, self._uid, [self._id], *args, **argv)
+ else:
+ return getattr(self._table, name)
+ else:
+ logger = netsvc.Logger()
+ logger.notifyChannel('orm', netsvc.LOG_ERROR, "Programming error: field '%s' does not exist in object '%s' !" % (name, self._table._name))
+ return False
+
+ # if the field is a classic one or a many2one, we'll fetch all classic and many2one fields
+ if col._classic_write:
+ # gen the list of "local" (ie not inherited) fields which are classic or many2one
+ ffields = filter(lambda x: x[1]._classic_write, self._table._columns.items())
+ # gen the list of inherited fields
+ inherits = map(lambda x: (x[0], x[1][2]), self._table._inherit_fields.items())
+ # complete the field list with the inherited fields which are classic or many2one
+ ffields += filter(lambda x: x[1]._classic_write, inherits)
+ # otherwise we fetch only that field
+ else:
+ ffields = [(name,col)]
+ ids = filter(lambda id: not self._data[id].has_key(name), self._data.keys())
+ # read the data
+ fffields = map(lambda x: x[0], ffields)
+ datas = self._table.read(self._cr, self._uid, ids, fffields, context=self._context, load="_classic_write")
+ if self._fields_process:
+ for n,f in ffields:
+ if f._type in self._fields_process:
+ for d in datas:
+ d[n] = self._fields_process[f._type](d[n])
+ d[n].set_value(d[n], self, f)
+
+
+ # create browse records for 'remote' objects
+ for data in datas:
+ for n,f in ffields:
+ if f._type in ('many2one', 'one2one'):
+ if data[n]:
+ obj = self._table.pool.get(f._obj)
+ compids=False
+ if not f._classic_write:
+ ids2 = data[n][0]
+ else:
+ ids2 = data[n]
+ if ids2:
+ data[n] = browse_record(self._cr, self._uid, ids2, obj, self._cache, context=self._context, list_class=self._list_class, fields_process=self._fields_process)
+ else:
+ data[n] = browse_null()
+ else:
+ data[n] = browse_null()
+ elif f._type in ('one2many', 'many2many') and len(data[n]):
+ data[n] = self._list_class([browse_record(self._cr,self._uid,id,self._table.pool.get(f._obj),self._cache, context=self._context, list_class=self._list_class, fields_process=self._fields_process) for id in data[n]], self._context)
+ self._data[data['id']].update(data)
+ return self._data[self._id][name]
+
+ def __getattr__(self, name):
+# raise an AttributeError exception.
+ return self[name]
+
+ def __contains__(self, name):
+ return (name in self._table._columns) or (name in self._table._inherit_fields) or hasattr(self._table, name)
+
+ def __hasattr__(self, name):
+ return name in self
+
+ def __int__(self):
+ return self._id
+
+ def __str__(self):
+ return "browse_record(%s, %d)" % (self._table_name, self._id)
+
+ def __eq__(self, other):
+ return (self._table_name, self._id) == (other._table_name, other._id)
+
+ def __ne__(self, other):
+ return (self._table_name, self._id) != (other._table_name, other._id)
+
+ # we need to define __unicode__ even though we've already defined __str__
+ # because we have overridden __getattr__
+ def __unicode__(self):
+ return unicode(str(self))
+
+ def __hash__(self):
+ return hash((self._table_name, self._id))
+
+ __repr__ = __str__
def get_pg_type(f):
- '''
- returns a tuple
- (type returned by postgres when the column was created, type expression to create the column)
- '''
-
- type_dict = {
- fields.boolean:'bool',
- fields.integer:'int4',
- fields.text:'text',
- fields.date:'date',
- fields.time:'time',
- fields.datetime:'timestamp',
- fields.binary:'bytea',
- fields.many2one:'int4',
- }
- if type_dict.has_key(type(f)):
- f_type = (type_dict[type(f)], type_dict[type(f)])
- elif isinstance(f, fields.float):
- if f.digits:
- f_type = ('numeric', 'NUMERIC(%d,%d)' % (f.digits[0],f.digits[1]))
- else:
- f_type = ('float8', 'DOUBLE PRECISION')
- elif isinstance(f, (fields.char, fields.reference)):
- f_type = ('varchar', 'VARCHAR(%d)' % (f.size,))
- elif isinstance(f, fields.selection):
- if isinstance(f.selection, list) and isinstance(f.selection[0][0], (str, unicode)):
- f_size = reduce(lambda x,y: max(x,len(y[0])), f.selection, f.size or 16)
- elif isinstance(f.selection, list) and isinstance(f.selection[0][0], int):
- f_size = -1
- else:
- f_size = (hasattr(f,'size') and f.size) or 16
-
- if f_size == -1:
- f_type = ('int4', 'INTEGER')
- else:
- f_type = ('varchar', 'VARCHAR(%d)' % f_size)
- elif isinstance(f, fields.function) and type_dict.has_key(eval('fields.'+(f._type))):
- t=eval('fields.'+(f._type))
- f_type = (type_dict[t], type_dict[t])
- elif isinstance(f, fields.function) and f._type == 'float':
- f_type = ('float8', 'DOUBLE PRECISION')
- elif isinstance(f, fields.function) and f._type == 'selection':
- f_type = ('text', 'text')
- else:
- logger = netsvc.Logger()
- logger.notifyChannel("init", netsvc.LOG_WARNING, '%s type not supported!' % (type(f)))
- f_type = None
- return f_type
+ '''
+ returns a tuple
+ (type returned by postgres when the column was created, type expression to create the column)
+ '''
+
+ type_dict = {
+ fields.boolean:'bool',
+ fields.integer:'int4',
+ fields.text:'text',
+ fields.date:'date',
+ fields.time:'time',
+ fields.datetime:'timestamp',
+ fields.binary:'bytea',
+ fields.many2one:'int4',
+ }
+ if type_dict.has_key(type(f)):
+ f_type = (type_dict[type(f)], type_dict[type(f)])
+ elif isinstance(f, fields.float):
+ if f.digits:
+ f_type = ('numeric', 'NUMERIC(%d,%d)' % (f.digits[0],f.digits[1]))
+ else:
+ f_type = ('float8', 'DOUBLE PRECISION')
+ elif isinstance(f, (fields.char, fields.reference)):
+ f_type = ('varchar', 'VARCHAR(%d)' % (f.size,))
+ elif isinstance(f, fields.selection):
+ if isinstance(f.selection, list) and isinstance(f.selection[0][0], (str, unicode)):
+ f_size = reduce(lambda x,y: max(x,len(y[0])), f.selection, f.size or 16)
+ elif isinstance(f.selection, list) and isinstance(f.selection[0][0], int):
+ f_size = -1
+ else:
+ f_size = (hasattr(f,'size') and f.size) or 16
+
+ if f_size == -1:
+ f_type = ('int4', 'INTEGER')
+ else:
+ f_type = ('varchar', 'VARCHAR(%d)' % f_size)
+ elif isinstance(f, fields.function) and type_dict.has_key(eval('fields.'+(f._type))):
+ t=eval('fields.'+(f._type))
+ f_type = (type_dict[t], type_dict[t])
+ elif isinstance(f, fields.function) and f._type == 'float':
+ f_type = ('float8', 'DOUBLE PRECISION')
+ elif isinstance(f, fields.function) and f._type == 'selection':
+ f_type = ('text', 'text')
+ else:
+ logger = netsvc.Logger()
+ logger.notifyChannel("init", netsvc.LOG_WARNING, '%s type not supported!' % (type(f)))
+ f_type = None
+ return f_type
class orm_template(object):
- _name = None
- _columns = {}
- _constraints = []
- _defaults = {}
- _rec_name = 'name'
- _parent_name = 'parent_id'
- _date_name = 'date'
- _order = 'id'
- _sequence = None
- _description = None
- _inherits = {}
- _table = None
-
- def _field_create(self, cr, context={}):
- cr.execute("SELECT id FROM ir_model WHERE model='%s'" % self._name)
- if not cr.rowcount:
- # reference model in order to have a description of its fonctionnality in custom_report
- cr.execute('SELECT nextval(%s)', ('ir_model_id_seq',))
- id = cr.fetchone()[0]
- cr.execute("INSERT INTO ir_model (id,model, name, info) VALUES (%s, %s, %s, %s)", (id,self._name, self._description, self.__doc__))
- 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._table, context['module'], 'ir.model', id)
- )
- cr.commit()
-
- cr.execute("SELECT * FROM ir_model_fields WHERE model=%s", (self._name,))
- cols = {}
- for rec in cr.dictfetchall():
- cols[rec['name']] = rec
-
- cr.execute("SELECT id FROM ir_model WHERE model='%s'" % self._name)
- model_id = cr.fetchone()[0]
-
- for (k,f) in self._columns.items():
- vals = {
- 'model_id':model_id,
- 'model':self._name,
- 'name':k,
- 'field_description':f.string.replace("'", " "),
- 'ttype':f._type,
- 'relate':(f.relate and 1) or 0,
- 'relation':f._obj or 'NULL',
- 'group_name':f.group_name or '',
- 'view_load':(f.view_load and 1) or 0,
- 'select_level':str(f.select or 0)
- }
- if k not in cols:
- cr.execute('select nextval(%s)', ('ir_model_fields_id_seq',))
- id = cr.fetchone()[0]
- vals['id'] = id
- cr.execute("""INSERT INTO ir_model_fields (
- id, model_id, model, name, field_description, ttype,
- relate,relation,group_name,view_load,state,select_level
- ) VALUES (
- %d,%s,%s,%s,%s,%s, %s,%s,%s,%s,%s, %s
- )""", (
- id, vals['model_id'], vals['model'], vals['name'], vals['field_description'], vals['ttype'],
- bool(vals['relate']), vals['relation'], vals['group_name'], bool(vals['view_load']), 'base',
- vals['select_level']
- ))
- 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)", \
- ( ('field_'+self._table+'_'+k)[:64], context['module'], 'ir.model.fields', id)
- )
- else:
- for key,val in vals.items():
- if cols[k][key]<>vals[key]:
- print 'Different', cols[k][key], vals[key], k, key, self._name
- cr.execute('update ir_model_fields set field_description=%s where model=%s and name=%s', (vals['field_description'],vals['model'],vals['name']))
- cr.commit()
- cr.execute("""UPDATE ir_model_fields SET
- model_id=%s, field_description=%s, ttype=%s, relate=%s, relation=%s,
- group_name=%s, view_load=%s, select_level=%s
- WHERE
- model=%s AND name=%s""", (
- vals['model_id'],vals['field_description'],vals['ttype'],bool(vals['relate']),
- vals['relation'], vals['group_name'], bool(vals['view_load']),
- vals['select_level'], vals['model'], vals['name']
- ))
- continue
- cr.commit()
-
- def _auto_init(self, cr, context={}):
- self._field_create(cr, context)
-
- def __init__(self, cr):
- if not self._description:
- self._description = self._name
- if not self._table:
- self._table=self._name.replace('.','_')
-
- def browse(self, cr, uid, select, context=None, list_class=None, fields_process={}):
- if not context:
- context={}
- self._list_class = list_class or browse_record_list
- cache = {}
- # need to accepts ints and longs because ids coming from a method
- # launched by button in the interface have a type long...
- if isinstance(select, (int, long)):
- return browse_record(cr,uid,select,self,cache, context=context, list_class=self._list_class, fields_process=fields_process)
- elif isinstance(select,list):
- return self._list_class([browse_record(cr,uid,id,self,cache, context=context, list_class=self._list_class, fields_process=fields_process) for id in select], context)
- else:
- return browse_null()
-
- def __export_row(self, cr, uid, row, fields, context=None):
- lines = []
- data = map(lambda x: '', range(len(fields)))
- done = []
- for fpos in range(len(fields)):
- f = fields[fpos]
- if f:
- r = row
- i = 0
- while i<len(f):
- r = r[f[i]]
- if not r:
- break
- if isinstance(r, (browse_record_list, list)):
- first = True
- fields2 = map(lambda x: (x[:i+1]==f[:i+1] and x[i+1:]) \
- or [], fields)
- if fields2 in done:
- break
- done.append(fields2)
- for row2 in r:
- lines2 = self.__export_row(cr, uid, row2, fields2,
- context)
- if first:
- for fpos2 in range(len(fields)):
- if lines2 and lines2[0][fpos2]:
- data[fpos2] = lines2[0][fpos2]
- lines+= lines2[1:]
- first = False
- else:
- lines+= lines2
- break
- i+=1
- if i==len(f):
- data[fpos] = str(r or '')
- return [data] + lines
-
- def export_data(self, cr, uid, ids, fields, context=None):
- if not context:
- context={}
- fields = map(lambda x: x.split('/'), fields)
- datas = []
- for row in self.browse(cr, uid, ids, context):
- datas += self.__export_row(cr, uid, row, fields, context)
- return datas
-
- def import_data(self, cr, uid, fields, datas, mode='init',
- current_module=None, noupdate=False, context=None):
- if not context:
- context={}
- fields = map(lambda x: x.split('/'), fields)
- logger = netsvc.Logger()
- def process_liness(self, datas, prefix, fields_def, position=0):
- line = datas[position]
- row = {}
- translate = {}
- todo = []
- warning = ''
- data_id= False
- #
- # Import normal fields
- #
- for i in range(len(fields)):
- if i>=len(line):
- raise Exception, _('Please check that all your lines have %d columns.') % (len(fields),)
- field = fields[i]
- if field == ["id"]:
- data_id= line[i]
- continue
- if (len(field)==len(prefix)+1) and field[len(prefix)].endswith(':id'):
- res_id = False
- if line[i]:
- if fields_def[field[len(prefix)][:-3]]['type']=='many2many':
- res_id = []
- for word in line[i].split(','):
- if '.' in word:
- module, xml_id = word.rsplit('.', 1)
- else:
- module, xml_id = current_module, word
- ir_model_data_obj = self.pool.get('ir.model.data')
- id = ir_model_data_obj._get_id(cr, uid, module,
- xml_id)
- res_id2 = ir_model_data_obj.read(cr, uid, [id],
- ['res_id'])[0]['res_id']
- if res_id2:
- res_id.append(res_id2)
- if len(res_id):
- res_id=[(6,0,res_id)]
- else:
- if '.' in line[i]:
- module, xml_id = line[i].rsplit('.', 1)
- else:
- module, xml_id = current_module, line[i]
- ir_model_data_obj = self.pool.get('ir.model.data')
- id = ir_model_data_obj._get_id(cr, uid, module, xml_id)
- res_id = ir_model_data_obj.read(cr, uid, [id],
- ['res_id'])[0]['res_id']
- row[field[0][:-3]] = res_id or False
- continue
- if (len(field) == len(prefix)+1) and \
- len(field[len(prefix)].split(':lang=')) == 2:
- f, lang = field[len(prefix)].split(':lang=')
- translate.setdefault(lang, {})[f]=line[i] or False
- continue
- if (len(field) == len(prefix)+1) and \
- (prefix == field[0:len(prefix)]):
- if fields_def[field[len(prefix)]]['type'] == 'integer':
- res =line[i] and int(line[i])
- elif fields_def[field[len(prefix)]]['type'] == 'float':
- res =line[i] and float(line[i])
- elif fields_def[field[len(prefix)]]['type'] == 'selection':
- res = False
- if isinstance(fields_def[field[len(prefix)]]['selection'],
- (tuple, list)):
- sel = fields_def[field[len(prefix)]]['selection']
- else:
- sel = fields_def[field[len(prefix)]]['selection'](self,
- cr, uid, context)
- for key, val in sel:
- if str(key) == line[i]:
- res = key
- if line[i] and not res:
- logger.notifyChannel("import", netsvc.LOG_WARNING,
- "key '%s' not found in selection field '%s'" % \
- (line[i], field[len(prefix)]))
- elif fields_def[field[len(prefix)]]['type']=='many2one':
- res = False
- if line[i]:
- relation = fields_def[field[len(prefix)]]['relation']
- res2 = self.pool.get(relation).name_search(cr, uid,
- line[i], [], operator='=')
- res = (res2 and res2[0][0]) or False
- if not res:
- warning += ('Relation not found: ' + line[i] + \
- ' on ' + relation + ' !\n')
- logger.notifyChannel("import", netsvc.LOG_WARNING,
- 'Relation not found: ' + line[i] + \
- ' on ' + relation + ' !\n')
- elif fields_def[field[len(prefix)]]['type']=='many2many':
- res = []
- if line[i]:
- relation = fields_def[field[len(prefix)]]['relation']
- for word in line[i].split(','):
- res2 = self.pool.get(relation).name_search(cr,
- uid, word, [], operator='=')
- res3 = (res2 and res2[0][0]) or False
- if not res3:
- warning += ('Relation not found: ' + \
- line[i] + ' on '+relation + ' !\n')
- logger.notifyChannel("import",
- netsvc.LOG_WARNING,
- 'Relation not found: ' + line[i] + \
- ' on '+relation + ' !\n')
- else:
- res.append(res3)
- if len(res):
- res= [(6,0,res)]
- else:
- res = line[i] or False
- row[field[len(prefix)]] = res
- elif (prefix==field[0:len(prefix)]):
- if field[0] not in todo:
- todo.append(field[len(prefix)])
- #
- # Import one2many fields
- #
- nbrmax = 1
- for field in todo:
- newfd = self.pool.get(fields_def[field]['relation']).fields_get(
- cr, uid, context=context)
- res = process_liness(self, datas, prefix + [field], newfd, position)
- (newrow, max2, w2, translate2, data_id2) = res
- nbrmax = max(nbrmax, max2)
- warning = warning + w2
- reduce(lambda x,y: x and y, newrow)
- row[field] = (reduce(lambda x, y: x or y, newrow.values()) and \
- [(0,0,newrow)]) or []
- i = max2
- while (position+i)<len(datas):
- ok = True
- for j in range(len(fields)):
- field2 = fields[j]
- if (len(field2) <= (len(prefix)+1)) and datas[position+i][j]:
- ok = False
- if not ok:
- break
-
- (newrow, max2, w2, translate2, data_id2) = process_liness(
- self, datas, prefix+[field], newfd, position+i)
- warning = warning+w2
- if reduce(lambda x,y: x or y, newrow.values()):
- row[field].append((0,0,newrow))
- i+=max2
- nbrmax = max(nbrmax, i)
-
- if len(prefix)==0:
- for i in range(max(nbrmax,1)):
- #if datas:
- datas.pop(0)
- result = (row, nbrmax, warning, translate, data_id)
- return result
-
- fields_def = self.fields_get(cr, uid, context=context)
- done = 0
-
- while len(datas):
- res = {}
- try:
- (res, other, warning, translate, data_id) = \
- process_liness(self, datas, [], fields_def)
- if warning:
- cr.rollback()
- return (-1, res, warning, '')
- id= self.pool.get('ir.model.data')._update(cr, uid, self._name,
- current_module, res, xml_id=data_id, mode=mode,
- noupdate=noupdate)
- for lang in translate:
- context2=context.copy()
- context2['lang']=lang
- self.write(cr, uid, [id], translate[lang], context2)
- if config.get('commit_mode', False):
- cr.commit()
- except Exception, e:
- logger.notifyChannel("import",netsvc.LOG_ERROR, e)
- cr.rollback()
- try:
- return (-1, res, e[0], warning)
- except:
- return (-1, res, e[0], '')
- done += 1
- #
- # TODO: Send a request with the result and multi-thread !
- #
- return (done, 0, 0, 0)
-
- def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'):
- raise _('The read method is not implemented on this object !')
-
- def _validate(self, cr, uid, ids, context=None):
- context = context or {}
- lng = context.get('lang', False) or 'en_US'
- trans = self.pool.get('ir.translation')
- field_error = []
- field_err_str = []
- for constraint in self._constraints:
- fun, msg, fields = constraint
- if not fun(self, cr, uid, ids):
- field_error += fields
- field_err_str.append( trans._get_source(cr, uid, self._name, 'constraint', lng, source=msg) )
- if len(field_err_str):
- cr.rollback()
- raise except_orm('ValidateError', ('\n'.join(field_err_str), ','.join(field_error)))
-
- def default_get(self, cr, uid, fields_list, context=None):
- return {}
-
- def perm_read(self, cr, user, ids, context=None, details=True):
- raise _('The perm_read method is not implemented on this object !')
-
- def unlink(self, cr, uid, ids, context=None):
- raise _('The unlink method is not implemented on this object !')
-
- def write(self, cr, user, ids, vals, context=None):
- raise _('The write method is not implemented on this object !')
-
- def create(self, cr, user, vals, context=None):
- raise _('The create method is not implemented on this object !')
-
- # returns the definition of each field in the object
- # the optional fields parameter can limit the result to some fields
- def fields_get(self, cr, user, fields=None, context=None, read_access=True):
- if context is None:
- context = {}
- res = {}
- translation_obj = self.pool.get('ir.translation')
- model_access_obj = self.pool.get('ir.model.access')
- for parent in self._inherits:
- res.update(self.pool.get(parent).fields_get(cr, user, fields,
- context))
- for f in self._columns.keys():
- res[f] = {'type': self._columns[f]._type}
- for arg in ('string', 'readonly', 'states', 'size', 'required',
- 'change_default', 'translate', 'help', 'select'):
- if getattr(self._columns[f], arg):
- res[f][arg] = getattr(self._columns[f], arg)
- if not read_access:
- res[f]['readonly']= True
- res[f]['states'] = {}
- for arg in ('digits', 'invisible'):
- if hasattr(self._columns[f], arg) \
- 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:
- res[f]['string'] = res_trans
- help_trans = translation_obj._get_source(cr, user,
- self._name + ',' + f, 'help', context.get('lang', False) or 'en_US')
- if help_trans:
- res[f]['help'] = help_trans
-
- if hasattr(self._columns[f], 'selection'):
- if isinstance(self._columns[f].selection, (tuple, list)):
- sel = self._columns[f].selection
- # translate each selection option
- sel2 = []
- for (key,val) in sel:
- val2 = translation_obj._get_source(cr, user,
- self._name + ',' + f, 'selection',
- context.get('lang', False) or 'en_US', val)
- sel2.append((key, val2 or val))
- sel = sel2
- res[f]['selection'] = sel
- else:
- # call the 'dynamic selection' function
- res[f]['selection'] = self._columns[f].selection(self, cr,
- user, context)
- if res[f]['type'] in ('one2many', 'many2many',
- 'many2one', 'one2one'):
- res[f]['relation'] = self._columns[f]._obj
- res[f]['domain'] = self._columns[f]._domain
- res[f]['context'] = self._columns[f]._context
-
- if fields:
- # filter out fields which aren't in the fields list
- for r in res.keys():
- if r not in fields:
- del res[r]
- return res
-
- #
- # Overload this method if you need a window title which depends on the context
- #
- def view_header_get(self, cr, user, view_id=None, view_type='form', context=None):
- return False
-
- def __view_look_dom(self, cr, user, node, context=None):
- if not context:
- context={}
- result = False
- fields = {}
- childs = True
-
- if node.nodeType==node.ELEMENT_NODE and node.localName=='field':
- if node.hasAttribute('name'):
- attrs = {}
- try:
- if node.getAttribute('name') in self._columns:
- relation = self._columns[node.getAttribute('name')]._obj
- else:
- relation = self._inherit_fields[node.getAttribute('name')][2]._obj
- except:
- relation = False
-
- if relation:
- childs = False
- views = {}
- for f in node.childNodes:
- if f.nodeType==f.ELEMENT_NODE and f.localName in ('form','tree','graph'):
- node.removeChild(f)
- xarch,xfields = self.pool.get(relation).__view_look_dom_arch(cr, user, f, context)
- views[str(f.localName)] = {
- 'arch': xarch,
- 'fields': xfields
- }
- attrs = {'views': views}
- fields[node.getAttribute('name')] = attrs
-
- elif node.nodeType==node.ELEMENT_NODE and node.localName in ('form','tree'):
- result = self.view_header_get(cr, user, False, node.localName, context)
- if result:
- node.setAttribute('string', result.decode('utf-8'))
- if node.nodeType==node.ELEMENT_NODE and node.hasAttribute('groups'):
- groups = None
- group_str = node.getAttribute('groups')
- if ',' in group_str:
- groups = group_str.split(',');
- readonly = False
- access_pool = self.pool.get('ir.model.access')
- for group in groups:
- readonly = readonly and access_pool.check_groups(cr, user, group)
-
- if readonly:
- parent = node.parentNode
- parent.removeChild(node)
-
- else:
- if not self.pool.get('ir.model.access').check_groups(cr, user, group_str):
- parent = node.parentNode
- parent.removeChild(node)
-
- if node.nodeType == node.ELEMENT_NODE:
- # 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'))
- if trans:
- node.setAttribute('string', trans.decode('utf8'))
- 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'))
- #
- # Add view for properties !
- #
- if node.localName=='properties':
- parent = node.parentNode
- doc = node.ownerDocument
- models = map(lambda x: "'"+x+"'", [self._name] + self._inherits.keys())
- cr.execute('select id,name,group_name from ir_model_fields where model in ('+','.join(models)+') and view_load order by group_name, id')
- oldgroup = None
- res = cr.fetchall()
- for id, fname, gname in res:
- if oldgroup != gname:
- child = doc.createElement('separator')
- child.setAttribute('string', gname.decode('utf-8'))
- child.setAttribute('colspan', "4")
- oldgroup = gname
- parent.insertBefore(child, node)
-
- child = doc.createElement('field')
- child.setAttribute('name', fname.decode('utf-8'))
- parent.insertBefore(child, node)
- parent.removeChild(node)
-
- if childs:
- for f in node.childNodes:
- fields.update(self.__view_look_dom(cr, user, f,context))
- return fields
-
- def __view_look_dom_arch(self, cr, user, node, context=None):
- if not context:
- context={}
- fields_def = self.__view_look_dom(cr, user, node, context=context)
-
- buttons = xpath.Evaluate('//button', node)
- if buttons:
- for button in buttons:
- if button.getAttribute('type') == 'object':
- continue
-
- ok = True
-
- serv = netsvc.LocalService('object_proxy')
- user_roles = serv.execute_cr(cr, user, 'res.users', 'read', [user], ['roles_id'])[0]['roles_id']
- cr.execute("select role_id from wkf_transition where signal='%s'" % button.getAttribute('name'))
- roles = cr.fetchall()
- for role in roles:
- if role[0]:
- ok = ok and serv.execute_cr(cr, user, 'res.roles', 'check', user_roles, role[0])
-
- if not ok:
- button.setAttribute('readonly', '1')
- else:
- button.setAttribute('readonly', '0')
-
- arch = node.toxml(encoding="utf-8").replace('\t', '')
-
- fields = self.fields_get(cr, user, fields_def.keys(), context)
- for field in fields_def:
- fields[field].update(fields_def[field])
- return arch, fields
-
-
- def __get_default_calendar_view(self):
- """Generate a default calendar view (For internal use only).
- """
-
- arch = ('<?xml version="1.0" encoding="utf-8"?>\n'
- '<calendar string="%s" date_start="%s"') % (self._description, self._date_name)
-
- if 'user_id' in self._columns:
- arch += ' color="user_id"'
-
- elif 'partner_id' in self._columns:
- arch += ' color="partner_id"'
-
- if 'date_stop' in self._columns:
- arch += ' date_stop="date_stop"'
-
- elif 'date_end' in self._columns:
- arch += ' date_stop="date_end"'
-
- elif 'date_delay' in self._columns:
- arch += ' date_delay="date_delay"'
-
- elif 'planned_hours' in self._columns:
- arch += ' date_delay="planned_hours"'
-
- arch += ('>\n'
- ' <field name="%s"/>\n'
- '</calendar>') % (self._rec_name)
-
- return arch
-
- #
- # if view_id, view_type is not required
- #
- def fields_view_get(self, cr, user, view_id=None, view_type='form', context=None, toolbar=False):
- if not context:
- context={}
- def _inherit_apply(src, inherit):
- def _find(node, node2):
- # Check if xpath query or normal inherit (with field matching)
- if node2.nodeType==node2.ELEMENT_NODE and node2.localName=='xpath':
- res = xpath.Evaluate(node2.getAttribute('expr'), node)
- return res and res[0]
- else:
- if node.nodeType==node.ELEMENT_NODE and node.localName==node2.localName:
- res = True
- for attr in node2.attributes.keys():
- if attr=='position':
- continue
- if node.hasAttribute(attr):
- if node.getAttribute(attr)==node2.getAttribute(attr):
- continue
- res = False
- if res:
- return node
- for child in node.childNodes:
- res = _find(child, node2)
- if res: return res
- return None
-
- doc_src = dom.minidom.parseString(src)
- doc_dest = dom.minidom.parseString(inherit)
- toparse = doc_dest.childNodes
- while len(toparse):
- node2 = toparse.pop(0)
- if not node2.nodeType==node2.ELEMENT_NODE:
- continue
- if node2.localName=='data':
- toparse += node2.childNodes
- continue
- node = _find(doc_src, node2)
- if node:
- pos = 'inside'
- if node2.hasAttribute('position'):
- pos = node2.getAttribute('position')
- if pos=='replace':
- parent = node.parentNode
- for child in node2.childNodes:
- if child.nodeType==child.ELEMENT_NODE:
- parent.insertBefore(child, node)
- parent.removeChild(node)
- else:
- for child in node2.childNodes:
- if child.nodeType==child.ELEMENT_NODE:
- if pos=='inside':
- node.appendChild(child)
- elif pos=='after':
- sib = node.nextSibling
- if sib:
- node.parentNode.insertBefore(child, sib)
- else:
- node.parentNode.appendChild(child)
- elif pos=='before':
- node.parentNode.insertBefore(child, node)
- else:
- raise AttributeError, _('Unknown position in inherited view %s !') % pos
- else:
- attrs = ''.join([
- ' %s="%s"' % (attr, node2.getAttribute(attr))
- for attr in node2.attributes.keys()
- if attr != 'position'
- ])
- tag = "<%s%s>" % (node2.localName, attrs)
- raise AttributeError, _("Couldn't find tag '%s' in parent view !") % tag
- return doc_src.toxml(encoding="utf-8").replace('\t', '')
-
- result = {'type':view_type, 'model':self._name}
-
- ok = True
- model = True
- sql_res = False
- 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,))
- else:
- cr.execute('SELECT arch,name,field_parent,id,type,inherit_id FROM ir_ui_view WHERE model=%s AND type=%s ORDER BY priority', (self._name,view_type))
- sql_res = cr.fetchone()
- if not sql_res:
- break
- ok = sql_res[5]
- view_id = ok or sql_res[3]
- model = False
-
- # if a view was found
- if sql_res:
- result['type'] = sql_res[4]
- result['view_id'] = sql_res[3]
- result['arch'] = sql_res[0]
-
- 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))
- sql_inherit = cr.fetchall()
- for (inherit,id) in sql_inherit:
- result = _inherit_apply(result, inherit)
- result = _inherit_apply_rec(result, id)
- return result
-
- result['arch'] = _inherit_apply_rec(result['arch'], sql_res[3])
-
- result['name'] = sql_res[1]
- result['field_parent'] = sql_res[2] or False
- else:
- # otherwise, build some kind of default view
- if view_type == 'form':
- res = self.fields_get(cr, user, context=context)
- xml = '''<?xml version="1.0" encoding="utf-8"?>''' \
- '''<form string="%s">''' % (self._description,)
- for x in res:
- if res[x]['type'] not in ('one2many', 'many2many'):
- xml += '<field name="%s"/>' % (x,)
- if res[x]['type'] == 'text':
- xml += "<newline/>"
- xml += "</form>"
- elif view_type == 'tree':
- xml = '''<?xml version="1.0" encoding="utf-8"?>''' \
- '''<tree string="%s"><field name="%s"/></tree>''' \
- % (self._description, self._rec_name)
- elif view_type == 'calendar':
- xml = self.__get_default_calendar_view()
- else:
- xml = ''
- result['arch'] = xml
- result['name'] = 'default'
- result['field_parent'] = False
- result['view_id'] = 0
-
- doc = dom.minidom.parseString(result['arch'].encode('utf-8'))
- xarch, xfields = self.__view_look_dom_arch(cr, user, doc, context=context)
- result['arch'] = xarch
- result['fields'] = xfields
- if toolbar:
- def clean(x):
- x = x[2]
- for key in ('report_sxw_content', 'report_rml_content',
- 'report_sxw', 'report_rml',
- 'report_sxw_content_data', 'report_rml_content_data'):
- if key in x:
- del x[key]
- return x
- ir_values_obj = self.pool.get('ir.values')
- resprint = ir_values_obj.get(cr, user, 'action',
- 'client_print_multi', [(self._name, False)], False,
- context)
- resaction = ir_values_obj.get(cr, user, 'action',
- 'client_action_multi', [(self._name, False)], False,
- context)
-
- resrelate = ir_values_obj.get(cr, user, 'action',
- 'client_action_relate', [(self._name, False)], False,
- context)
- resprint = map(clean, resprint)
- resaction = map(clean, resaction)
- resaction = filter(lambda x: not x.get('multi',False), resaction)
- resprint = filter(lambda x: not x.get('multi',False), resprint)
- resrelate = map(lambda x:x[2], resrelate)
-
- for x in resprint+resaction+resrelate:
- x['string'] = x['name']
-
- result['toolbar'] = {
- 'print': resprint,
- 'action': resaction,
- 'relate': resrelate
- }
- return result
-
- _view_look_dom_arch=__view_look_dom_arch
-
- def search_count(self, cr, user, args, context=None):
- if not context:
- context = {}
- res = self.search(cr, user, args, context=context, count=True)
- if isinstance(res, list):
- return len(res)
- return res
-
- def search(self, cr, user, args, offset=0, limit=None, order=None,
- context=None, count=False):
- raise _('The search method is not implemented on this object !')
-
- def name_get(self, cr, user, ids, context=None):
- raise _('The name_get method is not implemented on this object !')
-
- def name_search(self, cr, user, name='', args=None, operator='ilike', context=None, limit=80):
- raise _('The name_search method is not implemented on this object !')
-
- def copy(self, cr, uid, id, default=None, context=None):
- raise _('The copy method is not implemented on this object !')
+ _name = None
+ _columns = {}
+ _constraints = []
+ _defaults = {}
+ _rec_name = 'name'
+ _parent_name = 'parent_id'
+ _date_name = 'date'
+ _order = 'id'
+ _sequence = None
+ _description = None
+ _inherits = {}
+ _table = None
+
+ def _field_create(self, cr, context={}):
+ cr.execute("SELECT id FROM ir_model WHERE model='%s'" % self._name)
+ if not cr.rowcount:
+ # reference model in order to have a description of its fonctionnality in custom_report
+ cr.execute('SELECT nextval(%s)', ('ir_model_id_seq',))
+ id = cr.fetchone()[0]
+ cr.execute("INSERT INTO ir_model (id,model, name, info) VALUES (%s, %s, %s, %s)", (id,self._name, self._description, self.__doc__))
+ 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._table, context['module'], 'ir.model', id)
+ )
+ cr.commit()
+
+ cr.execute("SELECT * FROM ir_model_fields WHERE model=%s", (self._name,))
+ cols = {}
+ for rec in cr.dictfetchall():
+ cols[rec['name']] = rec
+
+ cr.execute("SELECT id FROM ir_model WHERE model='%s'" % self._name)
+ model_id = cr.fetchone()[0]
+
+ for (k,f) in self._columns.items():
+ vals = {
+ 'model_id':model_id,
+ 'model':self._name,
+ 'name':k,
+ 'field_description':f.string.replace("'", " "),
+ 'ttype':f._type,
+ 'relate':(f.relate and 1) or 0,
+ 'relation':f._obj or 'NULL',
+ 'group_name':f.group_name or '',
+ 'view_load':(f.view_load and 1) or 0,
+ 'select_level':str(f.select or 0)
+ }
+ if k not in cols:
+ cr.execute('select nextval(%s)', ('ir_model_fields_id_seq',))
+ id = cr.fetchone()[0]
+ vals['id'] = id
+ cr.execute("""INSERT INTO ir_model_fields (
+ id, model_id, model, name, field_description, ttype,
+ relate,relation,group_name,view_load,state,select_level
+ ) VALUES (
+ %d,%s,%s,%s,%s,%s, %s,%s,%s,%s,%s, %s
+ )""", (
+ id, vals['model_id'], vals['model'], vals['name'], vals['field_description'], vals['ttype'],
+ bool(vals['relate']), vals['relation'], vals['group_name'], bool(vals['view_load']), 'base',
+ vals['select_level']
+ ))
+ 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)", \
+ ( ('field_'+self._table+'_'+k)[:64], context['module'], 'ir.model.fields', id)
+ )
+ else:
+ for key,val in vals.items():
+ if cols[k][key]<>vals[key]:
+ print 'Different', cols[k][key], vals[key], k, key, self._name
+ cr.execute('update ir_model_fields set field_description=%s where model=%s and name=%s', (vals['field_description'],vals['model'],vals['name']))
+ cr.commit()
+ cr.execute("""UPDATE ir_model_fields SET
+ model_id=%s, field_description=%s, ttype=%s, relate=%s, relation=%s,
+ group_name=%s, view_load=%s, select_level=%s
+ WHERE
+ model=%s AND name=%s""", (
+ vals['model_id'],vals['field_description'],vals['ttype'],bool(vals['relate']),
+ vals['relation'], vals['group_name'], bool(vals['view_load']),
+ vals['select_level'], vals['model'], vals['name']
+ ))
+ continue
+ cr.commit()
+
+ def _auto_init(self, cr, context={}):
+ self._field_create(cr, context)
+
+ def __init__(self, cr):
+ if not self._description:
+ self._description = self._name
+ if not self._table:
+ self._table=self._name.replace('.','_')
+
+ def browse(self, cr, uid, select, context=None, list_class=None, fields_process={}):
+ if not context:
+ context={}
+ self._list_class = list_class or browse_record_list
+ cache = {}
+ # need to accepts ints and longs because ids coming from a method
+ # launched by button in the interface have a type long...
+ if isinstance(select, (int, long)):
+ return browse_record(cr,uid,select,self,cache, context=context, list_class=self._list_class, fields_process=fields_process)
+ elif isinstance(select,list):
+ return self._list_class([browse_record(cr,uid,id,self,cache, context=context, list_class=self._list_class, fields_process=fields_process) for id in select], context)
+ else:
+ return browse_null()
+
+ def __export_row(self, cr, uid, row, fields, context=None):
+ lines = []
+ data = map(lambda x: '', range(len(fields)))
+ done = []
+ for fpos in range(len(fields)):
+ f = fields[fpos]
+ if f:
+ r = row
+ i = 0
+ while i<len(f):
+ r = r[f[i]]
+ if not r:
+ break
+ if isinstance(r, (browse_record_list, list)):
+ first = True
+ fields2 = map(lambda x: (x[:i+1]==f[:i+1] and x[i+1:]) \
+ or [], fields)
+ if fields2 in done:
+ break
+ done.append(fields2)
+ for row2 in r:
+ lines2 = self.__export_row(cr, uid, row2, fields2,
+ context)
+ if first:
+ for fpos2 in range(len(fields)):
+ if lines2 and lines2[0][fpos2]:
+ data[fpos2] = lines2[0][fpos2]
+ lines+= lines2[1:]
+ first = False
+ else:
+ lines+= lines2
+ break
+ i+=1
+ if i==len(f):
+ data[fpos] = str(r or '')
+ return [data] + lines
+
+ def export_data(self, cr, uid, ids, fields, context=None):
+ if not context:
+ context={}
+ fields = map(lambda x: x.split('/'), fields)
+ datas = []
+ for row in self.browse(cr, uid, ids, context):
+ datas += self.__export_row(cr, uid, row, fields, context)
+ return datas
+
+ def import_data(self, cr, uid, fields, datas, mode='init',
+ current_module=None, noupdate=False, context=None):
+ if not context:
+ context={}
+ fields = map(lambda x: x.split('/'), fields)
+ logger = netsvc.Logger()
+ def process_liness(self, datas, prefix, fields_def, position=0):
+ line = datas[position]
+ row = {}
+ translate = {}
+ todo = []
+ warning = ''
+ data_id= False
+ #
+ # Import normal fields
+ #
+ for i in range(len(fields)):
+ if i>=len(line):
+ raise Exception, _('Please check that all your lines have %d columns.') % (len(fields),)
+ field = fields[i]
+ if field == ["id"]:
+ data_id= line[i]
+ continue
+ if (len(field)==len(prefix)+1) and field[len(prefix)].endswith(':id'):
+ res_id = False
+ if line[i]:
+ if fields_def[field[len(prefix)][:-3]]['type']=='many2many':
+ res_id = []
+ for word in line[i].split(','):
+ if '.' in word:
+ module, xml_id = word.rsplit('.', 1)
+ else:
+ module, xml_id = current_module, word
+ ir_model_data_obj = self.pool.get('ir.model.data')
+ id = ir_model_data_obj._get_id(cr, uid, module,
+ xml_id)
+ res_id2 = ir_model_data_obj.read(cr, uid, [id],
+ ['res_id'])[0]['res_id']
+ if res_id2:
+ res_id.append(res_id2)
+ if len(res_id):
+ res_id=[(6,0,res_id)]
+ else:
+ if '.' in line[i]:
+ module, xml_id = line[i].rsplit('.', 1)
+ else:
+ module, xml_id = current_module, line[i]
+ ir_model_data_obj = self.pool.get('ir.model.data')
+ id = ir_model_data_obj._get_id(cr, uid, module, xml_id)
+ res_id = ir_model_data_obj.read(cr, uid, [id],
+ ['res_id'])[0]['res_id']
+ row[field[0][:-3]] = res_id or False
+ continue
+ if (len(field) == len(prefix)+1) and \
+ len(field[len(prefix)].split(':lang=')) == 2:
+ f, lang = field[len(prefix)].split(':lang=')
+ translate.setdefault(lang, {})[f]=line[i] or False
+ continue
+ if (len(field) == len(prefix)+1) and \
+ (prefix == field[0:len(prefix)]):
+ if fields_def[field[len(prefix)]]['type'] == 'integer':
+ res =line[i] and int(line[i])
+ elif fields_def[field[len(prefix)]]['type'] == 'float':
+ res =line[i] and float(line[i])
+ elif fields_def[field[len(prefix)]]['type'] == 'selection':
+ res = False
+ if isinstance(fields_def[field[len(prefix)]]['selection'],
+ (tuple, list)):
+ sel = fields_def[field[len(prefix)]]['selection']
+ else:
+ sel = fields_def[field[len(prefix)]]['selection'](self,
+ cr, uid, context)
+ for key, val in sel:
+ if str(key) == line[i]:
+ res = key
+ if line[i] and not res:
+ logger.notifyChannel("import", netsvc.LOG_WARNING,
+ "key '%s' not found in selection field '%s'" % \
+ (line[i], field[len(prefix)]))
+ elif fields_def[field[len(prefix)]]['type']=='many2one':
+ res = False
+ if line[i]:
+ relation = fields_def[field[len(prefix)]]['relation']
+ res2 = self.pool.get(relation).name_search(cr, uid,
+ line[i], [], operator='=')
+ res = (res2 and res2[0][0]) or False
+ if not res:
+ warning += ('Relation not found: ' + line[i] + \
+ ' on ' + relation + ' !\n')
+ logger.notifyChannel("import", netsvc.LOG_WARNING,
+ 'Relation not found: ' + line[i] + \
+ ' on ' + relation + ' !\n')
+ elif fields_def[field[len(prefix)]]['type']=='many2many':
+ res = []
+ if line[i]:
+ relation = fields_def[field[len(prefix)]]['relation']
+ for word in line[i].split(','):
+ res2 = self.pool.get(relation).name_search(cr,
+ uid, word, [], operator='=')
+ res3 = (res2 and res2[0][0]) or False
+ if not res3:
+ warning += ('Relation not found: ' + \
+ line[i] + ' on '+relation + ' !\n')
+ logger.notifyChannel("import",
+ netsvc.LOG_WARNING,
+ 'Relation not found: ' + line[i] + \
+ ' on '+relation + ' !\n')
+ else:
+ res.append(res3)
+ if len(res):
+ res= [(6,0,res)]
+ else:
+ res = line[i] or False
+ row[field[len(prefix)]] = res
+ elif (prefix==field[0:len(prefix)]):
+ if field[0] not in todo:
+ todo.append(field[len(prefix)])
+ #
+ # Import one2many fields
+ #
+ nbrmax = 1
+ for field in todo:
+ newfd = self.pool.get(fields_def[field]['relation']).fields_get(
+ cr, uid, context=context)
+ res = process_liness(self, datas, prefix + [field], newfd, position)
+ (newrow, max2, w2, translate2, data_id2) = res
+ nbrmax = max(nbrmax, max2)
+ warning = warning + w2
+ reduce(lambda x,y: x and y, newrow)
+ row[field] = (reduce(lambda x, y: x or y, newrow.values()) and \
+ [(0,0,newrow)]) or []
+ i = max2
+ while (position+i)<len(datas):
+ ok = True
+ for j in range(len(fields)):
+ field2 = fields[j]
+ if (len(field2) <= (len(prefix)+1)) and datas[position+i][j]:
+ ok = False
+ if not ok:
+ break
+
+ (newrow, max2, w2, translate2, data_id2) = process_liness(
+ self, datas, prefix+[field], newfd, position+i)
+ warning = warning+w2
+ if reduce(lambda x,y: x or y, newrow.values()):
+ row[field].append((0,0,newrow))
+ i+=max2
+ nbrmax = max(nbrmax, i)
+
+ if len(prefix)==0:
+ for i in range(max(nbrmax,1)):
+ #if datas:
+ datas.pop(0)
+ result = (row, nbrmax, warning, translate, data_id)
+ return result
+
+ fields_def = self.fields_get(cr, uid, context=context)
+ done = 0
+
+ while len(datas):
+ res = {}
+ try:
+ (res, other, warning, translate, data_id) = \
+ process_liness(self, datas, [], fields_def)
+ if warning:
+ cr.rollback()
+ return (-1, res, warning, '')
+ id= self.pool.get('ir.model.data')._update(cr, uid, self._name,
+ current_module, res, xml_id=data_id, mode=mode,
+ noupdate=noupdate)
+ for lang in translate:
+ context2=context.copy()
+ context2['lang']=lang
+ self.write(cr, uid, [id], translate[lang], context2)
+ if config.get('commit_mode', False):
+ cr.commit()
+ except Exception, e:
+ logger.notifyChannel("import",netsvc.LOG_ERROR, e)
+ cr.rollback()
+ try:
+ return (-1, res, e[0], warning)
+ except:
+ return (-1, res, e[0], '')
+ done += 1
+ #
+ # TODO: Send a request with the result and multi-thread !
+ #
+ return (done, 0, 0, 0)
+
+ def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'):
+ raise _('The read method is not implemented on this object !')
+
+ def _validate(self, cr, uid, ids, context=None):
+ context = context or {}
+ lng = context.get('lang', False) or 'en_US'
+ trans = self.pool.get('ir.translation')
+ field_error = []
+ field_err_str = []
+ for constraint in self._constraints:
+ fun, msg, fields = constraint
+ if not fun(self, cr, uid, ids):
+ field_error += fields
+ field_err_str.append( trans._get_source(cr, uid, self._name, 'constraint', lng, source=msg) )
+ if len(field_err_str):
+ cr.rollback()
+ raise except_orm('ValidateError', ('\n'.join(field_err_str), ','.join(field_error)))
+
+ def default_get(self, cr, uid, fields_list, context=None):
+ return {}
+
+ def perm_read(self, cr, user, ids, context=None, details=True):
+ raise _('The perm_read method is not implemented on this object !')
+
+ def unlink(self, cr, uid, ids, context=None):
+ raise _('The unlink method is not implemented on this object !')
+
+ def write(self, cr, user, ids, vals, context=None):
+ raise _('The write method is not implemented on this object !')
+
+ def create(self, cr, user, vals, context=None):
+ raise _('The create method is not implemented on this object !')
+
+ # returns the definition of each field in the object
+ # the optional fields parameter can limit the result to some fields
+ def fields_get(self, cr, user, fields=None, context=None, read_access=True):
+ if context is None:
+ context = {}
+ res = {}
+ translation_obj = self.pool.get('ir.translation')
+ model_access_obj = self.pool.get('ir.model.access')
+ for parent in self._inherits:
+ res.update(self.pool.get(parent).fields_get(cr, user, fields,
+ context))
+ for f in self._columns.keys():
+ res[f] = {'type': self._columns[f]._type}
+ for arg in ('string', 'readonly', 'states', 'size', 'required',
+ 'change_default', 'translate', 'help', 'select'):
+ if getattr(self._columns[f], arg):
+ res[f][arg] = getattr(self._columns[f], arg)
+ if not read_access:
+ res[f]['readonly']= True
+ res[f]['states'] = {}
+ for arg in ('digits', 'invisible'):
+ if hasattr(self._columns[f], arg) \
+ 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:
+ res[f]['string'] = res_trans
+ help_trans = translation_obj._get_source(cr, user,
+ self._name + ',' + f, 'help', context.get('lang', False) or 'en_US')
+ if help_trans:
+ res[f]['help'] = help_trans
+
+ if hasattr(self._columns[f], 'selection'):
+ if isinstance(self._columns[f].selection, (tuple, list)):
+ sel = self._columns[f].selection
+ # translate each selection option
+ sel2 = []
+ for (key,val) in sel:
+ val2 = translation_obj._get_source(cr, user,
+ self._name + ',' + f, 'selection',
+ context.get('lang', False) or 'en_US', val)
+ sel2.append((key, val2 or val))
+ sel = sel2
+ res[f]['selection'] = sel
+ else:
+ # call the 'dynamic selection' function
+ res[f]['selection'] = self._columns[f].selection(self, cr,
+ user, context)
+ if res[f]['type'] in ('one2many', 'many2many',
+ 'many2one', 'one2one'):
+ res[f]['relation'] = self._columns[f]._obj
+ res[f]['domain'] = self._columns[f]._domain
+ res[f]['context'] = self._columns[f]._context
+
+ if fields:
+ # filter out fields which aren't in the fields list
+ for r in res.keys():
+ if r not in fields:
+ del res[r]
+ return res
+
+ #
+ # Overload this method if you need a window title which depends on the context
+ #
+ def view_header_get(self, cr, user, view_id=None, view_type='form', context=None):
+ return False
+
+ def __view_look_dom(self, cr, user, node, context=None):
+ if not context:
+ context={}
+ result = False
+ fields = {}
+ childs = True
+
+ if node.nodeType==node.ELEMENT_NODE and node.localName=='field':
+ if node.hasAttribute('name'):
+ attrs = {}
+ try:
+ if node.getAttribute('name') in self._columns:
+ relation = self._columns[node.getAttribute('name')]._obj
+ else:
+ relation = self._inherit_fields[node.getAttribute('name')][2]._obj
+ except:
+ relation = False
+
+ if relation:
+ childs = False
+ views = {}
+ for f in node.childNodes:
+ if f.nodeType==f.ELEMENT_NODE and f.localName in ('form','tree','graph'):
+ node.removeChild(f)
+ xarch,xfields = self.pool.get(relation).__view_look_dom_arch(cr, user, f, context)
+ views[str(f.localName)] = {
+ 'arch': xarch,
+ 'fields': xfields
+ }
+ attrs = {'views': views}
+ fields[node.getAttribute('name')] = attrs
+
+ elif node.nodeType==node.ELEMENT_NODE and node.localName in ('form','tree'):
+ result = self.view_header_get(cr, user, False, node.localName, context)
+ if result:
+ node.setAttribute('string', result.decode('utf-8'))
+ if node.nodeType==node.ELEMENT_NODE and node.hasAttribute('groups'):
+ groups = None
+ group_str = node.getAttribute('groups')
+ if ',' in group_str:
+ groups = group_str.split(',');
+ readonly = False
+ access_pool = self.pool.get('ir.model.access')
+ for group in groups:
+ readonly = readonly and access_pool.check_groups(cr, user, group)
+
+ if readonly:
+ parent = node.parentNode
+ parent.removeChild(node)
+
+ else:
+ if not self.pool.get('ir.model.access').check_groups(cr, user, group_str):
+ parent = node.parentNode
+ parent.removeChild(node)
+
+ if node.nodeType == node.ELEMENT_NODE:
+ # 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'))
+ if trans:
+ node.setAttribute('string', trans.decode('utf8'))
+ 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'))
+ #
+ # Add view for properties !
+ #
+ if node.localName=='properties':
+ parent = node.parentNode
+ doc = node.ownerDocument
+ models = map(lambda x: "'"+x+"'", [self._name] + self._inherits.keys())
+ cr.execute('select id,name,group_name from ir_model_fields where model in ('+','.join(models)+') and view_load order by group_name, id')
+ oldgroup = None
+ res = cr.fetchall()
+ for id, fname, gname in res:
+ if oldgroup != gname:
+ child = doc.createElement('separator')
+ child.setAttribute('string', gname.decode('utf-8'))
+ child.setAttribute('colspan', "4")
+ oldgroup = gname
+ parent.insertBefore(child, node)
+
+ child = doc.createElement('field')
+ child.setAttribute('name', fname.decode('utf-8'))
+ parent.insertBefore(child, node)
+ parent.removeChild(node)
+
+ if childs:
+ for f in node.childNodes:
+ fields.update(self.__view_look_dom(cr, user, f,context))
+ return fields
+
+ def __view_look_dom_arch(self, cr, user, node, context=None):
+ if not context:
+ context={}
+ fields_def = self.__view_look_dom(cr, user, node, context=context)
+
+ buttons = xpath.Evaluate('//button', node)
+ if buttons:
+ for button in buttons:
+ if button.getAttribute('type') == 'object':
+ continue
+
+ ok = True
+
+ serv = netsvc.LocalService('object_proxy')
+ user_roles = serv.execute_cr(cr, user, 'res.users', 'read', [user], ['roles_id'])[0]['roles_id']
+ cr.execute("select role_id from wkf_transition where signal='%s'" % button.getAttribute('name'))
+ roles = cr.fetchall()
+ for role in roles:
+ if role[0]:
+ ok = ok and serv.execute_cr(cr, user, 'res.roles', 'check', user_roles, role[0])
+
+ if not ok:
+ button.setAttribute('readonly', '1')
+ else:
+ button.setAttribute('readonly', '0')
+
+ arch = node.toxml(encoding="utf-8").replace('\t', '')
+
+ fields = self.fields_get(cr, user, fields_def.keys(), context)
+ for field in fields_def:
+ fields[field].update(fields_def[field])
+ return arch, fields
+
+
+ def __get_default_calendar_view(self):
+ """Generate a default calendar view (For internal use only).
+ """
+
+ arch = ('<?xml version="1.0" encoding="utf-8"?>\n'
+ '<calendar string="%s" date_start="%s"') % (self._description, self._date_name)
+
+ if 'user_id' in self._columns:
+ arch += ' color="user_id"'
+
+ elif 'partner_id' in self._columns:
+ arch += ' color="partner_id"'
+
+ if 'date_stop' in self._columns:
+ arch += ' date_stop="date_stop"'
+
+ elif 'date_end' in self._columns:
+ arch += ' date_stop="date_end"'
+
+ elif 'date_delay' in self._columns:
+ arch += ' date_delay="date_delay"'
+
+ elif 'planned_hours' in self._columns:
+ arch += ' date_delay="planned_hours"'
+
+ arch += ('>\n'
+ ' <field name="%s"/>\n'
+ '</calendar>') % (self._rec_name)
+
+ return arch
+
+ #
+ # if view_id, view_type is not required
+ #
+ def fields_view_get(self, cr, user, view_id=None, view_type='form', context=None, toolbar=False):
+ if not context:
+ context={}
+ def _inherit_apply(src, inherit):
+ def _find(node, node2):
+ # Check if xpath query or normal inherit (with field matching)
+ if node2.nodeType==node2.ELEMENT_NODE and node2.localName=='xpath':
+ res = xpath.Evaluate(node2.getAttribute('expr'), node)
+ return res and res[0]
+ else:
+ if node.nodeType==node.ELEMENT_NODE and node.localName==node2.localName:
+ res = True
+ for attr in node2.attributes.keys():
+ if attr=='position':
+ continue
+ if node.hasAttribute(attr):
+ if node.getAttribute(attr)==node2.getAttribute(attr):
+ continue
+ res = False
+ if res:
+ return node
+ for child in node.childNodes:
+ res = _find(child, node2)
+ if res: return res
+ return None
+
+ doc_src = dom.minidom.parseString(src)
+ doc_dest = dom.minidom.parseString(inherit)
+ toparse = doc_dest.childNodes
+ while len(toparse):
+ node2 = toparse.pop(0)
+ if not node2.nodeType==node2.ELEMENT_NODE:
+ continue
+ if node2.localName=='data':
+ toparse += node2.childNodes
+ continue
+ node = _find(doc_src, node2)
+ if node:
+ pos = 'inside'
+ if node2.hasAttribute('position'):
+ pos = node2.getAttribute('position')
+ if pos=='replace':
+ parent = node.parentNode
+ for child in node2.childNodes:
+ if child.nodeType==child.ELEMENT_NODE:
+ parent.insertBefore(child, node)
+ parent.removeChild(node)
+ else:
+ for child in node2.childNodes:
+ if child.nodeType==child.ELEMENT_NODE:
+ if pos=='inside':
+ node.appendChild(child)
+ elif pos=='after':
+ sib = node.nextSibling
+ if sib:
+ node.parentNode.insertBefore(child, sib)
+ else:
+ node.parentNode.appendChild(child)
+ elif pos=='before':
+ node.parentNode.insertBefore(child, node)
+ else:
+ raise AttributeError, _('Unknown position in inherited view %s !') % pos
+ else:
+ attrs = ''.join([
+ ' %s="%s"' % (attr, node2.getAttribute(attr))
+ for attr in node2.attributes.keys()
+ if attr != 'position'
+ ])
+ tag = "<%s%s>" % (node2.localName, attrs)
+ raise AttributeError, _("Couldn't find tag '%s' in parent view !") % tag
+ return doc_src.toxml(encoding="utf-8").replace('\t', '')
+
+ result = {'type':view_type, 'model':self._name}
+
+ ok = True
+ model = True
+ sql_res = False
+ 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,))
+ else:
+ cr.execute('SELECT arch,name,field_parent,id,type,inherit_id FROM ir_ui_view WHERE model=%s AND type=%s ORDER BY priority', (self._name,view_type))
+ sql_res = cr.fetchone()
+ if not sql_res:
+ break
+ ok = sql_res[5]
+ view_id = ok or sql_res[3]
+ model = False
+
+ # if a view was found
+ if sql_res:
+ result['type'] = sql_res[4]
+ result['view_id'] = sql_res[3]
+ result['arch'] = sql_res[0]
+
+ 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))
+ sql_inherit = cr.fetchall()
+ for (inherit,id) in sql_inherit:
+ result = _inherit_apply(result, inherit)
+ result = _inherit_apply_rec(result, id)
+ return result
+
+ result['arch'] = _inherit_apply_rec(result['arch'], sql_res[3])
+
+ result['name'] = sql_res[1]
+ result['field_parent'] = sql_res[2] or False
+ else:
+ # otherwise, build some kind of default view
+ if view_type == 'form':
+ res = self.fields_get(cr, user, context=context)
+ xml = '''<?xml version="1.0" encoding="utf-8"?>''' \
+ '''<form string="%s">''' % (self._description,)
+ for x in res:
+ if res[x]['type'] not in ('one2many', 'many2many'):
+ xml += '<field name="%s"/>' % (x,)
+ if res[x]['type'] == 'text':
+ xml += "<newline/>"
+ xml += "</form>"
+ elif view_type == 'tree':
+ xml = '''<?xml version="1.0" encoding="utf-8"?>''' \
+ '''<tree string="%s"><field name="%s"/></tree>''' \
+ % (self._description, self._rec_name)
+ elif view_type == 'calendar':
+ xml = self.__get_default_calendar_view()
+ else:
+ xml = ''
+ result['arch'] = xml
+ result['name'] = 'default'
+ result['field_parent'] = False
+ result['view_id'] = 0
+
+ doc = dom.minidom.parseString(result['arch'].encode('utf-8'))
+ xarch, xfields = self.__view_look_dom_arch(cr, user, doc, context=context)
+ result['arch'] = xarch
+ result['fields'] = xfields
+ if toolbar:
+ def clean(x):
+ x = x[2]
+ for key in ('report_sxw_content', 'report_rml_content',
+ 'report_sxw', 'report_rml',
+ 'report_sxw_content_data', 'report_rml_content_data'):
+ if key in x:
+ del x[key]
+ return x
+ ir_values_obj = self.pool.get('ir.values')
+ resprint = ir_values_obj.get(cr, user, 'action',
+ 'client_print_multi', [(self._name, False)], False,
+ context)
+ resaction = ir_values_obj.get(cr, user, 'action',
+ 'client_action_multi', [(self._name, False)], False,
+ context)
+
+ resrelate = ir_values_obj.get(cr, user, 'action',
+ 'client_action_relate', [(self._name, False)], False,
+ context)
+ resprint = map(clean, resprint)
+ resaction = map(clean, resaction)
+ resaction = filter(lambda x: not x.get('multi',False), resaction)
+ resprint = filter(lambda x: not x.get('multi',False), resprint)
+ resrelate = map(lambda x:x[2], resrelate)
+
+ for x in resprint+resaction+resrelate:
+ x['string'] = x['name']
+
+ result['toolbar'] = {
+ 'print': resprint,
+ 'action': resaction,
+ 'relate': resrelate
+ }
+ return result
+
+ _view_look_dom_arch=__view_look_dom_arch
+
+ def search_count(self, cr, user, args, context=None):
+ if not context:
+ context = {}
+ res = self.search(cr, user, args, context=context, count=True)
+ if isinstance(res, list):
+ return len(res)
+ return res
+
+ def search(self, cr, user, args, offset=0, limit=None, order=None,
+ context=None, count=False):
+ raise _('The search method is not implemented on this object !')
+
+ def name_get(self, cr, user, ids, context=None):
+ raise _('The name_get method is not implemented on this object !')
+
+ def name_search(self, cr, user, name='', args=None, operator='ilike', context=None, limit=80):
+ raise _('The name_search method is not implemented on this object !')
+
+ def copy(self, cr, uid, id, default=None, context=None):
+ raise _('The copy method is not implemented on this object !')
class orm_memory(orm_template):
- _protected = ['read','write','create','default_get','perm_read','unlink','fields_get','fields_view_get','search','name_get','distinct_field_get','name_search','copy','import_data','search_count']
- _inherit_fields = {}
- _max_count = 200
- _max_hours = 1
- _check_time = 20
- def __init__(self, cr):
- super(orm_memory, self).__init__(cr)
- self.datas = {}
- self.next_id = 0
- self.check_id = 0
- cr.execute('delete from wkf_instance where res_type=%s', (self._name,))
-
- def clear(self):
- self.check_id+=1
- if self.check_id % self._check_time:
- return True
- tounlink = []
- max = time.time() - self._max_hours * 60 * 60
- for id in self.datas:
- if self.datas[id]['internal.date_access'] < max:
- tounlink.append(id)
- self.unlink(tounlink)
- if len(self.datas)>self._max_count:
- sorted = map(lambda x: (x[1]['internal.date_access'], x[0]), self.datas.items())
- sorted.sort()
- ids = map(lambda x: x[1], sorted[:len(self.datas)-self._max_count])
- self.unlink(ids)
- return True
-
- def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'):
- if not fields:
- fields = self._columns.keys()
- result = []
- for id in ids:
- r = {'id': id}
- for f in fields:
- r[f] = self.datas[id].get(f, False)
- result.append(r)
- self.datas[id]['internal.date_access'] = time.time()
- fields_post = filter(lambda x: x in self._columns and not getattr(self._columns[x], load), fields)
- for f in fields_post:
- res2 = self._columns[f].get_memory(cr, self, ids, f, user, context=context, values=False)
- for record in result:
- record[f] = res2[record['id']]
- return result
-
- def write(self, cr, user, ids, vals, context=None):
- vals2 = {}
- upd_todo = []
- for field in vals:
- if self._columns[field]._classic_write:
- vals2[field] = vals[field]
- else:
- upd_todo.append(field)
- for id_new in ids:
- self.datas[id_new].update(vals2)
- self.datas[id_new]['internal.date_access'] = time.time()
- for field in upd_todo:
- self._columns[field].set_memory(cr, self, id_new, field, vals[field], user, context)
- self._validate(cr, user, [id_new], context)
- wf_service = netsvc.LocalService("workflow")
- wf_service.trg_write(user, self._name, id_new, cr)
- self.clear()
- return id_new
-
- def create(self, cr, user, vals, context=None):
- self.next_id += 1
- id_new = self.next_id
- default = []
- for f in self._columns.keys():
- if not f in vals:
- default.append(f)
- if len(default):
- vals.update(self.default_get(cr, user, default, context))
- vals2 = {}
- upd_todo = []
- for field in vals:
- if self._columns[field]._classic_write:
- vals2[field] = vals[field]
- else:
- upd_todo.append(field)
- self.datas[id_new] = vals2
- self.datas[id_new]['internal.date_access'] = time.time()
- for field in upd_todo:
- self._columns[field].set_memory(cr, self, id_new, field, vals[field], user, context)
- self._validate(cr, user, [id_new], context)
- wf_service = netsvc.LocalService("workflow")
- wf_service.trg_create(user, self._name, id_new, cr)
- self.clear()
- return id_new
-
- def default_get(self, cr, uid, fields_list, context=None):
- if not context:
- context={}
- value = {}
- # get the default values for the inherited fields
- for f in fields_list:
- if f in self._defaults:
- value[f] = self._defaults[f](self, cr, uid, context)
- fld_def = ((f in self._columns) and self._columns[f]) \
- or ((f in self._inherit_fields ) and self._inherit_fields[f][2]) \
- or False
-
- # get the default values set by the user and override the default
- # values defined in the object
- ir_values_obj = self.pool.get('ir.values')
- res = ir_values_obj.get(cr, uid, 'default', False, [self._name])
- for id, field, field_value in res:
- if field in fields_list:
- fld_def = (field in self._columns)
- if fld_def._type in ('many2one', 'one2one'):
- obj = self.pool.get(fld_def._obj)
- if not obj.search(cr, uid, [('id', '=', field_value)]):
- continue
- if fld_def._type in ('many2many'):
- obj = self.pool.get(fld_def._obj)
- field_value2 = []
- for i in range(len(field_value)):
- if not obj.search(cr, uid, [('id', '=',
- field_value[i])]):
- continue
- field_value2.append(field_value[i])
- field_value = field_value2
- if fld_def._type in ('one2many'):
- obj = self.pool.get(fld_def._obj)
- field_value2 = []
- for i in range(len(field_value)):
- field_value2.append({})
- for field2 in field_value[i]:
- if obj._columns[field2]._type in ('many2one', 'one2one'):
- obj2 = self.pool.get(obj._columns[field2]._obj)
- if not obj2.search(cr, uid,
- [('id', '=', field_value[i][field2])]):
- continue
- # TODO add test for many2many and one2many
- field_value2[i][field2] = field_value[i][field2]
- field_value = field_value2
- value[field] = field_value
- return value
-
- def search(self, cr, user, args, offset=0, limit=None, order=None,
- context=None, count=False):
- return self.datas.keys()
-
- def unlink(self, cr, uid, ids, context=None):
- for id in ids:
- if id in self.datas:
- del self.datas[id]
- if len(ids):
- cr.execute('delete from wkf_instance where res_type=%s and res_id in ('+','.join(map(str,ids))+')', (self._name, ))
- return True
-
- def perm_read(self, cr, user, ids, context=None, details=True):
- result = []
- for id in ids:
- result.append({
- 'create_uid': (user, 'Root'),
- 'create_date': time.strftime('%Y-%m-%d %H:%M:%S'),
- 'write_uid': False,
- 'write_date': False,
- 'id': id
- })
- return result
+ _protected = ['read','write','create','default_get','perm_read','unlink','fields_get','fields_view_get','search','name_get','distinct_field_get','name_search','copy','import_data','search_count']
+ _inherit_fields = {}
+ _max_count = 200
+ _max_hours = 1
+ _check_time = 20
+ def __init__(self, cr):
+ super(orm_memory, self).__init__(cr)
+ self.datas = {}
+ self.next_id = 0
+ self.check_id = 0
+ cr.execute('delete from wkf_instance where res_type=%s', (self._name,))
+
+ def clear(self):
+ self.check_id+=1
+ if self.check_id % self._check_time:
+ return True
+ tounlink = []
+ max = time.time() - self._max_hours * 60 * 60
+ for id in self.datas:
+ if self.datas[id]['internal.date_access'] < max:
+ tounlink.append(id)
+ self.unlink(tounlink)
+ if len(self.datas)>self._max_count:
+ sorted = map(lambda x: (x[1]['internal.date_access'], x[0]), self.datas.items())
+ sorted.sort()
+ ids = map(lambda x: x[1], sorted[:len(self.datas)-self._max_count])
+ self.unlink(ids)
+ return True
+
+ def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'):
+ if not fields:
+ fields = self._columns.keys()
+ result = []
+ for id in ids:
+ r = {'id': id}
+ for f in fields:
+ r[f] = self.datas[id].get(f, False)
+ result.append(r)
+ self.datas[id]['internal.date_access'] = time.time()
+ fields_post = filter(lambda x: x in self._columns and not getattr(self._columns[x], load), fields)
+ for f in fields_post:
+ res2 = self._columns[f].get_memory(cr, self, ids, f, user, context=context, values=False)
+ for record in result:
+ record[f] = res2[record['id']]
+ return result
+
+ def write(self, cr, user, ids, vals, context=None):
+ vals2 = {}
+ upd_todo = []
+ for field in vals:
+ if self._columns[field]._classic_write:
+ vals2[field] = vals[field]
+ else:
+ upd_todo.append(field)
+ for id_new in ids:
+ self.datas[id_new].update(vals2)
+ self.datas[id_new]['internal.date_access'] = time.time()
+ for field in upd_todo:
+ self._columns[field].set_memory(cr, self, id_new, field, vals[field], user, context)
+ self._validate(cr, user, [id_new], context)
+ wf_service = netsvc.LocalService("workflow")
+ wf_service.trg_write(user, self._name, id_new, cr)
+ self.clear()
+ return id_new
+
+ def create(self, cr, user, vals, context=None):
+ self.next_id += 1
+ id_new = self.next_id
+ default = []
+ for f in self._columns.keys():
+ if not f in vals:
+ default.append(f)
+ if len(default):
+ vals.update(self.default_get(cr, user, default, context))
+ vals2 = {}
+ upd_todo = []
+ for field in vals:
+ if self._columns[field]._classic_write:
+ vals2[field] = vals[field]
+ else:
+ upd_todo.append(field)
+ self.datas[id_new] = vals2
+ self.datas[id_new]['internal.date_access'] = time.time()
+ for field in upd_todo:
+ self._columns[field].set_memory(cr, self, id_new, field, vals[field], user, context)
+ self._validate(cr, user, [id_new], context)
+ wf_service = netsvc.LocalService("workflow")
+ wf_service.trg_create(user, self._name, id_new, cr)
+ self.clear()
+ return id_new
+
+ def default_get(self, cr, uid, fields_list, context=None):
+ if not context:
+ context={}
+ value = {}
+ # get the default values for the inherited fields
+ for f in fields_list:
+ if f in self._defaults:
+ value[f] = self._defaults[f](self, cr, uid, context)
+ fld_def = ((f in self._columns) and self._columns[f]) \
+ or ((f in self._inherit_fields ) and self._inherit_fields[f][2]) \
+ or False
+
+ # get the default values set by the user and override the default
+ # values defined in the object
+ ir_values_obj = self.pool.get('ir.values')
+ res = ir_values_obj.get(cr, uid, 'default', False, [self._name])
+ for id, field, field_value in res:
+ if field in fields_list:
+ fld_def = (field in self._columns)
+ if fld_def._type in ('many2one', 'one2one'):
+ obj = self.pool.get(fld_def._obj)
+ if not obj.search(cr, uid, [('id', '=', field_value)]):
+ continue
+ if fld_def._type in ('many2many'):
+ obj = self.pool.get(fld_def._obj)
+ field_value2 = []
+ for i in range(len(field_value)):
+ if not obj.search(cr, uid, [('id', '=',
+ field_value[i])]):
+ continue
+ field_value2.append(field_value[i])
+ field_value = field_value2
+ if fld_def._type in ('one2many'):
+ obj = self.pool.get(fld_def._obj)
+ field_value2 = []
+ for i in range(len(field_value)):
+ field_value2.append({})
+ for field2 in field_value[i]:
+ if obj._columns[field2]._type in ('many2one', 'one2one'):
+ obj2 = self.pool.get(obj._columns[field2]._obj)
+ if not obj2.search(cr, uid,
+ [('id', '=', field_value[i][field2])]):
+ continue
+ # TODO add test for many2many and one2many
+ field_value2[i][field2] = field_value[i][field2]
+ field_value = field_value2
+ value[field] = field_value
+ return value
+
+ def search(self, cr, user, args, offset=0, limit=None, order=None,
+ context=None, count=False):
+ return self.datas.keys()
+
+ def unlink(self, cr, uid, ids, context=None):
+ for id in ids:
+ if id in self.datas:
+ del self.datas[id]
+ if len(ids):
+ cr.execute('delete from wkf_instance where res_type=%s and res_id in ('+','.join(map(str,ids))+')', (self._name, ))
+ return True
+
+ def perm_read(self, cr, user, ids, context=None, details=True):
+ result = []
+ for id in ids:
+ result.append({
+ 'create_uid': (user, 'Root'),
+ 'create_date': time.strftime('%Y-%m-%d %H:%M:%S'),
+ 'write_uid': False,
+ 'write_date': False,
+ 'id': id
+ })
+ return result
class orm(orm_template):
- _sql_constraints = []
-
- _log_access = True
- _table = None
- _protected = ['read','write','create','default_get','perm_read','unlink','fields_get','fields_view_get','search','name_get','distinct_field_get','name_search','copy','import_data','search_count']
- def _auto_init(self, cr, context={}):
- logger = netsvc.Logger()
- create = False
- self._field_create(cr, context=context)
- if not hasattr(self, "_auto") or self._auto:
- cr.execute("SELECT relname FROM pg_class WHERE relkind in ('r','v') AND relname='%s'" % self._table)
- if not cr.rowcount:
- cr.execute("CREATE TABLE \"%s\" (id SERIAL NOT NULL, PRIMARY KEY(id)) WITH OIDS" % self._table)
- create = True
- cr.commit()
- if self._log_access:
- logs = {
- 'create_uid': 'INTEGER REFERENCES res_users ON DELETE SET NULL',
- 'create_date': 'TIMESTAMP',
- 'write_uid': 'INTEGER REFERENCES res_users ON DELETE SET NULL',
- 'write_date': 'TIMESTAMP'
- }
- for k in logs:
- 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))
- if not cr.rowcount:
- 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
- # of fields which were required but have been removed
- 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)
- 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']))
-
- # iterate on the "object columns"
- for k in self._columns:
- if k in ('id','write_uid','write_date','create_uid','create_date'):
- continue
- #raise _('Can not define a column %s. Reserved keyword !') % (k,)
- f = self._columns[k]
-
- 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))
- 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))
- 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():
- #FIXME: Remove this try/except
- try:
- 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.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))
- res = cr.dictfetchall()
- if not res:
- 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]))
-
- # 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))
- 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 r in res.items():
- cr.execute("UPDATE \"%s\" SET \"%s\"='%s' where id=%d"% (self._table, k, r[1],r[0]))
-
- # and add constraints if needed
- if isinstance(f, fields.many2one):
- #FIXME: Remove this try/except
- try:
- ref = self.pool.get(f._obj)._table
- except AttributeError:
- 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))
- if f.select:
- 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))
- except:
- logger.notifyChannel('init', netsvc.LOG_WARNING, 'WARNING: unable to set column %s of table %s not null !\nTry to re-run: tinyerp-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()
- elif len(res)==1:
- f_pg_def = res[0]
- f_pg_type = f_pg_def['typname']
- f_pg_size = f_pg_def['size']
- f_pg_notnull = f_pg_def['attnotnull']
- if isinstance(f, fields.function) and not f.store:
- logger.notifyChannel('init', netsvc.LOG_WARNING, 'column %s (%s) in table %s was converted to a function !\nYou should remove this column from your database.' % (k, f.string, self._table))
- f_obj_type = None
- else:
- f_obj_type = get_pg_type(f) and get_pg_type(f)[0]
-
- if f_obj_type:
- if f_pg_type != f_obj_type:
- logger.notifyChannel('init', netsvc.LOG_WARNING, "column '%s' in table '%s' has changed type (DB = %s, def = %s) !" % (k, self._table, f_pg_type, f._type))
- if f_pg_type == 'varchar' and f._type == 'char' and f_pg_size != f.size:
- # columns with the name 'type' cannot be changed for an unknown reason?!
- if k != 'type':
- if f_pg_size > f.size:
- logger.notifyChannel('init', netsvc.LOG_WARNING, "column '%s' in table '%s' has changed size (DB = %d, def = %d), strings will be truncated !" % (k, self._table, f_pg_size, f.size))
+ _sql_constraints = []
+
+ _log_access = True
+ _table = None
+ _protected = ['read','write','create','default_get','perm_read','unlink','fields_get','fields_view_get','search','name_get','distinct_field_get','name_search','copy','import_data','search_count']
+ def _auto_init(self, cr, context={}):
+ logger = netsvc.Logger()
+ create = False
+ self._field_create(cr, context=context)
+ if not hasattr(self, "_auto") or self._auto:
+ cr.execute("SELECT relname FROM pg_class WHERE relkind in ('r','v') AND relname='%s'" % self._table)
+ if not cr.rowcount:
+ cr.execute("CREATE TABLE \"%s\" (id SERIAL NOT NULL, PRIMARY KEY(id)) WITH OIDS" % self._table)
+ create = True
+ cr.commit()
+ if self._log_access:
+ logs = {
+ 'create_uid': 'INTEGER REFERENCES res_users ON DELETE SET NULL',
+ 'create_date': 'TIMESTAMP',
+ 'write_uid': 'INTEGER REFERENCES res_users ON DELETE SET NULL',
+ 'write_date': 'TIMESTAMP'
+ }
+ for k in logs:
+ 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))
+ if not cr.rowcount:
+ 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
+ # of fields which were required but have been removed
+ 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)
+ 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']))
+
+ # iterate on the "object columns"
+ for k in self._columns:
+ if k in ('id','write_uid','write_date','create_uid','create_date'):
+ continue
+ #raise _('Can not define a column %s. Reserved keyword !') % (k,)
+ f = self._columns[k]
+
+ 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))
+ 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))
+ 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():
+ #FIXME: Remove this try/except
+ try:
+ 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.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))
+ res = cr.dictfetchall()
+ if not res:
+ 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]))
+
+ # 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))
+ 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 r in res.items():
+ cr.execute("UPDATE \"%s\" SET \"%s\"='%s' where id=%d"% (self._table, k, r[1],r[0]))
+
+ # and add constraints if needed
+ if isinstance(f, fields.many2one):
+ #FIXME: Remove this try/except
+ try:
+ ref = self.pool.get(f._obj)._table
+ except AttributeError:
+ 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))
+ if f.select:
+ 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))
+ except:
+ logger.notifyChannel('init', netsvc.LOG_WARNING, 'WARNING: unable to set column %s of table %s not null !\nTry to re-run: tinyerp-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()
+ elif len(res)==1:
+ f_pg_def = res[0]
+ f_pg_type = f_pg_def['typname']
+ f_pg_size = f_pg_def['size']
+ f_pg_notnull = f_pg_def['attnotnull']
+ if isinstance(f, fields.function) and not f.store:
+ logger.notifyChannel('init', netsvc.LOG_WARNING, 'column %s (%s) in table %s was converted to a function !\nYou should remove this column from your database.' % (k, f.string, self._table))
+ f_obj_type = None
+ else:
+ f_obj_type = get_pg_type(f) and get_pg_type(f)[0]
+
+ if f_obj_type:
+ if f_pg_type != f_obj_type:
+ logger.notifyChannel('init', netsvc.LOG_WARNING, "column '%s' in table '%s' has changed type (DB = %s, def = %s) !" % (k, self._table, f_pg_type, f._type))
+ if f_pg_type == 'varchar' and f._type == 'char' and f_pg_size != f.size:
+ # columns with the name 'type' cannot be changed for an unknown reason?!
+ if k != 'type':
+ if f_pg_size > f.size:
+ logger.notifyChannel('init', netsvc.LOG_WARNING, "column '%s' in table '%s' has changed size (DB = %d, def = %d), strings will be truncated !" % (k, self._table, f_pg_size, f.size))
#TODO: check si y a des donnees qui vont poser probleme (select char_length(...))
#TODO: issue a log message even 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.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 self._defaults.has_key(k):
- 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))
- cr.commit()
- # add the NOT NULL constraint
- try:
- 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.commit()
- cr.execute("SELECT indexname FROM pg_indexes WHERE indexname = '%s_%s_index' and tablename = '%s'" % (self._table, k, 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.commit()
- if res and not f.select:
- 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'))
- res = cr.dictfetchall()
- if res:
- confdeltype = {
- 'RESTRICT': 'r',
- 'NO ACTION': 'a',
- 'CASCADE': 'c',
- 'SET NULL': 'n',
- 'SET DEFAULT': 'd',
- }
- if res[0]['confdeltype'] != confdeltype.get(f.ondelete.upper(), 'a'):
- cr.execute('ALTER TABLE "' + self._table + '" DROP CONSTRAINT "' + res[0]['conname'] + '"')
- cr.execute('ALTER TABLE "' + self._table + '" ADD FOREIGN KEY ("' + k + '") REFERENCES "' + ref + '" ON DELETE ' + f.ondelete)
- cr.commit()
- else:
- print "ERROR"
- else:
- 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))
- if not cr.dictfetchall():
- try:
- 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,))
-
- if create:
- if hasattr(self,"_sql"):
- for line in self._sql.split(';'):
- line2 = line.replace('\n','').strip()
- if line2:
- cr.execute(line2)
- cr.commit()
-
- def __init__(self, cr):
- super(orm, self).__init__(cr)
- 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 (key,_,msg) in self._sql_constraints:
- self.pool._sql_error[self._table+'_'+key] = msg
-
- # Load manual fields
-
- cr.execute("SELECT id FROM ir_model_fields WHERE name=%s AND model=%s", ('state','ir.model.fields'))
- if cr.fetchone():
- cr.execute('SELECT * FROM ir_model_fields WHERE model=%s AND state=%s', (self._name,'manual'))
- for field in cr.dictfetchall():
- if field['name'] in self._columns:
- continue
- attrs = {
- 'string': field['field_description'],
- 'required': bool(field['required']),
- 'readonly': bool(field['readonly']),
- 'domain': field['domain'] or None,
- 'size': field['size'],
- 'ondelete': field['on_delete'],
- 'translate': (field['translate']),
- #'select': int(field['select_level'])
- }
- #if field['relation']:
- # attrs['relation'] = field['relation']
- if field['ttype'] == 'selection':
- self._columns[field['name']] = getattr(fields, field['ttype'])(eval(field['selection']), **attrs)
- elif field['ttype'] == 'many2one':
- self._columns[field['name']] = getattr(fields, field['ttype'])(field['relation'], **attrs)
- else:
- self._columns[field['name']] = getattr(fields, field['ttype'])(**attrs)
-
- self._inherits_reload()
- if not self._sequence:
- self._sequence = self._table+'_id_seq'
- for k in self._defaults:
- assert (k in self._columns) or (k in self._inherit_fields), 'Default function defined in %s but field %s does not exist !' % (self._name, k,)
- for f in self._columns:
- self._columns[f].restart()
-
- def default_get(self, cr, uid, fields_list, context=None):
- if not context:
- context={}
- value = {}
- # get the default values for the inherited fields
- for t in self._inherits.keys():
- value.update(self.pool.get(t).default_get(cr, uid, fields_list,
- context))
-
- # get the default values defined in the object
- for f in fields_list:
- if f in self._defaults:
- value[f] = self._defaults[f](self, cr, uid, context)
- fld_def = ((f in self._columns) and self._columns[f]) \
- or ((f in self._inherit_fields ) and self._inherit_fields[f][2]) \
- or False
- if isinstance(fld_def, fields.property):
- property_obj = self.pool.get('ir.property')
- definition_id = fld_def._field_get(cr, uid, self._name, f)
- nid = property_obj.search(cr, uid, [('fields_id', '=',
- definition_id), ('res_id', '=', False)])
- if nid:
- prop_value = property_obj.browse(cr, uid, nid[0],
- context=context).value
- value[f] = (prop_value and int(prop_value.split(',')[1])) \
- or False
-
- # get the default values set by the user and override the default
- # values defined in the object
- ir_values_obj = self.pool.get('ir.values')
- res = ir_values_obj.get(cr, uid, 'default', False, [self._name])
- for id, field, field_value in res:
- if field in fields_list:
- fld_def = (field in self._columns) and self._columns[field] or self._inherit_fields[field][2]
- if fld_def._type in ('many2one', 'one2one'):
- obj = self.pool.get(fld_def._obj)
- if not obj.search(cr, uid, [('id', '=', field_value)]):
- continue
- if fld_def._type in ('many2many'):
- obj = self.pool.get(fld_def._obj)
- field_value2 = []
- for i in range(len(field_value)):
- if not obj.search(cr, uid, [('id', '=',
- field_value[i])]):
- continue
- field_value2.append(field_value[i])
- field_value = field_value2
- if fld_def._type in ('one2many'):
- obj = self.pool.get(fld_def._obj)
- field_value2 = []
- for i in range(len(field_value)):
- field_value2.append({})
- for field2 in field_value[i]:
- if obj._columns[field2]._type in ('many2one', 'one2one'):
- obj2 = self.pool.get(obj._columns[field2]._obj)
- if not obj2.search(cr, uid,
- [('id', '=', field_value[i][field2])]):
- continue
- # TODO add test for many2many and one2many
- field_value2[i][field2] = field_value[i][field2]
- field_value = field_value2
- value[field] = field_value
- return value
-
-
- #
- # Update objects that uses this one to update their _inherits fields
- #
- def _inherits_reload_src(self):
- for obj in self.pool.obj_pool.values():
- if self._name in obj._inherits:
- obj._inherits_reload()
-
- def _inherits_reload(self):
- res = {}
- for table in self._inherits:
- res.update(self.pool.get(table)._inherit_fields)
- for col in self.pool.get(table)._columns.keys():
- res[col]=(table, self._inherits[table], self.pool.get(table)._columns[col])
- for col in self.pool.get(table)._inherit_fields.keys():
- res[col]=(table, self._inherits[table], self.pool.get(table)._inherit_fields[col][2])
- self._inherit_fields=res
- self._inherits_reload_src()
-
- def fields_get(self, cr, user, fields=None, context=None):
- read_access= self.pool.get('ir.model.access').check(cr, user, self._name, 'write', raise_exception=False)
- return super(orm, self).fields_get(cr, user, fields, context, read_access)
-
- def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'):
- if not context:
- context={}
- self.pool.get('ir.model.access').check(cr, user, self._name, 'read')
- if not fields:
- fields = self._columns.keys() + self._inherit_fields.keys()
- select = ids
- if isinstance(ids, (int, long)):
- select = [ids]
- result = self._read_flat(cr, user, select, fields, context, load)
- for r in result:
- for key,v in r.items():
- if v == None:
- r[key]=False
- if isinstance(ids, (int, long)):
- return result[0]
- return result
-
- def _read_flat(self, cr, user, ids, fields, context=None, load='_classic_read'):
- if not context:
- context={}
- if not ids:
- return []
-
- if fields==None:
- fields = self._columns.keys()
-
- # construct a clause for the rules :
- d1, d2 = self.pool.get('ir.rule').domain_get(cr, user, self._name)
-
- # all inherited fields + all non inherited fields for which the attribute whose name is in load is True
- fields_pre = filter(lambda x: x in self._columns and getattr(self._columns[x],'_classic_write'), fields) + self._inherits.values()
-
- res = []
- if len(fields_pre) :
- fields_pre2 = map(lambda x: (x in ('create_date', 'write_date')) and ('date_trunc(\'second\', '+x+') as '+x) or '"'+x+'"', fields_pre)
- for i in range((len(ids) / ID_MAX) + ((len(ids) % ID_MAX) and 1 or 0)):
- sub_ids = ids[ID_MAX * i:ID_MAX * (i + 1)]
- if d1:
- cr.execute('SELECT %s FROM \"%s\" WHERE id IN (%s) AND %s ORDER BY %s' % \
- (','.join(fields_pre2 + ['id']), self._table,
- ','.join([str(x) for x in sub_ids]), d1,
- self._order),d2)
- if not cr.rowcount == len({}.fromkeys(sub_ids)):
- raise except_orm(_('AccessError'),
- _('You try to bypass an access rule (Document type: %s).') % self._description)
- else:
- cr.execute('SELECT %s FROM \"%s\" WHERE id IN (%s) ORDER BY %s' % \
- (','.join(fields_pre2 + ['id']), self._table,
- ','.join([str(x) for x in sub_ids]),
- self._order))
- res.extend(cr.dictfetchall())
- else:
- res = map(lambda x: {'id': x}, ids)
-
- for f in fields_pre:
- if self._columns[f].translate:
- ids = map(lambda x: x['id'], res)
- res_trans = self.pool.get('ir.translation')._get_ids(cr, user, self._name+','+f, 'model', context.get('lang', False) or 'en_US', ids)
- for r in res:
- r[f] = res_trans.get(r['id'], False) or r[f]
-
- for table in self._inherits:
- col = self._inherits[table]
- cols = intersect(self._inherit_fields.keys(), fields)
- if not cols:
- continue
- res2 = self.pool.get(table).read(cr, user, [x[col] for x in res], cols, context, load)
-
- res3 = {}
- for r in res2:
- res3[r['id']] = r
- del r['id']
-
- for record in res:
- record.update(res3[record[col]])
- if col not in fields:
- del record[col]
-
- # all fields which need to be post-processed by a simple function (symbol_get)
- fields_post = filter(lambda x: x in self._columns and self._columns[x]._symbol_get, fields)
- if fields_post:
- # maybe it would be faster to iterate on the fields then on res, so that we wouldn't need
- # 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])
- ids = map(lambda x: x['id'], res)
-
- # all non inherited fields for which the attribute whose name is in load is False
- fields_post = filter(lambda x: x in self._columns and not getattr(self._columns[x], load), fields)
- for f in fields_post:
- # get the value of that field for all records/ids
- res2 = self._columns[f].get(cr, self, ids, f, user, context=context, values=res)
- for record in res:
- record[f] = res2[record['id']]
-
- readonly = None
- for vals in res:
- for field in vals.copy():
- fobj = None
- if field in self._columns:
- fobj = self._columns[field]
-
- if not fobj:
- continue
- groups = fobj.read
- if groups:
- edit = False
- for group in groups:
- module = group.split(".")[0]
- grp = group.split(".")[1]
- cr.execute("select count(*) from res_groups_users_rel where gid in (select res_id from ir_model_data where name='%s' and module='%s' and model='%s') and uid=%s" % \
- (grp, module, 'res.groups', user))
- readonly = cr.fetchall()
- if readonly[0][0] >= 1:
- edit = True
- break
- elif readonly[0][0] == 0:
- edit = False
- else:
- edit = False
-
- if not edit:
- if type(vals[field]) == type([]):
- vals[field] = []
- elif type(vals[field]) == type(0.0):
- vals[field] = 0
- elif type(vals[field]) == type(''):
- vals[field] = '=No Permission='
- else:
- vals[field] = False
- return res
-
- def perm_read(self, cr, user, ids, context=None, details=True):
- if not context:
- context={}
- if not ids:
- return []
- fields = ''
- if self._log_access:
- fields =', u.create_uid, u.create_date, u.write_uid, u.write_date'
- if isinstance(ids, (int, long)):
- ids_str = str(ids)
- else:
- ids_str = string.join(map(lambda x:str(x), ids),',')
- cr.execute('select u.id'+fields+' from "'+self._table+'" u where u.id in ('+ids_str+')')
- res = cr.dictfetchall()
- for r in res:
- for key in r:
- r[key] = r[key] or False
- if key in ('write_uid','create_uid','uid') and details:
- if r[key]:
- r[key] = self.pool.get('res.users').name_get(cr, user, [r[key]])[0]
- if isinstance(ids, (int, long)):
- return res[ids]
- return res
-
- def unlink(self, cr, uid, ids, context=None):
- if not context:
- context={}
- if not ids:
- return True
- if isinstance(ids, (int, long)):
- 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)
-
- delta= context.get('read_delta',False)
- if delta and self._log_access:
- for i in range((len(ids) / ID_MAX) + ((len(ids) % ID_MAX) and 1 or 0)):
- sub_ids = ids[ID_MAX * i:ID_MAX * (i + 1)]
- cr.execute("select (now() - min(write_date)) <= '%s'::interval " \
- "from \"%s\" where id in (%s)" %
- (delta, self._table, ",".join(map(str, sub_ids))) )
- res= cr.fetchone()
- if res and res[0]:
- raise except_orm(_('ConcurrencyException'),
- _('This record was modified in the meanwhile'))
-
- self.pool.get('ir.model.access').check(cr, uid, self._name, 'unlink')
-
- wf_service = netsvc.LocalService("workflow")
- for id in ids:
- wf_service.trg_delete(uid, self._name, id, cr)
-
- #cr.execute('select * from '+self._table+' where id in ('+str_d+')', ids)
- #res = cr.dictfetchall()
- #for key in self._inherits:
- # ids2 = [x[self._inherits[key]] for x in res]
- # self.pool.get(key).unlink(cr, uid, ids2)
-
- d1, d2 = self.pool.get('ir.rule').domain_get(cr, uid, self._name)
- if d1:
- d1 = ' AND '+d1
-
- for i in range((len(ids) / ID_MAX) + ((len(ids) % ID_MAX) and 1 or 0)):
- sub_ids = ids[ID_MAX * i:ID_MAX * (i + 1)]
- str_d = string.join(('%d',)*len(sub_ids),',')
- if d1:
- cr.execute('SELECT id FROM "'+self._table+'" ' \
- 'WHERE id IN ('+str_d+')'+d1, sub_ids+d2)
- if not cr.rowcount == len({}.fromkeys(ids)):
- raise except_orm(_('AccessError'),
- _('You try to bypass an access rule (Document type: %s).') % \
- self._description)
-
- if d1:
- cr.execute('delete from "'+self._table+'" ' \
- 'where id in ('+str_d+')'+d1, sub_ids+d2)
- 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)
-
- return True
-
- #
- # TODO: Validate
- #
- def write(self, cr, user, ids, vals, context=None):
- readonly = None
- for field in vals.copy():
- fobj = None
- if field in self._columns:
- fobj = self._columns[field]
- else:
- fobj = self._inherit_fields[field][2]
- if not fobj:
- continue
- groups = fobj.write
-
- if groups:
- edit = False
- for group in groups:
- module = group.split(".")[0]
- grp = group.split(".")[1]
- cr.execute("select count(*) from res_groups_users_rel where gid in (select res_id from ir_model_data where name='%s' and module='%s' and model='%s') and uid=%s" % \
- (grp, module, 'res.groups', user))
- readonly = cr.fetchall()
- if readonly[0][0] >= 1:
- edit = True
- break
- elif readonly[0][0] == 0:
- edit = False
- else:
- edit = False
-
- if not edit:
- vals.pop(field)
-
- if not context:
- context={}
- if not ids:
- return True
- if isinstance(ids, (int, long)):
- ids = [ids]
- delta= context.get('read_delta',False)
- if delta and self._log_access:
- for i in range((len(ids) / ID_MAX) + ((len(ids) % ID_MAX) and 1 or 0)):
- sub_ids = ids[ID_MAX * i:ID_MAX * (i + 1)]
- cr.execute("select (now() - min(write_date)) <= '%s'::interval " \
- "from %s where id in (%s)" %
- (delta,self._table, ",".join(map(str, sub_ids))))
- res= cr.fetchone()
- if res and res[0]:
- for field in vals:
- if field in self._columns and self._columns[field]._classic_write:
- raise except_orm(_('ConcurrencyException'),
- _('This record was modified in the meanwhile'))
-
- self.pool.get('ir.model.access').check(cr, user, self._name, 'write')
-
- #for v in self._inherits.values():
- # assert v not in vals, (v, vals)
- upd0=[]
- upd1=[]
- upd_todo=[]
- updend=[]
- direct = []
- totranslate = context.get('lang', False) and (context['lang'] != 'en_US')
- for field in vals:
- if field in self._columns:
- if self._columns[field]._classic_write:
- if (not totranslate) or not self._columns[field].translate:
- upd0.append('"'+field+'"='+self._columns[field]._symbol_set[0])
- upd1.append(self._columns[field]._symbol_set[1](vals[field]))
- direct.append(field)
- else:
- upd_todo.append(field)
- else:
- updend.append(field)
- if field in self._columns \
- and hasattr(self._columns[field], 'selection') \
- and vals[field]:
- if self._columns[field]._type == 'reference':
- val = vals[field].split(',')[0]
- else:
- val = vals[field]
- if isinstance(self._columns[field].selection, (tuple, list)):
- if val not in dict(self._columns[field].selection):
- raise except_orm(_('ValidateError'),
- _('The value "%s" for the field "%s" is not in the selection') \
- % (vals[field], field))
- else:
- if val not in dict(self._columns[field].selection(
- self, cr, user, context=context)):
- raise except_orm(_('ValidateError'),
- _('The value "%s" for the field "%s" is not in the selection') \
- % (vals[field], field))
-
- if self._log_access:
- upd0.append('write_uid=%d')
- upd0.append('write_date=now()')
- upd1.append(user)
-
- if len(upd0):
-
- d1, d2 = self.pool.get('ir.rule').domain_get(cr, user, self._name)
- if d1:
- d1 = ' and '+d1
-
- for i in range((len(ids) / ID_MAX) + ((len(ids) % ID_MAX) and 1 or 0)):
- sub_ids = ids[ID_MAX * i:ID_MAX * (i + 1)]
- ids_str = string.join(map(str, sub_ids),',')
- if d1:
- cr.execute('SELECT id FROM "'+self._table+'" ' \
- 'WHERE id IN ('+ids_str+')'+d1, d2)
- if not cr.rowcount == len({}.fromkeys(sub_ids)):
- raise except_orm(_('AccessError'),
- _('You try to bypass an access rule (Document type: %s).') % \
- self._description)
- else:
- cr.execute('SELECT id FROM "'+self._table+'" WHERE id IN ('+ids_str+')')
- if not cr.rowcount == len({}.fromkeys(sub_ids)):
- raise except_orm(_('AccessError'),
- _('You try to write on an record that doesn\'t exist ' \
- '(Document type: %s).') % self._description)
- if d1:
- cr.execute('update "'+self._table+'" set '+string.join(upd0,',')+' ' \
- 'where id in ('+ids_str+')'+d1, upd1+ d2)
- else:
- cr.execute('update "'+self._table+'" set '+string.join(upd0,',')+' ' \
- 'where id in ('+ids_str+')', upd1)
-
- if totranslate:
- for f in direct:
- if self._columns[f].translate:
- self.pool.get('ir.translation')._set_ids(cr, user, self._name+','+f,'model', context['lang'], ids,vals[f])
-
- # call the 'set' method of fields which are not classic_write
- upd_todo.sort(lambda x,y: self._columns[x].priority-self._columns[y].priority)
- for field in upd_todo:
- for id in ids:
- self._columns[field].set(cr, self, id, field, vals[field], user, context=context)
-
- for table in self._inherits:
- col = self._inherits[table]
- nids = []
- for i in range((len(ids) / ID_MAX) + ((len(ids) % ID_MAX) and 1 or 0)):
- sub_ids = ids[ID_MAX * i:ID_MAX * (i + 1)]
- ids_str = string.join(map(str, sub_ids),',')
- cr.execute('select distinct "'+col+'" from "'+self._table+'" ' \
- 'where id in ('+ids_str+')', upd1)
- nids.extend([x[0] for x in cr.fetchall()])
-
- v = {}
- for val in updend:
- if self._inherit_fields[val][0]==table:
- v[val]=vals[val]
- self.pool.get(table).write(cr, user, nids, v, context)
-
- self._validate(cr, user, ids, context)
-
- if context.has_key('read_delta'):
- del context['read_delta']
-
- 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)
-
- return True
-
- #
- # TODO: Should set perm to user.xxx
- #
- def create(self, cr, user, vals, context=None):
- """ create(cr, user, vals, context) -> int
- cr = database cursor
- user = user id
- vals = dictionary of the form {'field_name':field_value, ...}
- """
- if not context:
- context={}
- self.pool.get('ir.model.access').check(cr, user, self._name, 'create')
-
- default = []
-
- avoid_table = []
- for (t,c) in self._inherits.items():
- if c in vals:
- avoid_table.append(t)
- for f in self._columns.keys(): # + self._inherit_fields.keys():
- if not f in vals:
- default.append(f)
- for f in self._inherit_fields.keys():
- if (not f in vals) and (not self._inherit_fields[f][0] in avoid_table):
- default.append(f)
-
- if len(default):
- vals.update(self.default_get(cr, user, default, context))
-
- tocreate = {}
- for v in self._inherits:
- if self._inherits[v] not in vals:
- tocreate[v] = {}
-
- (upd0, upd1, upd2) = ('', '', [])
- upd_todo = []
-
- for v in vals.keys():
- if v in self._inherit_fields:
- (table,col,col_detail) = self._inherit_fields[v]
- tocreate[table][v] = vals[v]
- del vals[v]
-
- cr.execute("SELECT nextval('"+self._sequence+"')")
- id_new = cr.fetchone()[0]
- for table in tocreate:
- id = self.pool.get(table).create(cr, user, tocreate[table])
- upd0 += ','+self._inherits[table]
- upd1 += ',%d'
- upd2.append(id)
-
- for field in vals:
- if self._columns[field]._classic_write:
- upd0=upd0+',"'+field+'"'
- upd1=upd1+','+self._columns[field]._symbol_set[0]
- upd2.append(self._columns[field]._symbol_set[1](vals[field]))
- else:
- upd_todo.append(field)
- if field in self._columns \
- and hasattr(self._columns[field], 'selection') \
- and vals[field]:
- if self._columns[field]._type == 'reference':
- val = vals[field].split(',')[0]
- else:
- val = vals[field]
- if isinstance(self._columns[field].selection, (tuple, list)):
- if val not in dict(self._columns[field].selection):
- raise except_orm(_('ValidateError'),
- _('The value "%s" for the field "%s" is not in the selection') \
- % (vals[field], field))
- else:
- if val not in dict(self._columns[field].selection(
- self, cr, user, context=context)):
- raise except_orm(_('ValidateError'),
- _('The value "%s" for the field "%s" is not in the selection') \
- % (vals[field], field))
- if self._log_access:
- upd0 += ',create_uid,create_date'
- upd1 += ',%d,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)
- for field in upd_todo:
- self._columns[field].set(cr, self, id_new, field, vals[field], user, context)
-
- self._validate(cr, user, [id_new], context)
-
- 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)
-
- 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])
- return parent_id
-
- def _store_set_values(self,cr,uid,ids,tuple_fn,parent_id,context):
- name = tuple_fn[1]
- table = tuple_fn[0]
- 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'):
- value = res[field][0]
- 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)
- return True
-
- #
- # TODO: Validate
- #
- def perm_write(self, cr, user, ids, fields, context=None):
- raise _('This method does not exist anymore')
-
- # TODO: ameliorer avec NULL
- def _where_calc(self, cr, user, args, active_test=True, context=None):
- if not context:
- context={}
- args = args[:]
- # if the object has a field named 'active', filter out all inactive
- # records unless they were explicitely asked for
- if 'active' in self._columns and (active_test and context.get('active_test', True)):
- i = 0
- active_found = False
- while i<len(args):
- if args[i][0]=='active':
- active_found = True
- i += 1
- if not active_found:
- args.append(('active', '=', 1))
-
- i = 0
- tables=['"'+self._table+'"']
- joins=[]
- while i<len(args):
- table=self
- assert args[i][1] in ('like','!=','ilike','=like', 'not like', 'not ilike', 'not in','inselect','child_of','in','=','<>','<','>','>=','<='), _('Error ! Bad clause operand "%s".') % (args[i][1],)
- if args[i][1] == 'inselect':
- raise except_orm(_('ValidateError'),
- _("The clause 'inselect' can not be used outside the orm!"))
- if args[i][0] in self._inherit_fields:
- table=self.pool.get(self._inherit_fields[args[i][0]][0])
- if ('"'+table._table+'"' not in tables):
- tables.append('"'+table._table+'"')
- joins.append(('id', 'join', '%s.%s' % (self._table, self._inherits[table._name]), table))
- fargs = args[i][0].split('.', 1)
- field = table._columns.get(fargs[0],False)
- if not field:
- if args[i][0] == 'id' and args[i][1] == 'child_of':
- ids2 = args[i][2]
- def _rec_get(ids, table, parent):
- if not ids:
- return []
- ids2 = table.search(cr, user, [(parent, 'in', ids)], context=context)
- return ids + _rec_get(ids2, table, parent)
- args[i] = (args[i][0], 'in', ids2 + _rec_get(ids2, table, table._parent_name), table)
- i+=1
- continue
- if len(fargs) > 1:
- if field._type == 'many2one':
- args[i] = (fargs[0], 'in', self.pool.get(field._obj).search(cr, user, [(fargs[1], args[i][1], args[i][2])], context=context))
- i+=1
- continue
- else:
- i+=1
- continue
- if field._properties:
- arg = [args.pop(i)]
- j = i
- while j<len(args):
- if args[j][0]==arg[0][0]:
- arg.append(args.pop(j))
- else:
- j+=1
- if field._fnct_search:
- args.extend(field.search(cr, user, self, arg[0][0], arg))
- if field.store:
- args.extend(arg)
- i+=1
- elif field._type=='one2many':
- field_obj = self.pool.get(field._obj)
-
- if isinstance(args[i][2], basestring):
- # get the ids of the records of the "distant" resource
- ids2 = [x[0] for x in field_obj.name_search(cr, user, args[i][2], [], args[i][1])]
- else:
- ids2 = args[i][2]
- if not ids2:
- args[i] = ('id','=','0')
- else:
- ids3 = []
- for j in range((len(ids2) / ID_MAX) + (len(ids2) % ID_MAX)):
- sub_ids2 = ids2[ID_MAX * j:ID_MAX * (j + 1)]
- if sub_ids2:
- cr.execute('SELECT "'+field._fields_id+'" ' \
- 'FROM "'+field_obj._table+'" ' \
- 'WHERE id in ('+','.join(map(str,sub_ids2))+')')
- ids3.extend([x[0] for x in cr.fetchall()])
-
- args[i] = ('id', 'in', ids3)
- i+=1
-
- elif field._type=='many2many':
- #FIXME
- if args[i][1]=='child_of':
- if isinstance(args[i][2], basestring):
- ids2 = [x[0] for x in self.pool.get(field._obj).name_search(cr, user, args[i][2], [], 'like')]
- else:
- ids2 = args[i][2]
- def _rec_get(ids, table, parent):
- if not ids:
- return []
- ids2 = table.search(cr, user, [(parent, 'in', ids)], context=context)
- return ids + _rec_get(ids2, table, parent)
- def _rec_convert(ids):
- if self.pool.get(field._obj)==self:
- return ids
- if not len(ids): return []
- cr.execute('select "'+field._id1+'" from "'+field._rel+'" where "'+field._id2+'" in ('+','.join(map(str,ids))+')')
- ids = [x[0] for x in cr.fetchall()]
- return ids
- args[i] = ('id','in',_rec_convert(ids2+_rec_get(ids2, self.pool.get(field._obj), table._parent_name)))
- else:
- if isinstance(args[i][2], basestring):
- res_ids = [x[0] for x in self.pool.get(field._obj).name_search(cr, user, args[i][2], [], args[i][1])]
- else:
- res_ids = args[i][2]
- if not len(res_ids):
- args[i] = ('id', 'in', [0])
- else:
- cr.execute('select "'+field._id1+'" from "'+field._rel+'" where "'+field._id2+'" in ('+','.join(map(str, res_ids))+')')
- args[i] = ('id', 'in', map(lambda x: x[0], cr.fetchall()))
- i+=1
-
- elif field._type=='many2one':
- if args[i][1]=='child_of':
- if isinstance(args[i][2], basestring):
- ids2 = [x[0] for x in self.pool.get(field._obj).name_search(cr, user, args[i][2], [], 'like')]
- else:
- ids2 = args[i][2]
- def _rec_get(ids, table, parent):
- if not ids:
- return []
- ids2 = table.search(cr, user, [(parent, 'in', ids)], context=context)
- return ids + _rec_get(ids2, table, parent)
- if field._obj <> table._name:
- args[i] = (args[i][0],'in',ids2+_rec_get(ids2, self.pool.get(field._obj), table._parent_name), table)
- else:
- args[i] = ('id','in',ids2+_rec_get(ids2, table, args[i][0]), table)
- else:
- if isinstance(args[i][2], basestring):
- res_ids = self.pool.get(field._obj).name_search(cr, user, args[i][2], [], args[i][1])
- args[i] = (args[i][0],'in',map(lambda x: x[0], res_ids), table)
- else:
- args[i] += (table,)
- i+=1
- else:
- if field.translate:
- if args[i][1] in ('like', 'ilike', 'not like', 'not ilike'):
- args[i] = (args[i][0], args[i][1], '%%%s%%' % args[i][2])
- query1 = '(SELECT res_id FROM ir_translation ' \
- 'WHERE name = %s AND lang = %s ' \
- 'AND type = %s ' \
- 'AND VALUE ' + args[i][1] + ' %s)'
- query2 = [table._name + ',' + args[i][0],
- context.get('lang', False) or 'en_US',
- 'model',
- args[i][2]]
- query1 += ' UNION '
- query1 += '(SELECT id FROM "' + table._table + '" ' \
- 'WHERE "' + args[i][0] + '" ' + args[i][1] + ' %s)'
- query2 += [args[i][2]]
- args[i] = ('id', 'inselect', (query1, query2), table)
- else:
- args[i] += (table,)
- i+=1
- args.extend(joins)
-
- qu1, qu2 = [], []
- for x in args:
- table=self
- if len(x) > 3:
- table=x[3]
- if x[1] == 'inselect':
- qu1.append('(%s.%s in (%s))' % (table._table, x[0], x[2][0]))
- qu2 += x[2][1]
- elif x[1]=='not in':
- if len(x[2])>0:
- todel = []
- for xitem in range(len(x[2])):
- if x[2][xitem]==False and isinstance(x[2][xitem],bool):
- todel.append(xitem)
- for xitem in todel[::-1]:
- del x[2][xitem]
- if x[0]=='id':
- qu1.append('(%s.id not in (%s))' % (table._table, ','.join(['%d'] * len(x[2])),))
- else:
- qu1.append('(%s.%s not in (%s))' % (table._table, x[0], ','.join([table._columns[x[0]]._symbol_set[0]]*len(x[2]))))
- if todel:
- qu1[-1] = '('+qu1[-1]+' or '+x[0]+' is null)'
- qu2+=x[2]
- else:
- qu1.append(' (1=0)')
- elif x[1] != 'in':
+ 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 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 self._defaults.has_key(k):
+ 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))
+ cr.commit()
+ # add the NOT NULL constraint
+ try:
+ 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.commit()
+ cr.execute("SELECT indexname FROM pg_indexes WHERE indexname = '%s_%s_index' and tablename = '%s'" % (self._table, k, 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.commit()
+ if res and not f.select:
+ 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'))
+ res = cr.dictfetchall()
+ if res:
+ confdeltype = {
+ 'RESTRICT': 'r',
+ 'NO ACTION': 'a',
+ 'CASCADE': 'c',
+ 'SET NULL': 'n',
+ 'SET DEFAULT': 'd',
+ }
+ if res[0]['confdeltype'] != confdeltype.get(f.ondelete.upper(), 'a'):
+ cr.execute('ALTER TABLE "' + self._table + '" DROP CONSTRAINT "' + res[0]['conname'] + '"')
+ cr.execute('ALTER TABLE "' + self._table + '" ADD FOREIGN KEY ("' + k + '") REFERENCES "' + ref + '" ON DELETE ' + f.ondelete)
+ cr.commit()
+ else:
+ print "ERROR"
+ else:
+ 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))
+ if not cr.dictfetchall():
+ try:
+ 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,))
+
+ if create:
+ if hasattr(self,"_sql"):
+ for line in self._sql.split(';'):
+ line2 = line.replace('\n','').strip()
+ if line2:
+ cr.execute(line2)
+ cr.commit()
+
+ def __init__(self, cr):
+ super(orm, self).__init__(cr)
+ 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 (key,_,msg) in self._sql_constraints:
+ self.pool._sql_error[self._table+'_'+key] = msg
+
+ # Load manual fields
+
+ cr.execute("SELECT id FROM ir_model_fields WHERE name=%s AND model=%s", ('state','ir.model.fields'))
+ if cr.fetchone():
+ cr.execute('SELECT * FROM ir_model_fields WHERE model=%s AND state=%s', (self._name,'manual'))
+ for field in cr.dictfetchall():
+ if field['name'] in self._columns:
+ continue
+ attrs = {
+ 'string': field['field_description'],
+ 'required': bool(field['required']),
+ 'readonly': bool(field['readonly']),
+ 'domain': field['domain'] or None,
+ 'size': field['size'],
+ 'ondelete': field['on_delete'],
+ 'translate': (field['translate']),
+ #'select': int(field['select_level'])
+ }
+ #if field['relation']:
+ # attrs['relation'] = field['relation']
+ if field['ttype'] == 'selection':
+ self._columns[field['name']] = getattr(fields, field['ttype'])(eval(field['selection']), **attrs)
+ elif field['ttype'] == 'many2one':
+ self._columns[field['name']] = getattr(fields, field['ttype'])(field['relation'], **attrs)
+ else:
+ self._columns[field['name']] = getattr(fields, field['ttype'])(**attrs)
+
+ self._inherits_reload()
+ if not self._sequence:
+ self._sequence = self._table+'_id_seq'
+ for k in self._defaults:
+ assert (k in self._columns) or (k in self._inherit_fields), 'Default function defined in %s but field %s does not exist !' % (self._name, k,)
+ for f in self._columns:
+ self._columns[f].restart()
+
+ def default_get(self, cr, uid, fields_list, context=None):
+ if not context:
+ context={}
+ value = {}
+ # get the default values for the inherited fields
+ for t in self._inherits.keys():
+ value.update(self.pool.get(t).default_get(cr, uid, fields_list,
+ context))
+
+ # get the default values defined in the object
+ for f in fields_list:
+ if f in self._defaults:
+ value[f] = self._defaults[f](self, cr, uid, context)
+ fld_def = ((f in self._columns) and self._columns[f]) \
+ or ((f in self._inherit_fields ) and self._inherit_fields[f][2]) \
+ or False
+ if isinstance(fld_def, fields.property):
+ property_obj = self.pool.get('ir.property')
+ definition_id = fld_def._field_get(cr, uid, self._name, f)
+ nid = property_obj.search(cr, uid, [('fields_id', '=',
+ definition_id), ('res_id', '=', False)])
+ if nid:
+ prop_value = property_obj.browse(cr, uid, nid[0],
+ context=context).value
+ value[f] = (prop_value and int(prop_value.split(',')[1])) \
+ or False
+
+ # get the default values set by the user and override the default
+ # values defined in the object
+ ir_values_obj = self.pool.get('ir.values')
+ res = ir_values_obj.get(cr, uid, 'default', False, [self._name])
+ for id, field, field_value in res:
+ if field in fields_list:
+ fld_def = (field in self._columns) and self._columns[field] or self._inherit_fields[field][2]
+ if fld_def._type in ('many2one', 'one2one'):
+ obj = self.pool.get(fld_def._obj)
+ if not obj.search(cr, uid, [('id', '=', field_value)]):
+ continue
+ if fld_def._type in ('many2many'):
+ obj = self.pool.get(fld_def._obj)
+ field_value2 = []
+ for i in range(len(field_value)):
+ if not obj.search(cr, uid, [('id', '=',
+ field_value[i])]):
+ continue
+ field_value2.append(field_value[i])
+ field_value = field_value2
+ if fld_def._type in ('one2many'):
+ obj = self.pool.get(fld_def._obj)
+ field_value2 = []
+ for i in range(len(field_value)):
+ field_value2.append({})
+ for field2 in field_value[i]:
+ if obj._columns[field2]._type in ('many2one', 'one2one'):
+ obj2 = self.pool.get(obj._columns[field2]._obj)
+ if not obj2.search(cr, uid,
+ [('id', '=', field_value[i][field2])]):
+ continue
+ # TODO add test for many2many and one2many
+ field_value2[i][field2] = field_value[i][field2]
+ field_value = field_value2
+ value[field] = field_value
+ return value
+
+
+ #
+ # Update objects that uses this one to update their _inherits fields
+ #
+ def _inherits_reload_src(self):
+ for obj in self.pool.obj_pool.values():
+ if self._name in obj._inherits:
+ obj._inherits_reload()
+
+ def _inherits_reload(self):
+ res = {}
+ for table in self._inherits:
+ res.update(self.pool.get(table)._inherit_fields)
+ for col in self.pool.get(table)._columns.keys():
+ res[col]=(table, self._inherits[table], self.pool.get(table)._columns[col])
+ for col in self.pool.get(table)._inherit_fields.keys():
+ res[col]=(table, self._inherits[table], self.pool.get(table)._inherit_fields[col][2])
+ self._inherit_fields=res
+ self._inherits_reload_src()
+
+ def fields_get(self, cr, user, fields=None, context=None):
+ read_access= self.pool.get('ir.model.access').check(cr, user, self._name, 'write', raise_exception=False)
+ return super(orm, self).fields_get(cr, user, fields, context, read_access)
+
+ def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'):
+ if not context:
+ context={}
+ self.pool.get('ir.model.access').check(cr, user, self._name, 'read')
+ if not fields:
+ fields = self._columns.keys() + self._inherit_fields.keys()
+ select = ids
+ if isinstance(ids, (int, long)):
+ select = [ids]
+ result = self._read_flat(cr, user, select, fields, context, load)
+ for r in result:
+ for key,v in r.items():
+ if v == None:
+ r[key]=False
+ if isinstance(ids, (int, long)):
+ return result[0]
+ return result
+
+ def _read_flat(self, cr, user, ids, fields, context=None, load='_classic_read'):
+ if not context:
+ context={}
+ if not ids:
+ return []
+
+ if fields==None:
+ fields = self._columns.keys()
+
+ # construct a clause for the rules :
+ d1, d2 = self.pool.get('ir.rule').domain_get(cr, user, self._name)
+
+ # all inherited fields + all non inherited fields for which the attribute whose name is in load is True
+ fields_pre = filter(lambda x: x in self._columns and getattr(self._columns[x],'_classic_write'), fields) + self._inherits.values()
+
+ res = []
+ if len(fields_pre) :
+ fields_pre2 = map(lambda x: (x in ('create_date', 'write_date')) and ('date_trunc(\'second\', '+x+') as '+x) or '"'+x+'"', fields_pre)
+ for i in range((len(ids) / ID_MAX) + ((len(ids) % ID_MAX) and 1 or 0)):
+ sub_ids = ids[ID_MAX * i:ID_MAX * (i + 1)]
+ if d1:
+ cr.execute('SELECT %s FROM \"%s\" WHERE id IN (%s) AND %s ORDER BY %s' % \
+ (','.join(fields_pre2 + ['id']), self._table,
+ ','.join([str(x) for x in sub_ids]), d1,
+ self._order),d2)
+ if not cr.rowcount == len({}.fromkeys(sub_ids)):
+ raise except_orm(_('AccessError'),
+ _('You try to bypass an access rule (Document type: %s).') % self._description)
+ else:
+ cr.execute('SELECT %s FROM \"%s\" WHERE id IN (%s) ORDER BY %s' % \
+ (','.join(fields_pre2 + ['id']), self._table,
+ ','.join([str(x) for x in sub_ids]),
+ self._order))
+ res.extend(cr.dictfetchall())
+ else:
+ res = map(lambda x: {'id': x}, ids)
+
+ for f in fields_pre:
+ if self._columns[f].translate:
+ ids = map(lambda x: x['id'], res)
+ res_trans = self.pool.get('ir.translation')._get_ids(cr, user, self._name+','+f, 'model', context.get('lang', False) or 'en_US', ids)
+ for r in res:
+ r[f] = res_trans.get(r['id'], False) or r[f]
+
+ for table in self._inherits:
+ col = self._inherits[table]
+ cols = intersect(self._inherit_fields.keys(), fields)
+ if not cols:
+ continue
+ res2 = self.pool.get(table).read(cr, user, [x[col] for x in res], cols, context, load)
+
+ res3 = {}
+ for r in res2:
+ res3[r['id']] = r
+ del r['id']
+
+ for record in res:
+ record.update(res3[record[col]])
+ if col not in fields:
+ del record[col]
+
+ # all fields which need to be post-processed by a simple function (symbol_get)
+ fields_post = filter(lambda x: x in self._columns and self._columns[x]._symbol_get, fields)
+ if fields_post:
+ # maybe it would be faster to iterate on the fields then on res, so that we wouldn't need
+ # 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])
+ ids = map(lambda x: x['id'], res)
+
+ # all non inherited fields for which the attribute whose name is in load is False
+ fields_post = filter(lambda x: x in self._columns and not getattr(self._columns[x], load), fields)
+ for f in fields_post:
+ # get the value of that field for all records/ids
+ res2 = self._columns[f].get(cr, self, ids, f, user, context=context, values=res)
+ for record in res:
+ record[f] = res2[record['id']]
+
+ readonly = None
+ for vals in res:
+ for field in vals.copy():
+ fobj = None
+ if field in self._columns:
+ fobj = self._columns[field]
+
+ if not fobj:
+ continue
+ groups = fobj.read
+ if groups:
+ edit = False
+ for group in groups:
+ module = group.split(".")[0]
+ grp = group.split(".")[1]
+ cr.execute("select count(*) from res_groups_users_rel where gid in (select res_id from ir_model_data where name='%s' and module='%s' and model='%s') and uid=%s" % \
+ (grp, module, 'res.groups', user))
+ readonly = cr.fetchall()
+ if readonly[0][0] >= 1:
+ edit = True
+ break
+ elif readonly[0][0] == 0:
+ edit = False
+ else:
+ edit = False
+
+ if not edit:
+ if type(vals[field]) == type([]):
+ vals[field] = []
+ elif type(vals[field]) == type(0.0):
+ vals[field] = 0
+ elif type(vals[field]) == type(''):
+ vals[field] = '=No Permission='
+ else:
+ vals[field] = False
+ return res
+
+ def perm_read(self, cr, user, ids, context=None, details=True):
+ if not context:
+ context={}
+ if not ids:
+ return []
+ fields = ''
+ if self._log_access:
+ fields =', u.create_uid, u.create_date, u.write_uid, u.write_date'
+ if isinstance(ids, (int, long)):
+ ids_str = str(ids)
+ else:
+ ids_str = string.join(map(lambda x:str(x), ids),',')
+ cr.execute('select u.id'+fields+' from "'+self._table+'" u where u.id in ('+ids_str+')')
+ res = cr.dictfetchall()
+ for r in res:
+ for key in r:
+ r[key] = r[key] or False
+ if key in ('write_uid','create_uid','uid') and details:
+ if r[key]:
+ r[key] = self.pool.get('res.users').name_get(cr, user, [r[key]])[0]
+ if isinstance(ids, (int, long)):
+ return res[ids]
+ return res
+
+ def unlink(self, cr, uid, ids, context=None):
+ if not context:
+ context={}
+ if not ids:
+ return True
+ if isinstance(ids, (int, long)):
+ 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)
+
+ delta= context.get('read_delta',False)
+ if delta and self._log_access:
+ for i in range((len(ids) / ID_MAX) + ((len(ids) % ID_MAX) and 1 or 0)):
+ sub_ids = ids[ID_MAX * i:ID_MAX * (i + 1)]
+ cr.execute("select (now() - min(write_date)) <= '%s'::interval " \
+ "from \"%s\" where id in (%s)" %
+ (delta, self._table, ",".join(map(str, sub_ids))) )
+ res= cr.fetchone()
+ if res and res[0]:
+ raise except_orm(_('ConcurrencyException'),
+ _('This record was modified in the meanwhile'))
+
+ self.pool.get('ir.model.access').check(cr, uid, self._name, 'unlink')
+
+ wf_service = netsvc.LocalService("workflow")
+ for id in ids:
+ wf_service.trg_delete(uid, self._name, id, cr)
+
+ #cr.execute('select * from '+self._table+' where id in ('+str_d+')', ids)
+ #res = cr.dictfetchall()
+ #for key in self._inherits:
+ # ids2 = [x[self._inherits[key]] for x in res]
+ # self.pool.get(key).unlink(cr, uid, ids2)
+
+ d1, d2 = self.pool.get('ir.rule').domain_get(cr, uid, self._name)
+ if d1:
+ d1 = ' AND '+d1
+
+ for i in range((len(ids) / ID_MAX) + ((len(ids) % ID_MAX) and 1 or 0)):
+ sub_ids = ids[ID_MAX * i:ID_MAX * (i + 1)]
+ str_d = string.join(('%d',)*len(sub_ids),',')
+ if d1:
+ cr.execute('SELECT id FROM "'+self._table+'" ' \
+ 'WHERE id IN ('+str_d+')'+d1, sub_ids+d2)
+ if not cr.rowcount == len({}.fromkeys(ids)):
+ raise except_orm(_('AccessError'),
+ _('You try to bypass an access rule (Document type: %s).') % \
+ self._description)
+
+ if d1:
+ cr.execute('delete from "'+self._table+'" ' \
+ 'where id in ('+str_d+')'+d1, sub_ids+d2)
+ 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)
+
+ return True
+
+ #
+ # TODO: Validate
+ #
+ def write(self, cr, user, ids, vals, context=None):
+ readonly = None
+ for field in vals.copy():
+ fobj = None
+ if field in self._columns:
+ fobj = self._columns[field]
+ else:
+ fobj = self._inherit_fields[field][2]
+ if not fobj:
+ continue
+ groups = fobj.write
+
+ if groups:
+ edit = False
+ for group in groups:
+ module = group.split(".")[0]
+ grp = group.split(".")[1]
+ cr.execute("select count(*) from res_groups_users_rel where gid in (select res_id from ir_model_data where name='%s' and module='%s' and model='%s') and uid=%s" % \
+ (grp, module, 'res.groups', user))
+ readonly = cr.fetchall()
+ if readonly[0][0] >= 1:
+ edit = True
+ break
+ elif readonly[0][0] == 0:
+ edit = False
+ else:
+ edit = False
+
+ if not edit:
+ vals.pop(field)
+
+ if not context:
+ context={}
+ if not ids:
+ return True
+ if isinstance(ids, (int, long)):
+ ids = [ids]
+ delta= context.get('read_delta',False)
+ if delta and self._log_access:
+ for i in range((len(ids) / ID_MAX) + ((len(ids) % ID_MAX) and 1 or 0)):
+ sub_ids = ids[ID_MAX * i:ID_MAX * (i + 1)]
+ cr.execute("select (now() - min(write_date)) <= '%s'::interval " \
+ "from %s where id in (%s)" %
+ (delta,self._table, ",".join(map(str, sub_ids))))
+ res= cr.fetchone()
+ if res and res[0]:
+ for field in vals:
+ if field in self._columns and self._columns[field]._classic_write:
+ raise except_orm(_('ConcurrencyException'),
+ _('This record was modified in the meanwhile'))
+
+ self.pool.get('ir.model.access').check(cr, user, self._name, 'write')
+
+ #for v in self._inherits.values():
+ # assert v not in vals, (v, vals)
+ upd0=[]
+ upd1=[]
+ upd_todo=[]
+ updend=[]
+ direct = []
+ totranslate = context.get('lang', False) and (context['lang'] != 'en_US')
+ for field in vals:
+ if field in self._columns:
+ if self._columns[field]._classic_write:
+ if (not totranslate) or not self._columns[field].translate:
+ upd0.append('"'+field+'"='+self._columns[field]._symbol_set[0])
+ upd1.append(self._columns[field]._symbol_set[1](vals[field]))
+ direct.append(field)
+ else:
+ upd_todo.append(field)
+ else:
+ updend.append(field)
+ if field in self._columns \
+ and hasattr(self._columns[field], 'selection') \
+ and vals[field]:
+ if self._columns[field]._type == 'reference':
+ val = vals[field].split(',')[0]
+ else:
+ val = vals[field]
+ if isinstance(self._columns[field].selection, (tuple, list)):
+ if val not in dict(self._columns[field].selection):
+ raise except_orm(_('ValidateError'),
+ _('The value "%s" for the field "%s" is not in the selection') \
+ % (vals[field], field))
+ else:
+ if val not in dict(self._columns[field].selection(
+ self, cr, user, context=context)):
+ raise except_orm(_('ValidateError'),
+ _('The value "%s" for the field "%s" is not in the selection') \
+ % (vals[field], field))
+
+ if self._log_access:
+ upd0.append('write_uid=%d')
+ upd0.append('write_date=now()')
+ upd1.append(user)
+
+ if len(upd0):
+
+ d1, d2 = self.pool.get('ir.rule').domain_get(cr, user, self._name)
+ if d1:
+ d1 = ' and '+d1
+
+ for i in range((len(ids) / ID_MAX) + ((len(ids) % ID_MAX) and 1 or 0)):
+ sub_ids = ids[ID_MAX * i:ID_MAX * (i + 1)]
+ ids_str = string.join(map(str, sub_ids),',')
+ if d1:
+ cr.execute('SELECT id FROM "'+self._table+'" ' \
+ 'WHERE id IN ('+ids_str+')'+d1, d2)
+ if not cr.rowcount == len({}.fromkeys(sub_ids)):
+ raise except_orm(_('AccessError'),
+ _('You try to bypass an access rule (Document type: %s).') % \
+ self._description)
+ else:
+ cr.execute('SELECT id FROM "'+self._table+'" WHERE id IN ('+ids_str+')')
+ if not cr.rowcount == len({}.fromkeys(sub_ids)):
+ raise except_orm(_('AccessError'),
+ _('You try to write on an record that doesn\'t exist ' \
+ '(Document type: %s).') % self._description)
+ if d1:
+ cr.execute('update "'+self._table+'" set '+string.join(upd0,',')+' ' \
+ 'where id in ('+ids_str+')'+d1, upd1+ d2)
+ else:
+ cr.execute('update "'+self._table+'" set '+string.join(upd0,',')+' ' \
+ 'where id in ('+ids_str+')', upd1)
+
+ if totranslate:
+ for f in direct:
+ if self._columns[f].translate:
+ self.pool.get('ir.translation')._set_ids(cr, user, self._name+','+f,'model', context['lang'], ids,vals[f])
+
+ # call the 'set' method of fields which are not classic_write
+ upd_todo.sort(lambda x,y: self._columns[x].priority-self._columns[y].priority)
+ for field in upd_todo:
+ for id in ids:
+ self._columns[field].set(cr, self, id, field, vals[field], user, context=context)
+
+ for table in self._inherits:
+ col = self._inherits[table]
+ nids = []
+ for i in range((len(ids) / ID_MAX) + ((len(ids) % ID_MAX) and 1 or 0)):
+ sub_ids = ids[ID_MAX * i:ID_MAX * (i + 1)]
+ ids_str = string.join(map(str, sub_ids),',')
+ cr.execute('select distinct "'+col+'" from "'+self._table+'" ' \
+ 'where id in ('+ids_str+')', upd1)
+ nids.extend([x[0] for x in cr.fetchall()])
+
+ v = {}
+ for val in updend:
+ if self._inherit_fields[val][0]==table:
+ v[val]=vals[val]
+ self.pool.get(table).write(cr, user, nids, v, context)
+
+ self._validate(cr, user, ids, context)
+
+ if context.has_key('read_delta'):
+ del context['read_delta']
+
+ 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)
+
+ return True
+
+ #
+ # TODO: Should set perm to user.xxx
+ #
+ def create(self, cr, user, vals, context=None):
+ """ create(cr, user, vals, context) -> int
+ cr = database cursor
+ user = user id
+ vals = dictionary of the form {'field_name':field_value, ...}
+ """
+ if not context:
+ context={}
+ self.pool.get('ir.model.access').check(cr, user, self._name, 'create')
+
+ default = []
+
+ avoid_table = []
+ for (t,c) in self._inherits.items():
+ if c in vals:
+ avoid_table.append(t)
+ for f in self._columns.keys(): # + self._inherit_fields.keys():
+ if not f in vals:
+ default.append(f)
+ for f in self._inherit_fields.keys():
+ if (not f in vals) and (not self._inherit_fields[f][0] in avoid_table):
+ default.append(f)
+
+ if len(default):
+ vals.update(self.default_get(cr, user, default, context))
+
+ tocreate = {}
+ for v in self._inherits:
+ if self._inherits[v] not in vals:
+ tocreate[v] = {}
+
+ (upd0, upd1, upd2) = ('', '', [])
+ upd_todo = []
+
+ for v in vals.keys():
+ if v in self._inherit_fields:
+ (table,col,col_detail) = self._inherit_fields[v]
+ tocreate[table][v] = vals[v]
+ del vals[v]
+
+ cr.execute("SELECT nextval('"+self._sequence+"')")
+ id_new = cr.fetchone()[0]
+ for table in tocreate:
+ id = self.pool.get(table).create(cr, user, tocreate[table])
+ upd0 += ','+self._inherits[table]
+ upd1 += ',%d'
+ upd2.append(id)
+
+ for field in vals:
+ if self._columns[field]._classic_write:
+ upd0=upd0+',"'+field+'"'
+ upd1=upd1+','+self._columns[field]._symbol_set[0]
+ upd2.append(self._columns[field]._symbol_set[1](vals[field]))
+ else:
+ upd_todo.append(field)
+ if field in self._columns \
+ and hasattr(self._columns[field], 'selection') \
+ and vals[field]:
+ if self._columns[field]._type == 'reference':
+ val = vals[field].split(',')[0]
+ else:
+ val = vals[field]
+ if isinstance(self._columns[field].selection, (tuple, list)):
+ if val not in dict(self._columns[field].selection):
+ raise except_orm(_('ValidateError'),
+ _('The value "%s" for the field "%s" is not in the selection') \
+ % (vals[field], field))
+ else:
+ if val not in dict(self._columns[field].selection(
+ self, cr, user, context=context)):
+ raise except_orm(_('ValidateError'),
+ _('The value "%s" for the field "%s" is not in the selection') \
+ % (vals[field], field))
+ if self._log_access:
+ upd0 += ',create_uid,create_date'
+ upd1 += ',%d,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)
+ for field in upd_todo:
+ self._columns[field].set(cr, self, id_new, field, vals[field], user, context)
+
+ self._validate(cr, user, [id_new], context)
+
+ 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)
+
+ 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])
+ return parent_id
+
+ def _store_set_values(self,cr,uid,ids,tuple_fn,parent_id,context):
+ name = tuple_fn[1]
+ table = tuple_fn[0]
+ 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'):
+ value = res[field][0]
+ 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)
+ return True
+
+ #
+ # TODO: Validate
+ #
+ def perm_write(self, cr, user, ids, fields, context=None):
+ raise _('This method does not exist anymore')
+
+ # TODO: ameliorer avec NULL
+ def _where_calc(self, cr, user, args, active_test=True, context=None):
+ if not context:
+ context={}
+ args = args[:]
+ # if the object has a field named 'active', filter out all inactive
+ # records unless they were explicitely asked for
+ if 'active' in self._columns and (active_test and context.get('active_test', True)):
+ i = 0
+ active_found = False
+ while i<len(args):
+ if args[i][0]=='active':
+ active_found = True
+ i += 1
+ if not active_found:
+ args.append(('active', '=', 1))
+
+ i = 0
+ tables=['"'+self._table+'"']
+ joins=[]
+ while i<len(args):
+ table=self
+ assert args[i][1] in ('like','!=','ilike','=like', 'not like', 'not ilike', 'not in','inselect','child_of','in','=','<>','<','>','>=','<='), _('Error ! Bad clause operand "%s".') % (args[i][1],)
+ if args[i][1] == 'inselect':
+ raise except_orm(_('ValidateError'),
+ _("The clause 'inselect' can not be used outside the orm!"))
+ if args[i][0] in self._inherit_fields:
+ table=self.pool.get(self._inherit_fields[args[i][0]][0])
+ if ('"'+table._table+'"' not in tables):
+ tables.append('"'+table._table+'"')
+ joins.append(('id', 'join', '%s.%s' % (self._table, self._inherits[table._name]), table))
+ fargs = args[i][0].split('.', 1)
+ field = table._columns.get(fargs[0],False)
+ if not field:
+ if args[i][0] == 'id' and args[i][1] == 'child_of':
+ ids2 = args[i][2]
+ def _rec_get(ids, table, parent):
+ if not ids:
+ return []
+ ids2 = table.search(cr, user, [(parent, 'in', ids)], context=context)
+ return ids + _rec_get(ids2, table, parent)
+ args[i] = (args[i][0], 'in', ids2 + _rec_get(ids2, table, table._parent_name), table)
+ i+=1
+ continue
+ if len(fargs) > 1:
+ if field._type == 'many2one':
+ args[i] = (fargs[0], 'in', self.pool.get(field._obj).search(cr, user, [(fargs[1], args[i][1], args[i][2])], context=context))
+ i+=1
+ continue
+ else:
+ i+=1
+ continue
+ if field._properties:
+ arg = [args.pop(i)]
+ j = i
+ while j<len(args):
+ if args[j][0]==arg[0][0]:
+ arg.append(args.pop(j))
+ else:
+ j+=1
+ if field._fnct_search:
+ args.extend(field.search(cr, user, self, arg[0][0], arg))
+ if field.store:
+ args.extend(arg)
+ i+=1
+ elif field._type=='one2many':
+ field_obj = self.pool.get(field._obj)
+
+ if isinstance(args[i][2], basestring):
+ # get the ids of the records of the "distant" resource
+ ids2 = [x[0] for x in field_obj.name_search(cr, user, args[i][2], [], args[i][1])]
+ else:
+ ids2 = args[i][2]
+ if not ids2:
+ args[i] = ('id','=','0')
+ else:
+ ids3 = []
+ for j in range((len(ids2) / ID_MAX) + (len(ids2) % ID_MAX)):
+ sub_ids2 = ids2[ID_MAX * j:ID_MAX * (j + 1)]
+ if sub_ids2:
+ cr.execute('SELECT "'+field._fields_id+'" ' \
+ 'FROM "'+field_obj._table+'" ' \
+ 'WHERE id in ('+','.join(map(str,sub_ids2))+')')
+ ids3.extend([x[0] for x in cr.fetchall()])
+
+ args[i] = ('id', 'in', ids3)
+ i+=1
+
+ elif field._type=='many2many':
+ #FIXME
+ if args[i][1]=='child_of':
+ if isinstance(args[i][2], basestring):
+ ids2 = [x[0] for x in self.pool.get(field._obj).name_search(cr, user, args[i][2], [], 'like')]
+ else:
+ ids2 = args[i][2]
+ def _rec_get(ids, table, parent):
+ if not ids:
+ return []
+ ids2 = table.search(cr, user, [(parent, 'in', ids)], context=context)
+ return ids + _rec_get(ids2, table, parent)
+ def _rec_convert(ids):
+ if self.pool.get(field._obj)==self:
+ return ids
+ if not len(ids): return []
+ cr.execute('select "'+field._id1+'" from "'+field._rel+'" where "'+field._id2+'" in ('+','.join(map(str,ids))+')')
+ ids = [x[0] for x in cr.fetchall()]
+ return ids
+ args[i] = ('id','in',_rec_convert(ids2+_rec_get(ids2, self.pool.get(field._obj), table._parent_name)))
+ else:
+ if isinstance(args[i][2], basestring):
+ res_ids = [x[0] for x in self.pool.get(field._obj).name_search(cr, user, args[i][2], [], args[i][1])]
+ else:
+ res_ids = args[i][2]
+ if not len(res_ids):
+ args[i] = ('id', 'in', [0])
+ else:
+ cr.execute('select "'+field._id1+'" from "'+field._rel+'" where "'+field._id2+'" in ('+','.join(map(str, res_ids))+')')
+ args[i] = ('id', 'in', map(lambda x: x[0], cr.fetchall()))
+ i+=1
+
+ elif field._type=='many2one':
+ if args[i][1]=='child_of':
+ if isinstance(args[i][2], basestring):
+ ids2 = [x[0] for x in self.pool.get(field._obj).name_search(cr, user, args[i][2], [], 'like')]
+ else:
+ ids2 = args[i][2]
+ def _rec_get(ids, table, parent):
+ if not ids:
+ return []
+ ids2 = table.search(cr, user, [(parent, 'in', ids)], context=context)
+ return ids + _rec_get(ids2, table, parent)
+ if field._obj <> table._name:
+ args[i] = (args[i][0],'in',ids2+_rec_get(ids2, self.pool.get(field._obj), table._parent_name), table)
+ else:
+ args[i] = ('id','in',ids2+_rec_get(ids2, table, args[i][0]), table)
+ else:
+ if isinstance(args[i][2], basestring):
+ res_ids = self.pool.get(field._obj).name_search(cr, user, args[i][2], [], args[i][1])
+ args[i] = (args[i][0],'in',map(lambda x: x[0], res_ids), table)
+ else:
+ args[i] += (table,)
+ i+=1
+ else:
+ if field.translate:
+ if args[i][1] in ('like', 'ilike', 'not like', 'not ilike'):
+ args[i] = (args[i][0], args[i][1], '%%%s%%' % args[i][2])
+ query1 = '(SELECT res_id FROM ir_translation ' \
+ 'WHERE name = %s AND lang = %s ' \
+ 'AND type = %s ' \
+ 'AND VALUE ' + args[i][1] + ' %s)'
+ query2 = [table._name + ',' + args[i][0],
+ context.get('lang', False) or 'en_US',
+ 'model',
+ args[i][2]]
+ query1 += ' UNION '
+ query1 += '(SELECT id FROM "' + table._table + '" ' \
+ 'WHERE "' + args[i][0] + '" ' + args[i][1] + ' %s)'
+ query2 += [args[i][2]]
+ args[i] = ('id', 'inselect', (query1, query2), table)
+ else:
+ args[i] += (table,)
+ i+=1
+ args.extend(joins)
+
+ qu1, qu2 = [], []
+ for x in args:
+ table=self
+ if len(x) > 3:
+ table=x[3]
+ if x[1] == 'inselect':
+ qu1.append('(%s.%s in (%s))' % (table._table, x[0], x[2][0]))
+ qu2 += x[2][1]
+ elif x[1]=='not in':
+ if len(x[2])>0:
+ todel = []
+ for xitem in range(len(x[2])):
+ if x[2][xitem]==False and isinstance(x[2][xitem],bool):
+ todel.append(xitem)
+ for xitem in todel[::-1]:
+ del x[2][xitem]
+ if x[0]=='id':
+ qu1.append('(%s.id not in (%s))' % (table._table, ','.join(['%d'] * len(x[2])),))
+ else:
+ qu1.append('(%s.%s not in (%s))' % (table._table, x[0], ','.join([table._columns[x[0]]._symbol_set[0]]*len(x[2]))))
+ if todel:
+ qu1[-1] = '('+qu1[-1]+' or '+x[0]+' is null)'
+ qu2+=x[2]
+ else:
+ qu1.append(' (1=0)')
+ elif x[1] != 'in':
#FIXME: this replace all (..., '=', False) values with 'is null' and this is
# not what we want for real boolean fields. The problem is, we can't change it
# easily because we use False everywhere instead of None
# NOTE FAB: we can't use None becStay tunes ! ause it is not accepted by XML-RPC, that's why
# boolean (0-1), None -> False
# Ged> boolean fields are not always = 0 or 1
- if (x[2] is False) and (x[1]=='='):
- qu1.append(x[0]+' is null')
- elif (x[2] is False) and (x[1]=='<>' or x[1]=='!='):
- qu1.append(x[0]+' is not null')
- else:
- if x[0]=='id':
- if x[1]=='join':
- qu1.append('(%s.%s = %s)' % (table._table, x[0], x[2]))
- else:
- qu1.append('(%s.%s %s %%s)' % (table._table, x[0], x[1]))
- qu2.append(x[2])
- else:
- add_null = False
- if x[1] in ('like', 'ilike', 'not like', 'not ilike'):
- if isinstance(x[2], str):
- str_utf8 = x[2]
- elif isinstance(x[2], unicode):
- str_utf8 = x[2].encode('utf-8')
- else:
- str_utf8 = str(x[2])
- qu2.append('%%%s%%' % str_utf8)
- if not str_utf8:
- add_null = True
- else:
- if x[0] in table._columns:
- qu2.append(table._columns[x[0]]._symbol_set[1](x[2]))
- if x[1]=='=like':
- x1 = 'like'
- else:
- x1 = x[1]
- if x[0] in table._columns:
- if x[1] in ('like', 'ilike', 'not like', 'not ilike'):
-
- qu1.append('(%s.%s %s %s)' % (table._table,
- x[0], x1, '%s'))
- else:
- qu1.append('(%s.%s %s %s)' % (table._table,
- x[0], x1,
- table._columns[x[0]]._symbol_set[0]))
- else:
- qu1.append('(%s.%s %s \'%s\')' % (table._table, x[0], x1, x[2]))
-
- if add_null:
- qu1[-1] = '('+qu1[-1]+' or '+x[0]+' is null)'
- elif x[1]=='in':
- if len(x[2])>0:
- todel = []
- for xitem in range(len(x[2])):
- if x[2][xitem]==False and isinstance(x[2][xitem],bool):
- todel.append(xitem)
- for xitem in todel[::-1]:
- del x[2][xitem]
- #TODO fix max_stack_depth
- if x[0]=='id':
- qu1.append('(%s.id in (%s))' % (table._table, ','.join(['%d'] * len(x[2])),))
- else:
- qu1.append('(%s.%s in (%s))' % (table._table, x[0], ','.join([table._columns[x[0]]._symbol_set[0]]*len(x[2]))))
- if todel:
- qu1[-1] = '('+qu1[-1]+' or '+x[0]+' is null)'
- qu2+=x[2]
- else:
- qu1.append(' (1=0)')
- return (qu1,qu2,tables)
-
- def _check_qorder(self, word):
- if not regex_order.match(word):
- raise except_orm(_('AccessError'), _('Bad query.'))
- return True
-
- def search(self, cr, user, args, offset=0, limit=None, order=None,
- context=None, count=False):
- if not context:
- context = {}
- # compute the where, order by, limit and offset clauses
- (qu1,qu2,tables) = self._where_calc(cr, user, args, context=context)
-
- if len(qu1):
- qu1 = ' where '+string.join(qu1,' and ')
- else:
- qu1 = ''
-
- if order:
- self._check_qorder(order)
- order_by = order or self._order
-
- limit_str = limit and ' limit %d' % limit or ''
- offset_str = offset and ' offset %d' % offset or ''
-
-
- # construct a clause for the rules :
- d1, d2 = self.pool.get('ir.rule').domain_get(cr, user, self._name)
- if d1:
- qu1 = qu1 and qu1+' and '+d1 or ' where '+d1
- qu2 += d2
-
- if count:
- cr.execute('select count(%s.id) from ' % self._table +
- ','.join(tables) +qu1 + limit_str + offset_str, qu2)
- res = cr.fetchall()
- return res[0][0]
- # execute the "main" query to fetch the ids we were searching for
- cr.execute('select %s.id from ' % self._table + ','.join(tables) +qu1+' order by '+order_by+limit_str+offset_str, qu2)
- res = cr.fetchall()
- return [x[0] for x in res]
-
- # returns the different values ever entered for one field
- # this is used, for example, in the client when the user hits enter on
- # a char field
- def distinct_field_get(self, cr, uid, field, value, args=None, offset=0, limit=None):
- if not args:
- args=[]
- if field in self._inherit_fields:
- return self.pool.get(self._inherit_fields[field][0]).distinct_field_get(cr, uid,field,value,args,offset,limit)
- else:
- return self._columns[field].search(cr, self, args, field, value, offset, limit, uid)
-
- def name_get(self, cr, user, ids, context=None):
- if not context:
- context={}
- if not ids:
- return []
- if isinstance(ids, (int, long)):
- ids = [ids]
- return [(r['id'], str(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=80):
- if not args:
- args=[]
- if not context:
- context={}
- args=args[:]
- if name:
- args += [(self._rec_name,operator,name)]
- ids = self.search(cr, user, args, limit=limit, context=context)
- res = self.name_get(cr, user, ids, context)
- return res
-
- def copy(self, cr, uid, id, default=None, context=None):
- if not context:
- context={}
- if not default:
- default = {}
- if 'state' not in default:
- if 'state' in self._defaults:
- default['state'] = self._defaults['state'](self, cr, uid, context)
- data = self.read(cr, uid, [id], context=context)[0]
- fields = self.fields_get(cr, uid)
- for f in fields:
- ftype = fields[f]['type']
-
- if self._log_access and f in ('create_date', 'create_uid', 'write_date', 'write_uid'):
- del data[f]
-
- if f in default:
- data[f] = default[f]
- elif ftype == 'function':
- del data[f]
- elif ftype == 'many2one':
- try:
- data[f] = data[f] and data[f][0]
- except:
- pass
- elif ftype in ('one2many', 'one2one'):
- res = []
- rel = self.pool.get(fields[f]['relation'])
- for rel_id in data[f]:
- # the lines are first duplicated using the wrong (old)
- # parent but then are reassigned to the correct one thanks
- # to the (4, ...)
- res.append((4, rel.copy(cr, uid, rel_id, context=context)))
- data[f] = res
- elif ftype == 'many2many':
- data[f] = [(6, 0, data[f])]
- del data['id']
- for v in self._inherits:
- del data[self._inherits[v]]
- return self.create(cr, uid, data)
-
- def read_string(self, cr, uid, id, langs, fields=None, context=None):
- if not context:
- context={}
- res = {}
- res2 = {}
- self.pool.get('ir.model.access').check(cr, uid, 'ir.translation', 'read')
- if not fields:
- fields = self._columns.keys() + self._inherit_fields.keys()
- for lang in langs:
- res[lang] = {'code': lang}
- for f in fields:
- if f in self._columns:
- res_trans = self.pool.get('ir.translation')._get_source(cr, uid, self._name+','+f, 'field', lang)
- if res_trans:
- res[lang][f]=res_trans
- else:
- res[lang][f]=self._columns[f].string
- for table in self._inherits:
- cols = intersect(self._inherit_fields.keys(), fields)
- res2 = self.pool.get(table).read_string(cr, uid, id, langs, cols, context)
- for lang in res2:
- if lang in res:
- res[lang]={'code': lang}
- for f in res2[lang]:
- res[lang][f]=res2[lang][f]
- return res
-
- def write_string(self, cr, uid, id, langs, vals, context=None):
- if not context:
- context={}
- self.pool.get('ir.model.access').check(cr, uid, 'ir.translation', 'write')
- for lang in langs:
- for field in vals:
- if field in self._columns:
- self.pool.get('ir.translation')._set_ids(cr, uid, self._name+','+field, 'field', lang, [0], vals[field])
- for table in self._inherits:
- cols = intersect(self._inherit_fields.keys(), vals)
- if cols:
- self.pool.get(table).write_string(cr, uid, id, langs, vals, context)
- return True
-
- def check_recursion(self, cr, uid, ids, parent=None):
- if not parent:
- parent = self._parent_name
- ids_parent = ids[:]
- while len(ids_parent):
- ids_parent2 = []
- for i in range((len(ids) / ID_MAX) + ((len(ids) % ID_MAX) and 1 or 0)):
- sub_ids_parent = ids_parent[ID_MAX * i:ID_MAX * (i + 1)]
- cr.execute('SELECT distinct "'+parent+'"'+
- ' FROM "'+self._table+'" ' \
- 'WHERE id in ('+','.join(map(str, sub_ids_parent))+')')
- ids_parent2.extend(filter(None, map(lambda x: x[0], cr.fetchall())))
- ids_parent = ids_parent2
- for i in ids_parent:
- if i in ids:
- return False
- return True
+ if (x[2] is False) and (x[1]=='='):
+ qu1.append(x[0]+' is null')
+ elif (x[2] is False) and (x[1]=='<>' or x[1]=='!='):
+ qu1.append(x[0]+' is not null')
+ else:
+ if x[0]=='id':
+ if x[1]=='join':
+ qu1.append('(%s.%s = %s)' % (table._table, x[0], x[2]))
+ else:
+ qu1.append('(%s.%s %s %%s)' % (table._table, x[0], x[1]))
+ qu2.append(x[2])
+ else:
+ add_null = False
+ if x[1] in ('like', 'ilike', 'not like', 'not ilike'):
+ if isinstance(x[2], str):
+ str_utf8 = x[2]
+ elif isinstance(x[2], unicode):
+ str_utf8 = x[2].encode('utf-8')
+ else:
+ str_utf8 = str(x[2])
+ qu2.append('%%%s%%' % str_utf8)
+ if not str_utf8:
+ add_null = True
+ else:
+ if x[0] in table._columns:
+ qu2.append(table._columns[x[0]]._symbol_set[1](x[2]))
+ if x[1]=='=like':
+ x1 = 'like'
+ else:
+ x1 = x[1]
+ if x[0] in table._columns:
+ if x[1] in ('like', 'ilike', 'not like', 'not ilike'):
+
+ qu1.append('(%s.%s %s %s)' % (table._table,
+ x[0], x1, '%s'))
+ else:
+ qu1.append('(%s.%s %s %s)' % (table._table,
+ x[0], x1,
+ table._columns[x[0]]._symbol_set[0]))
+ else:
+ qu1.append('(%s.%s %s \'%s\')' % (table._table, x[0], x1, x[2]))
+
+ if add_null:
+ qu1[-1] = '('+qu1[-1]+' or '+x[0]+' is null)'
+ elif x[1]=='in':
+ if len(x[2])>0:
+ todel = []
+ for xitem in range(len(x[2])):
+ if x[2][xitem]==False and isinstance(x[2][xitem],bool):
+ todel.append(xitem)
+ for xitem in todel[::-1]:
+ del x[2][xitem]
+ #TODO fix max_stack_depth
+ if x[0]=='id':
+ qu1.append('(%s.id in (%s))' % (table._table, ','.join(['%d'] * len(x[2])),))
+ else:
+ qu1.append('(%s.%s in (%s))' % (table._table, x[0], ','.join([table._columns[x[0]]._symbol_set[0]]*len(x[2]))))
+ if todel:
+ qu1[-1] = '('+qu1[-1]+' or '+x[0]+' is null)'
+ qu2+=x[2]
+ else:
+ qu1.append(' (1=0)')
+ return (qu1,qu2,tables)
+
+ def _check_qorder(self, word):
+ if not regex_order.match(word):
+ raise except_orm(_('AccessError'), _('Bad query.'))
+ return True
+
+ def search(self, cr, user, args, offset=0, limit=None, order=None,
+ context=None, count=False):
+ if not context:
+ context = {}
+ # compute the where, order by, limit and offset clauses
+ (qu1,qu2,tables) = self._where_calc(cr, user, args, context=context)
+
+ if len(qu1):
+ qu1 = ' where '+string.join(qu1,' and ')
+ else:
+ qu1 = ''
+
+ if order:
+ self._check_qorder(order)
+ order_by = order or self._order
+
+ limit_str = limit and ' limit %d' % limit or ''
+ offset_str = offset and ' offset %d' % offset or ''
+
+
+ # construct a clause for the rules :
+ d1, d2 = self.pool.get('ir.rule').domain_get(cr, user, self._name)
+ if d1:
+ qu1 = qu1 and qu1+' and '+d1 or ' where '+d1
+ qu2 += d2
+
+ if count:
+ cr.execute('select count(%s.id) from ' % self._table +
+ ','.join(tables) +qu1 + limit_str + offset_str, qu2)
+ res = cr.fetchall()
+ return res[0][0]
+ # execute the "main" query to fetch the ids we were searching for
+ cr.execute('select %s.id from ' % self._table + ','.join(tables) +qu1+' order by '+order_by+limit_str+offset_str, qu2)
+ res = cr.fetchall()
+ return [x[0] for x in res]
+
+ # returns the different values ever entered for one field
+ # this is used, for example, in the client when the user hits enter on
+ # a char field
+ def distinct_field_get(self, cr, uid, field, value, args=None, offset=0, limit=None):
+ if not args:
+ args=[]
+ if field in self._inherit_fields:
+ return self.pool.get(self._inherit_fields[field][0]).distinct_field_get(cr, uid,field,value,args,offset,limit)
+ else:
+ return self._columns[field].search(cr, self, args, field, value, offset, limit, uid)
+
+ def name_get(self, cr, user, ids, context=None):
+ if not context:
+ context={}
+ if not ids:
+ return []
+ if isinstance(ids, (int, long)):
+ ids = [ids]
+ return [(r['id'], str(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=80):
+ if not args:
+ args=[]
+ if not context:
+ context={}
+ args=args[:]
+ if name:
+ args += [(self._rec_name,operator,name)]
+ ids = self.search(cr, user, args, limit=limit, context=context)
+ res = self.name_get(cr, user, ids, context)
+ return res
+
+ def copy(self, cr, uid, id, default=None, context=None):
+ if not context:
+ context={}
+ if not default:
+ default = {}
+ if 'state' not in default:
+ if 'state' in self._defaults:
+ default['state'] = self._defaults['state'](self, cr, uid, context)
+ data = self.read(cr, uid, [id], context=context)[0]
+ fields = self.fields_get(cr, uid)
+ for f in fields:
+ ftype = fields[f]['type']
+
+ if self._log_access and f in ('create_date', 'create_uid', 'write_date', 'write_uid'):
+ del data[f]
+
+ if f in default:
+ data[f] = default[f]
+ elif ftype == 'function':
+ del data[f]
+ elif ftype == 'many2one':
+ try:
+ data[f] = data[f] and data[f][0]
+ except:
+ pass
+ elif ftype in ('one2many', 'one2one'):
+ res = []
+ rel = self.pool.get(fields[f]['relation'])
+ for rel_id in data[f]:
+ # the lines are first duplicated using the wrong (old)
+ # parent but then are reassigned to the correct one thanks
+ # to the (4, ...)
+ res.append((4, rel.copy(cr, uid, rel_id, context=context)))
+ data[f] = res
+ elif ftype == 'many2many':
+ data[f] = [(6, 0, data[f])]
+ del data['id']
+ for v in self._inherits:
+ del data[self._inherits[v]]
+ return self.create(cr, uid, data)
+
+ def read_string(self, cr, uid, id, langs, fields=None, context=None):
+ if not context:
+ context={}
+ res = {}
+ res2 = {}
+ self.pool.get('ir.model.access').check(cr, uid, 'ir.translation', 'read')
+ if not fields:
+ fields = self._columns.keys() + self._inherit_fields.keys()
+ for lang in langs:
+ res[lang] = {'code': lang}
+ for f in fields:
+ if f in self._columns:
+ res_trans = self.pool.get('ir.translation')._get_source(cr, uid, self._name+','+f, 'field', lang)
+ if res_trans:
+ res[lang][f]=res_trans
+ else:
+ res[lang][f]=self._columns[f].string
+ for table in self._inherits:
+ cols = intersect(self._inherit_fields.keys(), fields)
+ res2 = self.pool.get(table).read_string(cr, uid, id, langs, cols, context)
+ for lang in res2:
+ if lang in res:
+ res[lang]={'code': lang}
+ for f in res2[lang]:
+ res[lang][f]=res2[lang][f]
+ return res
+
+ def write_string(self, cr, uid, id, langs, vals, context=None):
+ if not context:
+ context={}
+ self.pool.get('ir.model.access').check(cr, uid, 'ir.translation', 'write')
+ for lang in langs:
+ for field in vals:
+ if field in self._columns:
+ self.pool.get('ir.translation')._set_ids(cr, uid, self._name+','+field, 'field', lang, [0], vals[field])
+ for table in self._inherits:
+ cols = intersect(self._inherit_fields.keys(), vals)
+ if cols:
+ self.pool.get(table).write_string(cr, uid, id, langs, vals, context)
+ return True
+
+ def check_recursion(self, cr, uid, ids, parent=None):
+ if not parent:
+ parent = self._parent_name
+ ids_parent = ids[:]
+ while len(ids_parent):
+ ids_parent2 = []
+ for i in range((len(ids) / ID_MAX) + ((len(ids) % ID_MAX) and 1 or 0)):
+ sub_ids_parent = ids_parent[ID_MAX * i:ID_MAX * (i + 1)]
+ cr.execute('SELECT distinct "'+parent+'"'+
+ ' FROM "'+self._table+'" ' \
+ 'WHERE id in ('+','.join(map(str, sub_ids_parent))+')')
+ ids_parent2.extend(filter(None, map(lambda x: x[0], cr.fetchall())))
+ ids_parent = ids_parent2
+ for i in ids_parent:
+ if i in ids:
+ return False
+ return True
# vim:noexpandtab:ts=4
diff --git a/bin/osv/osv.py b/bin/osv/osv.py
index 3b948aec5d3..63cc52408b8 100644
--- a/bin/osv/osv.py
+++ b/bin/osv/osv.py
@@ -45,315 +45,315 @@ module_class_list = {}
class_pool = {}
class except_osv(Exception):
- def __init__(self, name, value, exc_type='warning'):
- self.name = name
- self.exc_type = exc_type
- self.value = value
- self.args = (exc_type,name)
+ def __init__(self, name, value, exc_type='warning'):
+ self.name = name
+ self.exc_type = exc_type
+ self.value = value
+ self.args = (exc_type,name)
class osv_pool(netsvc.Service):
- def __init__(self):
- self.obj_pool = {}
- self.module_object_list = {}
- self.created = []
- self._sql_error = {}
- self._store_function = {}
- netsvc.Service.__init__(self, 'object_proxy', audience='')
- self.joinGroup('web-services')
- self.exportMethod(self.exportedMethods)
- self.exportMethod(self.obj_list)
- self.exportMethod(self.exec_workflow)
- self.exportMethod(self.execute)
- self.exportMethod(self.execute_cr)
-
- def execute_cr(self, cr, uid, obj, method, *args, **kw):
- try:
- object = pooler.get_pool(cr.dbname).get(obj)
- if not object:
- self.abortResponse(1, 'Object Error', 'warning',
- 'Object %s doesn\'t exist' % str(obj))
- return getattr(object,method)(cr, uid, *args, **kw)
- except orm.except_orm, inst:
- 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:
- for key in self._sql_error.keys():
- if key in inst[0]:
- self.abortResponse(1, 'Constraint Error', 'warning',
- self._sql_error[key])
- self.abortResponse(1, 'Integrity Error', 'warning', inst[0])
- except Exception, e:
- import traceback
- tb_s = reduce(lambda x, y: x+y, traceback.format_exception(
- sys.exc_type, sys.exc_value, sys.exc_traceback))
- logger = Logger()
- logger.notifyChannel("web-services", LOG_ERROR,
- 'Exception in call: ' + tb_s)
- raise
-
- def execute(self, db, uid, obj, method, *args, **kw):
- db, pool = pooler.get_db_and_pool(db)
- cr = db.cursor()
- try:
- try:
- res = pool.execute_cr(cr, uid, obj, method, *args, **kw)
- cr.commit()
- except Exception:
- cr.rollback()
- raise
- finally:
- cr.close()
- return res
-
- def exec_workflow_cr(self, cr, uid, obj, method, *args):
- wf_service = netsvc.LocalService("workflow")
- return wf_service.trg_validate(uid, obj, args[0], method, cr)
-
- def exec_workflow(self, db, uid, obj, method, *args):
- cr = pooler.get_db(db).cursor()
- try:
- try:
- res = self.exec_workflow_cr(cr, uid, obj, method, *args)
- cr.commit()
- except orm.except_orm, inst:
- cr.rollback()
- self.abortResponse(1, inst.name, 'warning', inst.value)
- except except_osv, inst:
- cr.rollback()
- self.abortResponse(1, inst.name, inst[0], inst.value)
- finally:
- cr.close()
- return res
-
- def obj_list(self):
- return self.obj_pool.keys()
-
- # adds a new object instance to the object pool.
- # if it already existed, the instance is replaced
- def add(self, name, obj_inst):
- if self.obj_pool.has_key(name):
- del self.obj_pool[name]
- self.obj_pool[name] = obj_inst
-
- module = str(obj_inst.__class__)[6:]
- module = module[:len(module)-1]
- module = module.split('.')[0][2:]
- self.module_object_list.setdefault(module, []).append(obj_inst)
-
- def get(self, name):
- obj = self.obj_pool.get(name, None)
+ def __init__(self):
+ self.obj_pool = {}
+ self.module_object_list = {}
+ self.created = []
+ self._sql_error = {}
+ self._store_function = {}
+ netsvc.Service.__init__(self, 'object_proxy', audience='')
+ self.joinGroup('web-services')
+ self.exportMethod(self.exportedMethods)
+ self.exportMethod(self.obj_list)
+ self.exportMethod(self.exec_workflow)
+ self.exportMethod(self.execute)
+ self.exportMethod(self.execute_cr)
+
+ def execute_cr(self, cr, uid, obj, method, *args, **kw):
+ try:
+ object = pooler.get_pool(cr.dbname).get(obj)
+ if not object:
+ self.abortResponse(1, 'Object Error', 'warning',
+ 'Object %s doesn\'t exist' % str(obj))
+ return getattr(object,method)(cr, uid, *args, **kw)
+ except orm.except_orm, inst:
+ 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:
+ for key in self._sql_error.keys():
+ if key in inst[0]:
+ self.abortResponse(1, 'Constraint Error', 'warning',
+ self._sql_error[key])
+ self.abortResponse(1, 'Integrity Error', 'warning', inst[0])
+ except Exception, e:
+ import traceback
+ tb_s = reduce(lambda x, y: x+y, traceback.format_exception(
+ sys.exc_type, sys.exc_value, sys.exc_traceback))
+ logger = Logger()
+ logger.notifyChannel("web-services", LOG_ERROR,
+ 'Exception in call: ' + tb_s)
+ raise
+
+ def execute(self, db, uid, obj, method, *args, **kw):
+ db, pool = pooler.get_db_and_pool(db)
+ cr = db.cursor()
+ try:
+ try:
+ res = pool.execute_cr(cr, uid, obj, method, *args, **kw)
+ cr.commit()
+ except Exception:
+ cr.rollback()
+ raise
+ finally:
+ cr.close()
+ return res
+
+ def exec_workflow_cr(self, cr, uid, obj, method, *args):
+ wf_service = netsvc.LocalService("workflow")
+ return wf_service.trg_validate(uid, obj, args[0], method, cr)
+
+ def exec_workflow(self, db, uid, obj, method, *args):
+ cr = pooler.get_db(db).cursor()
+ try:
+ try:
+ res = self.exec_workflow_cr(cr, uid, obj, method, *args)
+ cr.commit()
+ except orm.except_orm, inst:
+ cr.rollback()
+ self.abortResponse(1, inst.name, 'warning', inst.value)
+ except except_osv, inst:
+ cr.rollback()
+ self.abortResponse(1, inst.name, inst[0], inst.value)
+ finally:
+ cr.close()
+ return res
+
+ def obj_list(self):
+ return self.obj_pool.keys()
+
+ # adds a new object instance to the object pool.
+ # if it already existed, the instance is replaced
+ def add(self, name, obj_inst):
+ if self.obj_pool.has_key(name):
+ del self.obj_pool[name]
+ self.obj_pool[name] = obj_inst
+
+ module = str(obj_inst.__class__)[6:]
+ module = module[:len(module)-1]
+ module = module.split('.')[0][2:]
+ self.module_object_list.setdefault(module, []).append(obj_inst)
+
+ def get(self, name):
+ obj = self.obj_pool.get(name, None)
# We cannot uncomment this line because it breaks initialisation since objects do not initialize
# in the correct order and the ORM doesnt support correctly when some objets do not exist yet
-# assert obj, "object %s does not exist !" % name
- return obj
-
- #TODO: pass a list of modules to load
- def instanciate(self, module, cr):
-# print "module list:", module_list
-# for module in module_list:
- res = []
- class_list = module_class_list.get(module, [])
-# if module not in self.module_object_list:
-# print "%s class_list:" % module, class_list
- for klass in class_list:
- res.append(klass.createInstance(self, module, cr))
- return res
-# else:
-# print "skipping module", module
+# assert obj, "object %s does not exist !" % name
+ return obj
+
+ #TODO: pass a list of modules to load
+ def instanciate(self, module, cr):
+# print "module list:", module_list
+# for module in module_list:
+ res = []
+ class_list = module_class_list.get(module, [])
+# if module not in self.module_object_list:
+# print "%s class_list:" % module, class_list
+ for klass in class_list:
+ res.append(klass.createInstance(self, module, cr))
+ return res
+# else:
+# print "skipping module", module
#pooler.get_pool(cr.dbname) = osv_pool()
class osv_memory(orm.orm_memory):
- #__metaclass__ = inheritor
- def __new__(cls):
- module = str(cls)[6:]
- module = module[:len(module)-1]
- module = module.split('.')[0][2:]
- if not hasattr(cls, '_module'):
- cls._module = module
- module_class_list.setdefault(cls._module, []).append(cls)
- class_pool[cls._name] = cls
- if module not in module_list:
- module_list.append(cls._module)
- return None
-
- #
- # Goal: try to apply inheritancy at the instanciation level and
- # put objects in the pool var
- #
- def createInstance(cls, pool, module, cr):
- name = hasattr(cls,'_name') and cls._name or cls._inherit
- parent_name = hasattr(cls, '_inherit') and cls._inherit
- if parent_name:
- print 'Inherit not supported in osv_memory object !'
- obj = object.__new__(cls)
- obj.__init__(pool, cr)
- return obj
- createInstance = classmethod(createInstance)
-
- def __init__(self, pool, cr):
- pool.add(self._name, self)
- self.pool = pool
- orm.orm_memory.__init__(self, cr)
+ #__metaclass__ = inheritor
+ def __new__(cls):
+ module = str(cls)[6:]
+ module = module[:len(module)-1]
+ module = module.split('.')[0][2:]
+ if not hasattr(cls, '_module'):
+ cls._module = module
+ module_class_list.setdefault(cls._module, []).append(cls)
+ class_pool[cls._name] = cls
+ if module not in module_list:
+ module_list.append(cls._module)
+ return None
+
+ #
+ # Goal: try to apply inheritancy at the instanciation level and
+ # put objects in the pool var
+ #
+ def createInstance(cls, pool, module, cr):
+ name = hasattr(cls,'_name') and cls._name or cls._inherit
+ parent_name = hasattr(cls, '_inherit') and cls._inherit
+ if parent_name:
+ print 'Inherit not supported in osv_memory object !'
+ obj = object.__new__(cls)
+ obj.__init__(pool, cr)
+ return obj
+ createInstance = classmethod(createInstance)
+
+ def __init__(self, pool, cr):
+ pool.add(self._name, self)
+ self.pool = pool
+ orm.orm_memory.__init__(self, cr)
class osv(orm.orm):
- #__metaclass__ = inheritor
- def __new__(cls):
- module = str(cls)[6:]
- module = module[:len(module)-1]
- module = module.split('.')[0][2:]
- if not hasattr(cls, '_module'):
- cls._module = module
- module_class_list.setdefault(cls._module, []).append(cls)
- class_pool[cls._name] = cls
- if module not in module_list:
- module_list.append(cls._module)
- return None
-
- #
- # Goal: try to apply inheritancy at the instanciation level and
- # put objects in the pool var
- #
- def createInstance(cls, pool, module, cr):
- parent_name = hasattr(cls, '_inherit') and cls._inherit
- if parent_name:
- parent_class = pool.get(parent_name).__class__
- assert parent_class, "parent class %s does not exist !" % parent_name
- nattr = {}
- for s in ('_columns', '_defaults', '_inherits', '_constraints', '_sql_constraints'):
- new = copy.copy(getattr(pool.get(parent_name), s))
- if hasattr(new, 'update'):
- new.update(cls.__dict__.get(s, {}))
- else:
- new.extend(cls.__dict__.get(s, []))
- nattr[s] = new
- name = hasattr(cls,'_name') and cls._name or cls._inherit
- cls = type(name, (cls, parent_class), nattr)
- obj = object.__new__(cls)
- obj.__init__(pool, cr)
- return obj
- createInstance = classmethod(createInstance)
-
- def __init__(self, pool, cr):
- pool.add(self._name, self)
- self.pool = pool
- orm.orm.__init__(self, cr)
+ #__metaclass__ = inheritor
+ def __new__(cls):
+ module = str(cls)[6:]
+ module = module[:len(module)-1]
+ module = module.split('.')[0][2:]
+ if not hasattr(cls, '_module'):
+ cls._module = module
+ module_class_list.setdefault(cls._module, []).append(cls)
+ class_pool[cls._name] = cls
+ if module not in module_list:
+ module_list.append(cls._module)
+ return None
+
+ #
+ # Goal: try to apply inheritancy at the instanciation level and
+ # put objects in the pool var
+ #
+ def createInstance(cls, pool, module, cr):
+ parent_name = hasattr(cls, '_inherit') and cls._inherit
+ if parent_name:
+ parent_class = pool.get(parent_name).__class__
+ assert parent_class, "parent class %s does not exist !" % parent_name
+ nattr = {}
+ for s in ('_columns', '_defaults', '_inherits', '_constraints', '_sql_constraints'):
+ new = copy.copy(getattr(pool.get(parent_name), s))
+ if hasattr(new, 'update'):
+ new.update(cls.__dict__.get(s, {}))
+ else:
+ new.extend(cls.__dict__.get(s, []))
+ nattr[s] = new
+ name = hasattr(cls,'_name') and cls._name or cls._inherit
+ cls = type(name, (cls, parent_class), nattr)
+ obj = object.__new__(cls)
+ obj.__init__(pool, cr)
+ return obj
+ createInstance = classmethod(createInstance)
+
+ def __init__(self, pool, cr):
+ pool.add(self._name, self)
+ self.pool = pool
+ orm.orm.__init__(self, cr)
class Cacheable(object):
- _cache = UpdateableDict()
+ _cache = UpdateableDict()
- def add(self, key, value):
- self._cache[key] = value
+ def add(self, key, value):
+ self._cache[key] = value
- def invalidate(self, key):
- del self._cache[key]
+ def invalidate(self, key):
+ del self._cache[key]
- def get(self, key):
- try:
- w = self._cache[key]
- return w
- except KeyError:
- return None
+ def get(self, key):
+ try:
+ w = self._cache[key]
+ return w
+ except KeyError:
+ return None
- def clear(self):
- self._cache.clear()
- self._items = []
+ 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
+ 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)
+ _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
# vim:noexpandtab:
#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()
+# 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()
diff --git a/bin/pooler.py b/bin/pooler.py
index b775934730f..52b9305b801 100644
--- a/bin/pooler.py
+++ b/bin/pooler.py
@@ -36,65 +36,65 @@ 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))
- db = sql_db.db_connect(db_name)
- db_dic[db_name] = db
-
- if db_name in pool_dic:
- pool = pool_dic[db_name]
- else:
- pool = osv.osv.osv_pool()
- pool_dic[db_name] = pool
- addons.load_modules(db, force_demo, status, update_module)
+ 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))
+ db = sql_db.db_connect(db_name)
+ db_dic[db_name] = db
+
+ if db_name in pool_dic:
+ pool = pool_dic[db_name]
+ else:
+ pool = osv.osv.osv_pool()
+ pool_dic[db_name] = pool
+ addons.load_modules(db, force_demo, status, update_module)
- if not update_module:
- import report
- report.interface.register_all(db)
- pool.get('ir.cron')._poolJobs(db.dbname)
- return db, pool
+ if not update_module:
+ import report
+ report.interface.register_all(db)
+ pool.get('ir.cron')._poolJobs(db.dbname)
+ return db, pool
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)
+# 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]
+ 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
- return db
+ if db_name in db_dic:
+ db = db_dic[db_name]
+ else:
+ db = sql_db.db_connect(db_name)
+ db_dic[db_name] = db
+ return db
def get_db(db_name):
-# print "get_db", db_name
- return get_db_and_pool(db_name)[0]
+# 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]
+# 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()
+ global db
+# db = get_db_only(tools.config['db_name'])
+ sql_db.init()
diff --git a/bin/report/common.py b/bin/report/common.py
index 218ed8d210d..b8cc3593761 100644
--- a/bin/report/common.py
+++ b/bin/report/common.py
@@ -28,6 +28,6 @@
##############################################################################
pageSize = {
- 'A4': (210,297),
- 'A5': (148.5,105)
+ 'A4': (210,297),
+ 'A5': (148.5,105)
}
diff --git a/bin/report/custom.py b/bin/report/custom.py
index 77fb343b47c..ed072e330d2 100644
--- a/bin/report/custom.py
+++ b/bin/report/custom.py
@@ -46,12 +46,12 @@ import misc
import StringIO
class external_pdf(render.render):
- def __init__(self, pdf):
- render.render.__init__(self)
- self.pdf = pdf
- self.output_type='pdf'
- def _render(self):
- return self.pdf
+ def __init__(self, pdf):
+ render.render.__init__(self)
+ self.pdf = pdf
+ self.output_type='pdf'
+ def _render(self):
+ return self.pdf
theme.use_color = 1
@@ -61,603 +61,603 @@ theme.use_color = 1
# heuu, ca marche pas ds tous les cas car graphs sont generes en pdf directment
# par pychart, et on passe donc pas par du rml
class report_custom(report_int):
- def __init__(self, name):
- report_int.__init__(self, name)
- #
- # PRE:
- # fields = [['address','city'],['name'], ['zip']]
- # conditions = [[('zip','==','3'),(,)],(,),(,)] #same structure as fields
- # row_canvas = ['Rue', None, None]
- # POST:
- # [ ['ville','name','zip'] ]
- #
- def _row_get(self, cr, uid, objs, fields, conditions, row_canvas=None, group_by=None):
- result = []
- tmp = []
- for obj in objs:
- tobreak = False
- for cond in conditions:
- if cond and cond[0]:
- c = cond[0]
- temp = c[0](eval('obj.'+c[1]))
- if not eval('\''+temp+'\''+' '+c[2]+' '+'\''+str(c[3])+'\''):
- tobreak = True
- if tobreak:
- break
- levels = {}
- row = []
- for i in range(len(fields)):
- if not fields[i]:
- row.append(row_canvas and row_canvas[i])
- if row_canvas[i]:
- row_canvas[i]=False
- elif len(fields[i])==1:
- if not isinstance(obj, browse_null):
- row.append(str(eval('obj.'+fields[i][0])))
- else:
- row.append(None)
- else:
- row.append(None)
- levels[fields[i][0]]=True
- if not levels:
- result.append(row)
- else:
- # Process group_by data first
- key = []
- if group_by != None and fields[group_by] != None:
- if fields[group_by][0] in levels.keys():
- key.append(fields[group_by][0])
- for l in levels.keys():
- if l != fields[group_by][0]:
- key.append(l)
- else:
- key = levels.keys()
- for l in key:
- objs = eval('obj.'+l)
- if not isinstance(objs, browse_record_list) and type(objs) <> type([]):
- objs = [objs]
- field_new = []
- cond_new = []
- for f in range(len(fields)):
- if (fields[f] and fields[f][0])==l:
- field_new.append(fields[f][1:])
- cond_new.append(conditions[f][1:])
- else:
- field_new.append(None)
- cond_new.append(None)
- if len(objs):
- result += self._row_get(cr, uid, objs, field_new, cond_new, row, group_by)
- else:
- result.append(row)
- return result
-
-
- def create(self, cr, uid, ids, datas, context=None):
- if not context:
- context={}
- self.pool = pooler.get_pool(cr.dbname)
- report = self.pool.get('ir.report.custom').browse(cr, uid, [datas['report_id']])[0]
- datas['model'] = report.model_id.model
- if report.menu_id:
- ids = self.pool.get(report.model_id.model).search(cr, uid, [])
- datas['ids'] = ids
-
- service = netsvc.LocalService("object_proxy")
- report_id = datas['report_id']
- report = service.execute(cr.dbname, uid, 'ir.report.custom', 'read', [report_id], context=context)[0]
- fields = service.execute(cr.dbname, uid, 'ir.report.custom.fields', 'read', report['fields_child0'], context=context)
-
- fields.sort(lambda x,y : x['sequence'] - y['sequence'])
-
- if report['field_parent']:
- parent_field = service.execute(cr.dbname, uid, 'ir.model.fields', 'read', [report['field_parent'][0]],['model'])
- model_name = service.execute(cr.dbname, uid, 'ir.model', 'read', [report['model_id'][0]], ['model'],context=context)[0]['model']
-
- fct = {}
- fct['id'] = lambda x : x
- fct['gety'] = lambda x: x.split('-')[0]
- fct['in'] = lambda x: x.split(',')
- new_fields = []
- new_cond = []
- for f in fields:
- row = []
- cond = []
- for i in range(4):
- if f['field_child'+str(i)]:
- row.append(f['field_child'+str(i)][1])
- if f['fc'+str(i)+'_operande']:
- fct_name = 'id'
- cond_op = f['fc'+str(i)+'_op']
- if len(f['fc'+str(i)+'_op'].split(',')) == 2:
- cond_op = f['fc'+str(i)+'_op'].split(',')[1]
- fct_name = f['fc'+str(i)+'_op'].split(',')[0]
- cond.append((fct[fct_name], f['fc'+str(i)+'_operande'][1], cond_op, f['fc'+str(i)+'_condition']))
- else:
- cond.append(None)
- new_fields.append(row)
- new_cond.append(cond)
- objs = self.pool.get(model_name).browse(cr, uid, ids)
-
- # Group by
- groupby = None
- idx = 0
- for f in fields:
- if f['groupby']:
- groupby = idx
- idx += 1
-
-
- results = []
- if report['field_parent']:
- level = []
- def build_tree(obj, level, depth):
- res = self._row_get(cr, uid,[obj], new_fields, new_cond)
- level.append(depth)
- new_obj = eval('obj.'+report['field_parent'][1])
- if not isinstance(new_obj, list) :
- new_obj = [new_obj]
- for o in new_obj:
- if not isinstance(o, browse_null):
- res += build_tree(o, level, depth+1)
- return res
-
- for obj in objs:
- results += build_tree(obj, level, 0)
- else:
- results = self._row_get(cr, uid,objs, new_fields, new_cond, group_by=groupby)
-
- fct = {
- 'calc_sum': lambda l: reduce(lambda x,y: float(x)+float(y), filter(None, l), 0),
- 'calc_avg': lambda l: reduce(lambda x,y: float(x)+float(y), filter(None, l), 0) / (len(filter(None, l)) or 1.0),
- 'calc_max': lambda l: reduce(lambda x,y: max(x,y), [(i or 0.0) for i in l], 0),
- 'calc_min': lambda l: reduce(lambda x,y: min(x,y), [(i or 0.0) for i in l], 0),
- 'calc_count': lambda l: len(filter(None, l)),
- 'False': lambda l: '\r\n'.join(filter(None, l)),
- 'groupby': lambda l: reduce(lambda x,y: x or y, l)
- }
- new_res = []
-
- prev = None
- if groupby != None:
- res_dic = {}
- for line in results:
- if not line[groupby] and prev in res_dic:
- res_dic[prev].append(line)
- else:
- prev = line[groupby]
- if res_dic.has_key(line[groupby]):
- res_dic[line[groupby]].append(line)
- else:
- res_dic[line[groupby]] = []
- res_dic[line[groupby]].append(line)
- #we use the keys in results since they are ordered, whereas in res_dic.heys() they aren't
- for key in filter(None, [x[groupby] for x in results]):
- row = []
- for col in range(len(fields)):
- if col == groupby:
- row.append(fct['groupby'](map(lambda x: x[col], res_dic[key])))
- else:
- row.append(fct[str(fields[col]['operation'])](map(lambda x: x[col], res_dic[key])))
- new_res.append(row)
- results = new_res
-
- if report['type']=='table':
- if report['field_parent']:
- res = self._create_tree(uid, ids, report, fields, level, results, context)
- else:
- sort_idx = 0
- for idx in range(len(fields)):
- if fields[idx]['name'] == report['sortby']:
- sort_idx = idx
- break
- try :
- results.sort(lambda x,y : cmp(float(x[sort_idx]),float(y[sort_idx])))
- except :
- results.sort(lambda x,y : cmp(x[sort_idx],y[sort_idx]))
- if report['limitt']:
- results = results[:int(report['limitt'])]
- res = self._create_table(uid, ids, report, fields, None, results, context)
- elif report['type'] in ('pie','bar', 'line'):
- results2 = []
- prev = False
- for r in results:
- row = []
- for j in range(len(r)):
- if j == 0 and not r[j]:
- row.append(prev)
- elif j == 0 and r[j]:
- prev = r[j]
- row.append(r[j])
- else:
- try:
- row.append(float(r[j]))
- except:
- row.append(r[j])
- results2.append(row)
- if report['type']=='pie':
- res = self._create_pie(cr,uid, ids, report, fields, results2, context)
- elif report['type']=='bar':
- res = self._create_bars(cr,uid, ids, report, fields, results2, context)
- elif report['type']=='line':
- res = self._create_lines(cr,uid, ids, report, fields, results2, context)
- return (self.obj.get(), 'pdf')
-
- def _create_tree(self, uid, ids, report, fields, level, results, context):
- pageSize=common.pageSize.get(report['print_format'], [210.0,297.0])
- if report['print_orientation']=='landscape':
- pageSize=[pageSize[1],pageSize[0]]
-
- impl = minidom.getDOMImplementation()
- new_doc = impl.createDocument(None, "report", None)
-
- # build header
- config = new_doc.createElement("config")
-
- def _append_node(name, text):
- n = new_doc.createElement(name)
- t = new_doc.createTextNode(text)
- n.appendChild(t)
- config.appendChild(n)
-
- _append_node('date', time.strftime('%d/%m/%Y'))
- _append_node('PageFormat', '%s' % report['print_format'])
- _append_node('PageSize', '%.2fmm,%.2fmm' % tuple(pageSize))
- _append_node('PageWidth', '%.2f' % (pageSize[0] * 2.8346,))
- _append_node('PageHeight', '%.2f' %(pageSize[1] * 2.8346,))
-
- length = pageSize[0]-30-reduce(lambda x,y:x+(y['width'] or 0), fields, 0)
- count = 0
- for f in fields:
- if not f['width']: count+=1
- for f in fields:
- if not f['width']:
- f['width']=round((float(length)/count)-0.5)
-
- _append_node('tableSize', '%s' % ','.join(map(lambda x: '%.2fmm' % (x['width'],), fields)))
- _append_node('report-header', '%s' % (report['title'],))
- _append_node('report-footer', '%s' % (report['footer'],))
-
- new_doc.childNodes[0].appendChild(config)
- header = new_doc.createElement("header")
-
- for f in fields:
- field = new_doc.createElement("field")
- field_txt = new_doc.createTextNode('%s' % (f['name'],))
- field.appendChild(field_txt)
- header.appendChild(field)
-
- new_doc.childNodes[0].appendChild(header)
-
- lines = new_doc.createElement("lines")
- level.reverse()
- for line in results:
- shift = level.pop()
- node_line = new_doc.createElement("row")
- prefix = '+'
- for f in range(len(fields)):
- col = new_doc.createElement("col")
- if f == 0:
- col.setAttribute('para','yes')
- col.setAttribute('tree','yes')
- col.setAttribute('space',str(3*shift)+'mm')
- if line[f] != None:
- txt = new_doc.createTextNode(prefix+str(line[f]) or '')
- else:
- txt = new_doc.createTextNode('/')
- col.appendChild(txt)
- node_line.appendChild(col)
- prefix = ''
- lines.appendChild(node_line)
-
- new_doc.childNodes[0].appendChild(lines)
-
- styledoc = libxml2.parseFile(os.path.join(tools.config['root_path'],'addons/base/report/custom_new.xsl'))
- style = libxslt.parseStylesheetDoc(styledoc)
- doc = libxml2.parseDoc(new_doc.toxml())
- rml_obj = style.applyStylesheet(doc, None)
- rml = style.saveResultToString(rml_obj)
-
- self.obj = render.rml(rml)
- self.obj.render()
- return True
-
-
- def _create_lines(self, cr, uid, ids, report, fields, results, context):
- service = netsvc.LocalService("object_proxy")
- pdf_string = StringIO.StringIO()
- can = canvas.init(fname=pdf_string, format='pdf')
-
- can.show(80,380,'/16/H'+report['title'])
-
- ar = area.T(size=(350,350),
- #x_coord = category_coord.T(['2005-09-01','2005-10-22'],0),
- x_axis = axis.X(label = fields[0]['name'], format="/a-30{}%s"),
- y_axis = axis.Y(label = ', '.join(map(lambda x : x['name'], fields[1:]))))
-
- process_date = {}
- process_date['D'] = lambda x : reduce(lambda xx,yy : xx+'-'+yy,x.split('-')[1:3])
- process_date['M'] = lambda x : x.split('-')[1]
- process_date['Y'] = lambda x : x.split('-')[0]
-
- order_date = {}
- order_date['D'] = lambda x : time.mktime((2005,int(x.split('-')[0]), int(x.split('-')[1]),0,0,0,0,0,0))
- order_date['M'] = lambda x : x
- order_date['Y'] = lambda x : x
-
- abscissa = []
- tmp = {}
-
- idx = 0
- date_idx = None
- fct = {}
- for f in fields:
- field_id = (f['field_child3'] and f['field_child3'][0]) or (f['field_child2'] and f['field_child2'][0]) or (f['field_child1'] and f['field_child1'][0]) or (f['field_child0'] and f['field_child0'][0])
- if field_id:
- type = service.execute(cr.dbname, uid, 'ir.model.fields', 'read', [field_id],['ttype'])
- if type[0]['ttype'] == 'date':
- date_idx = idx
- fct[idx] = process_date[report['frequency']]
- else:
- fct[idx] = lambda x : x
- else:
- fct[idx] = lambda x : x
- idx+=1
-
- # plots are usually displayed year by year
- # so we do so if the first field is a date
- data_by_year = {}
- if date_idx != None:
- for r in results:
- key = process_date['Y'](r[date_idx])
- if not data_by_year.has_key(key):
- data_by_year[key] = []
- for i in range(len(r)):
- r[i] = fct[i](r[i])
- data_by_year[key].append(r)
- else:
- data_by_year[''] = results
-
- idx0 = 0
- nb_bar = len(data_by_year)*(len(fields)-1)
- colors = map(lambda x:line_style.T(color=x), misc.choice_colors(nb_bar))
- abscissa = {}
- for line in data_by_year.keys():
- fields_bar = []
- # sum data and save it in a list. An item for a fields
- for d in data_by_year[line]:
- for idx in range(len(fields)-1):
- fields_bar.append({})
- if fields_bar[idx].has_key(d[0]):
- fields_bar[idx][d[0]] += d[idx+1]
- else:
- fields_bar[idx][d[0]] = d[idx+1]
- for idx in range(len(fields)-1):
- data = {}
- for k in fields_bar[idx].keys():
- if data.has_key(k):
- data[k] += fields_bar[idx][k]
- else:
- data[k] = fields_bar[idx][k]
- data_cum = []
- prev = 0.0
- keys = data.keys()
- keys.sort()
- # cumulate if necessary
- for k in keys:
- data_cum.append([k, float(data[k])+float(prev)])
- if fields[idx+1]['cumulate']:
- prev += data[k]
- idx0 = 0
- plot = line_plot.T(label=fields[idx+1]['name']+' '+str(line), data = data_cum, line_style=colors[idx0*(len(fields)-1)+idx])
- ar.add_plot(plot)
- abscissa.update(fields_bar[idx])
- idx0 += 1
-
- abscissa = map(lambda x : [x, None], abscissa)
- ar.x_coord = category_coord.T(abscissa,0)
- ar.draw(can)
-
- can.close()
- self.obj = external_pdf(pdf_string.getvalue())
- self.obj.render()
- pdf_string.close()
- return True
-
-
-
- def _create_bars(self, cr, uid, ids, report, fields, results, context):
- service = netsvc.LocalService("object_proxy")
- pdf_string = StringIO.StringIO()
- can = canvas.init(fname=pdf_string, format='pdf')
-
- can.show(80,380,'/16/H'+report['title'])
-
- process_date = {}
- process_date['D'] = lambda x : reduce(lambda xx,yy : xx+'-'+yy,x.split('-')[1:3])
- process_date['M'] = lambda x : x.split('-')[1]
- process_date['Y'] = lambda x : x.split('-')[0]
-
- order_date = {}
- order_date['D'] = lambda x : time.mktime((2005,int(x.split('-')[0]), int(x.split('-')[1]),0,0,0,0,0,0))
- order_date['M'] = lambda x : x
- order_date['Y'] = lambda x : x
-
- ar = area.T(size=(350,350),
- x_axis = axis.X(label = fields[0]['name'], format="/a-30{}%s"),
- y_axis = axis.Y(label = ', '.join(map(lambda x : x['name'], fields[1:]))))
-
- idx = 0
- date_idx = None
- fct = {}
- for f in fields:
- field_id = (f['field_child3'] and f['field_child3'][0]) or (f['field_child2'] and f['field_child2'][0]) or (f['field_child1'] and f['field_child1'][0]) or (f['field_child0'] and f['field_child0'][0])
- if field_id:
- type = service.execute(cr.dbname, uid, 'ir.model.fields', 'read', [field_id],['ttype'])
- if type[0]['ttype'] == 'date':
- date_idx = idx
- fct[idx] = process_date[report['frequency']]
- else:
- fct[idx] = lambda x : x
- else:
- fct[idx] = lambda x : x
- idx+=1
-
- # plot are usually displayed year by year
- # so we do so if the first field is a date
- data_by_year = {}
- if date_idx != None:
- for r in results:
- key = process_date['Y'](r[date_idx])
- if not data_by_year.has_key(key):
- data_by_year[key] = []
- for i in range(len(r)):
- r[i] = fct[i](r[i])
- data_by_year[key].append(r)
- else:
- data_by_year[''] = results
-
-
- nb_bar = len(data_by_year)*(len(fields)-1)
- colors = map(lambda x:fill_style.Plain(bgcolor=x), misc.choice_colors(nb_bar))
-
- abscissa = {}
- for line in data_by_year.keys():
- fields_bar = []
- # sum data and save it in a list. An item for a fields
- for d in data_by_year[line]:
- for idx in range(len(fields)-1):
- fields_bar.append({})
- if fields_bar[idx].has_key(d[0]):
- fields_bar[idx][d[0]] += d[idx+1]
- else:
- fields_bar[idx][d[0]] = d[idx+1]
- for idx in range(len(fields)-1):
- data = {}
- for k in fields_bar[idx].keys():
- if data.has_key(k):
- data[k] += fields_bar[idx][k]
- else:
- data[k] = fields_bar[idx][k]
- data_cum = []
- prev = 0.0
- keys = data.keys()
- keys.sort()
- # cumulate if necessary
- for k in keys:
- data_cum.append([k, float(data[k])+float(prev)])
- if fields[idx+1]['cumulate']:
- prev += data[k]
-
- idx0 = 0
- plot = bar_plot.T(label=fields[idx+1]['name']+' '+str(line), data = data_cum, cluster=(idx0*(len(fields)-1)+idx,nb_bar), fill_style=colors[idx0*(len(fields)-1)+idx])
- ar.add_plot(plot)
- abscissa.update(fields_bar[idx])
- idx0 += 1
- abscissa = map(lambda x : [x, None], abscissa)
- ar.x_coord = category_coord.T(abscissa,0)
- ar.draw(can)
-
- can.close()
- self.obj = external_pdf(pdf_string.getvalue())
- self.obj.render()
- pdf_string.close()
- return True
-
- def _create_pie(self, cr, uid, ids, report, fields, results, context):
- pdf_string = StringIO.StringIO()
- can = canvas.init(fname=pdf_string, format='pdf')
- ar = area.T(size=(350,350), legend=legend.T(),
- x_grid_style = None, y_grid_style = None)
- colors = map(lambda x:fill_style.Plain(bgcolor=x), misc.choice_colors(len(results)))
-
- if reduce(lambda x,y : x+y, map(lambda x : x[1],results)) == 0.0:
- raise(_('The sum of the data (2nd field) is null.\nWe can draw a pie chart !'))
-
- plot = pie_plot.T(data=results, arc_offsets=[0,10,0,10],
- shadow = (2, -2, fill_style.gray50),
- label_offset = 25,
- arrow_style = arrow.a3,
- fill_styles=colors)
- ar.add_plot(plot)
- ar.draw(can)
- can.close()
- self.obj = external_pdf(pdf_string.getvalue())
- self.obj.render()
- pdf_string.close()
- return True
-
- def _create_table(self, uid, ids, report, fields, tree, results, context):
- pageSize=common.pageSize.get(report['print_format'], [210.0,297.0])
- if report['print_orientation']=='landscape':
- pageSize=[pageSize[1],pageSize[0]]
-
- impl = minidom.getDOMImplementation()
- new_doc = impl.createDocument(None, "report", None)
-
- # build header
- config = new_doc.createElement("config")
-
- def _append_node(name, text):
- n = new_doc.createElement(name)
- t = new_doc.createTextNode(text)
- n.appendChild(t)
- config.appendChild(n)
-
- _append_node('date', time.strftime('%d/%m/%Y'))
- _append_node('PageSize', '%.2fmm,%.2fmm' % tuple(pageSize))
- _append_node('PageFormat', '%s' % report['print_format'])
- _append_node('PageWidth', '%.2f' % (pageSize[0] * 2.8346,))
- _append_node('PageHeight', '%.2f' %(pageSize[1] * 2.8346,))
-
- length = pageSize[0]-30-reduce(lambda x,y:x+(y['width'] or 0), fields, 0)
- count = 0
- for f in fields:
- if not f['width']: count+=1
- for f in fields:
- if not f['width']:
- f['width']=round((float(length)/count)-0.5)
-
- _append_node('tableSize', '%s' % ','.join(map(lambda x: '%.2fmm' % (x['width'],), fields)))
- _append_node('report-header', '%s' % (report['title'],))
- _append_node('report-footer', '%s' % (report['footer'],))
-
- new_doc.childNodes[0].appendChild(config)
- header = new_doc.createElement("header")
-
- for f in fields:
- field = new_doc.createElement("field")
- field_txt = new_doc.createTextNode('%s' % (f['name'],))
- field.appendChild(field_txt)
- header.appendChild(field)
-
- new_doc.childNodes[0].appendChild(header)
-
- lines = new_doc.createElement("lines")
- for line in results:
- node_line = new_doc.createElement("row")
- for f in range(len(fields)):
- col = new_doc.createElement("col")
- col.setAttribute('tree','no')
- if line[f] != None:
- txt = new_doc.createTextNode(str(line[f] or ''))
- else:
- txt = new_doc.createTextNode('/')
- col.appendChild(txt)
- node_line.appendChild(col)
- lines.appendChild(node_line)
-
- new_doc.childNodes[0].appendChild(lines)
-
-# file('/tmp/terp.xml','w+').write(new_doc.toxml())
-
- styledoc = libxml2.parseFile(os.path.join(tools.config['root_path'],'addons/base/report/custom_new.xsl'))
- style = libxslt.parseStylesheetDoc(styledoc)
- doc = libxml2.parseDoc(new_doc.toxml())
- rml_obj = style.applyStylesheet(doc, None)
- rml = style.saveResultToString(rml_obj)
-
- self.obj = render.rml(rml)
- self.obj.render()
- return True
+ def __init__(self, name):
+ report_int.__init__(self, name)
+ #
+ # PRE:
+ # fields = [['address','city'],['name'], ['zip']]
+ # conditions = [[('zip','==','3'),(,)],(,),(,)] #same structure as fields
+ # row_canvas = ['Rue', None, None]
+ # POST:
+ # [ ['ville','name','zip'] ]
+ #
+ def _row_get(self, cr, uid, objs, fields, conditions, row_canvas=None, group_by=None):
+ result = []
+ tmp = []
+ for obj in objs:
+ tobreak = False
+ for cond in conditions:
+ if cond and cond[0]:
+ c = cond[0]
+ temp = c[0](eval('obj.'+c[1]))
+ if not eval('\''+temp+'\''+' '+c[2]+' '+'\''+str(c[3])+'\''):
+ tobreak = True
+ if tobreak:
+ break
+ levels = {}
+ row = []
+ for i in range(len(fields)):
+ if not fields[i]:
+ row.append(row_canvas and row_canvas[i])
+ if row_canvas[i]:
+ row_canvas[i]=False
+ elif len(fields[i])==1:
+ if not isinstance(obj, browse_null):
+ row.append(str(eval('obj.'+fields[i][0])))
+ else:
+ row.append(None)
+ else:
+ row.append(None)
+ levels[fields[i][0]]=True
+ if not levels:
+ result.append(row)
+ else:
+ # Process group_by data first
+ key = []
+ if group_by != None and fields[group_by] != None:
+ if fields[group_by][0] in levels.keys():
+ key.append(fields[group_by][0])
+ for l in levels.keys():
+ if l != fields[group_by][0]:
+ key.append(l)
+ else:
+ key = levels.keys()
+ for l in key:
+ objs = eval('obj.'+l)
+ if not isinstance(objs, browse_record_list) and type(objs) <> type([]):
+ objs = [objs]
+ field_new = []
+ cond_new = []
+ for f in range(len(fields)):
+ if (fields[f] and fields[f][0])==l:
+ field_new.append(fields[f][1:])
+ cond_new.append(conditions[f][1:])
+ else:
+ field_new.append(None)
+ cond_new.append(None)
+ if len(objs):
+ result += self._row_get(cr, uid, objs, field_new, cond_new, row, group_by)
+ else:
+ result.append(row)
+ return result
+
+
+ def create(self, cr, uid, ids, datas, context=None):
+ if not context:
+ context={}
+ self.pool = pooler.get_pool(cr.dbname)
+ report = self.pool.get('ir.report.custom').browse(cr, uid, [datas['report_id']])[0]
+ datas['model'] = report.model_id.model
+ if report.menu_id:
+ ids = self.pool.get(report.model_id.model).search(cr, uid, [])
+ datas['ids'] = ids
+
+ service = netsvc.LocalService("object_proxy")
+ report_id = datas['report_id']
+ report = service.execute(cr.dbname, uid, 'ir.report.custom', 'read', [report_id], context=context)[0]
+ fields = service.execute(cr.dbname, uid, 'ir.report.custom.fields', 'read', report['fields_child0'], context=context)
+
+ fields.sort(lambda x,y : x['sequence'] - y['sequence'])
+
+ if report['field_parent']:
+ parent_field = service.execute(cr.dbname, uid, 'ir.model.fields', 'read', [report['field_parent'][0]],['model'])
+ model_name = service.execute(cr.dbname, uid, 'ir.model', 'read', [report['model_id'][0]], ['model'],context=context)[0]['model']
+
+ fct = {}
+ fct['id'] = lambda x : x
+ fct['gety'] = lambda x: x.split('-')[0]
+ fct['in'] = lambda x: x.split(',')
+ new_fields = []
+ new_cond = []
+ for f in fields:
+ row = []
+ cond = []
+ for i in range(4):
+ if f['field_child'+str(i)]:
+ row.append(f['field_child'+str(i)][1])
+ if f['fc'+str(i)+'_operande']:
+ fct_name = 'id'
+ cond_op = f['fc'+str(i)+'_op']
+ if len(f['fc'+str(i)+'_op'].split(',')) == 2:
+ cond_op = f['fc'+str(i)+'_op'].split(',')[1]
+ fct_name = f['fc'+str(i)+'_op'].split(',')[0]
+ cond.append((fct[fct_name], f['fc'+str(i)+'_operande'][1], cond_op, f['fc'+str(i)+'_condition']))
+ else:
+ cond.append(None)
+ new_fields.append(row)
+ new_cond.append(cond)
+ objs = self.pool.get(model_name).browse(cr, uid, ids)
+
+ # Group by
+ groupby = None
+ idx = 0
+ for f in fields:
+ if f['groupby']:
+ groupby = idx
+ idx += 1
+
+
+ results = []
+ if report['field_parent']:
+ level = []
+ def build_tree(obj, level, depth):
+ res = self._row_get(cr, uid,[obj], new_fields, new_cond)
+ level.append(depth)
+ new_obj = eval('obj.'+report['field_parent'][1])
+ if not isinstance(new_obj, list) :
+ new_obj = [new_obj]
+ for o in new_obj:
+ if not isinstance(o, browse_null):
+ res += build_tree(o, level, depth+1)
+ return res
+
+ for obj in objs:
+ results += build_tree(obj, level, 0)
+ else:
+ results = self._row_get(cr, uid,objs, new_fields, new_cond, group_by=groupby)
+
+ fct = {
+ 'calc_sum': lambda l: reduce(lambda x,y: float(x)+float(y), filter(None, l), 0),
+ 'calc_avg': lambda l: reduce(lambda x,y: float(x)+float(y), filter(None, l), 0) / (len(filter(None, l)) or 1.0),
+ 'calc_max': lambda l: reduce(lambda x,y: max(x,y), [(i or 0.0) for i in l], 0),
+ 'calc_min': lambda l: reduce(lambda x,y: min(x,y), [(i or 0.0) for i in l], 0),
+ 'calc_count': lambda l: len(filter(None, l)),
+ 'False': lambda l: '\r\n'.join(filter(None, l)),
+ 'groupby': lambda l: reduce(lambda x,y: x or y, l)
+ }
+ new_res = []
+
+ prev = None
+ if groupby != None:
+ res_dic = {}
+ for line in results:
+ if not line[groupby] and prev in res_dic:
+ res_dic[prev].append(line)
+ else:
+ prev = line[groupby]
+ if res_dic.has_key(line[groupby]):
+ res_dic[line[groupby]].append(line)
+ else:
+ res_dic[line[groupby]] = []
+ res_dic[line[groupby]].append(line)
+ #we use the keys in results since they are ordered, whereas in res_dic.heys() they aren't
+ for key in filter(None, [x[groupby] for x in results]):
+ row = []
+ for col in range(len(fields)):
+ if col == groupby:
+ row.append(fct['groupby'](map(lambda x: x[col], res_dic[key])))
+ else:
+ row.append(fct[str(fields[col]['operation'])](map(lambda x: x[col], res_dic[key])))
+ new_res.append(row)
+ results = new_res
+
+ if report['type']=='table':
+ if report['field_parent']:
+ res = self._create_tree(uid, ids, report, fields, level, results, context)
+ else:
+ sort_idx = 0
+ for idx in range(len(fields)):
+ if fields[idx]['name'] == report['sortby']:
+ sort_idx = idx
+ break
+ try :
+ results.sort(lambda x,y : cmp(float(x[sort_idx]),float(y[sort_idx])))
+ except :
+ results.sort(lambda x,y : cmp(x[sort_idx],y[sort_idx]))
+ if report['limitt']:
+ results = results[:int(report['limitt'])]
+ res = self._create_table(uid, ids, report, fields, None, results, context)
+ elif report['type'] in ('pie','bar', 'line'):
+ results2 = []
+ prev = False
+ for r in results:
+ row = []
+ for j in range(len(r)):
+ if j == 0 and not r[j]:
+ row.append(prev)
+ elif j == 0 and r[j]:
+ prev = r[j]
+ row.append(r[j])
+ else:
+ try:
+ row.append(float(r[j]))
+ except:
+ row.append(r[j])
+ results2.append(row)
+ if report['type']=='pie':
+ res = self._create_pie(cr,uid, ids, report, fields, results2, context)
+ elif report['type']=='bar':
+ res = self._create_bars(cr,uid, ids, report, fields, results2, context)
+ elif report['type']=='line':
+ res = self._create_lines(cr,uid, ids, report, fields, results2, context)
+ return (self.obj.get(), 'pdf')
+
+ def _create_tree(self, uid, ids, report, fields, level, results, context):
+ pageSize=common.pageSize.get(report['print_format'], [210.0,297.0])
+ if report['print_orientation']=='landscape':
+ pageSize=[pageSize[1],pageSize[0]]
+
+ impl = minidom.getDOMImplementation()
+ new_doc = impl.createDocument(None, "report", None)
+
+ # build header
+ config = new_doc.createElement("config")
+
+ def _append_node(name, text):
+ n = new_doc.createElement(name)
+ t = new_doc.createTextNode(text)
+ n.appendChild(t)
+ config.appendChild(n)
+
+ _append_node('date', time.strftime('%d/%m/%Y'))
+ _append_node('PageFormat', '%s' % report['print_format'])
+ _append_node('PageSize', '%.2fmm,%.2fmm' % tuple(pageSize))
+ _append_node('PageWidth', '%.2f' % (pageSize[0] * 2.8346,))
+ _append_node('PageHeight', '%.2f' %(pageSize[1] * 2.8346,))
+
+ length = pageSize[0]-30-reduce(lambda x,y:x+(y['width'] or 0), fields, 0)
+ count = 0
+ for f in fields:
+ if not f['width']: count+=1
+ for f in fields:
+ if not f['width']:
+ f['width']=round((float(length)/count)-0.5)
+
+ _append_node('tableSize', '%s' % ','.join(map(lambda x: '%.2fmm' % (x['width'],), fields)))
+ _append_node('report-header', '%s' % (report['title'],))
+ _append_node('report-footer', '%s' % (report['footer'],))
+
+ new_doc.childNodes[0].appendChild(config)
+ header = new_doc.createElement("header")
+
+ for f in fields:
+ field = new_doc.createElement("field")
+ field_txt = new_doc.createTextNode('%s' % (f['name'],))
+ field.appendChild(field_txt)
+ header.appendChild(field)
+
+ new_doc.childNodes[0].appendChild(header)
+
+ lines = new_doc.createElement("lines")
+ level.reverse()
+ for line in results:
+ shift = level.pop()
+ node_line = new_doc.createElement("row")
+ prefix = '+'
+ for f in range(len(fields)):
+ col = new_doc.createElement("col")
+ if f == 0:
+ col.setAttribute('para','yes')
+ col.setAttribute('tree','yes')
+ col.setAttribute('space',str(3*shift)+'mm')
+ if line[f] != None:
+ txt = new_doc.createTextNode(prefix+str(line[f]) or '')
+ else:
+ txt = new_doc.createTextNode('/')
+ col.appendChild(txt)
+ node_line.appendChild(col)
+ prefix = ''
+ lines.appendChild(node_line)
+
+ new_doc.childNodes[0].appendChild(lines)
+
+ styledoc = libxml2.parseFile(os.path.join(tools.config['root_path'],'addons/base/report/custom_new.xsl'))
+ style = libxslt.parseStylesheetDoc(styledoc)
+ doc = libxml2.parseDoc(new_doc.toxml())
+ rml_obj = style.applyStylesheet(doc, None)
+ rml = style.saveResultToString(rml_obj)
+
+ self.obj = render.rml(rml)
+ self.obj.render()
+ return True
+
+
+ def _create_lines(self, cr, uid, ids, report, fields, results, context):
+ service = netsvc.LocalService("object_proxy")
+ pdf_string = StringIO.StringIO()
+ can = canvas.init(fname=pdf_string, format='pdf')
+
+ can.show(80,380,'/16/H'+report['title'])
+
+ ar = area.T(size=(350,350),
+ #x_coord = category_coord.T(['2005-09-01','2005-10-22'],0),
+ x_axis = axis.X(label = fields[0]['name'], format="/a-30{}%s"),
+ y_axis = axis.Y(label = ', '.join(map(lambda x : x['name'], fields[1:]))))
+
+ process_date = {}
+ process_date['D'] = lambda x : reduce(lambda xx,yy : xx+'-'+yy,x.split('-')[1:3])
+ process_date['M'] = lambda x : x.split('-')[1]
+ process_date['Y'] = lambda x : x.split('-')[0]
+
+ order_date = {}
+ order_date['D'] = lambda x : time.mktime((2005,int(x.split('-')[0]), int(x.split('-')[1]),0,0,0,0,0,0))
+ order_date['M'] = lambda x : x
+ order_date['Y'] = lambda x : x
+
+ abscissa = []
+ tmp = {}
+
+ idx = 0
+ date_idx = None
+ fct = {}
+ for f in fields:
+ field_id = (f['field_child3'] and f['field_child3'][0]) or (f['field_child2'] and f['field_child2'][0]) or (f['field_child1'] and f['field_child1'][0]) or (f['field_child0'] and f['field_child0'][0])
+ if field_id:
+ type = service.execute(cr.dbname, uid, 'ir.model.fields', 'read', [field_id],['ttype'])
+ if type[0]['ttype'] == 'date':
+ date_idx = idx
+ fct[idx] = process_date[report['frequency']]
+ else:
+ fct[idx] = lambda x : x
+ else:
+ fct[idx] = lambda x : x
+ idx+=1
+
+ # plots are usually displayed year by year
+ # so we do so if the first field is a date
+ data_by_year = {}
+ if date_idx != None:
+ for r in results:
+ key = process_date['Y'](r[date_idx])
+ if not data_by_year.has_key(key):
+ data_by_year[key] = []
+ for i in range(len(r)):
+ r[i] = fct[i](r[i])
+ data_by_year[key].append(r)
+ else:
+ data_by_year[''] = results
+
+ idx0 = 0
+ nb_bar = len(data_by_year)*(len(fields)-1)
+ colors = map(lambda x:line_style.T(color=x), misc.choice_colors(nb_bar))
+ abscissa = {}
+ for line in data_by_year.keys():
+ fields_bar = []
+ # sum data and save it in a list. An item for a fields
+ for d in data_by_year[line]:
+ for idx in range(len(fields)-1):
+ fields_bar.append({})
+ if fields_bar[idx].has_key(d[0]):
+ fields_bar[idx][d[0]] += d[idx+1]
+ else:
+ fields_bar[idx][d[0]] = d[idx+1]
+ for idx in range(len(fields)-1):
+ data = {}
+ for k in fields_bar[idx].keys():
+ if data.has_key(k):
+ data[k] += fields_bar[idx][k]
+ else:
+ data[k] = fields_bar[idx][k]
+ data_cum = []
+ prev = 0.0
+ keys = data.keys()
+ keys.sort()
+ # cumulate if necessary
+ for k in keys:
+ data_cum.append([k, float(data[k])+float(prev)])
+ if fields[idx+1]['cumulate']:
+ prev += data[k]
+ idx0 = 0
+ plot = line_plot.T(label=fields[idx+1]['name']+' '+str(line), data = data_cum, line_style=colors[idx0*(len(fields)-1)+idx])
+ ar.add_plot(plot)
+ abscissa.update(fields_bar[idx])
+ idx0 += 1
+
+ abscissa = map(lambda x : [x, None], abscissa)
+ ar.x_coord = category_coord.T(abscissa,0)
+ ar.draw(can)
+
+ can.close()
+ self.obj = external_pdf(pdf_string.getvalue())
+ self.obj.render()
+ pdf_string.close()
+ return True
+
+
+
+ def _create_bars(self, cr, uid, ids, report, fields, results, context):
+ service = netsvc.LocalService("object_proxy")
+ pdf_string = StringIO.StringIO()
+ can = canvas.init(fname=pdf_string, format='pdf')
+
+ can.show(80,380,'/16/H'+report['title'])
+
+ process_date = {}
+ process_date['D'] = lambda x : reduce(lambda xx,yy : xx+'-'+yy,x.split('-')[1:3])
+ process_date['M'] = lambda x : x.split('-')[1]
+ process_date['Y'] = lambda x : x.split('-')[0]
+
+ order_date = {}
+ order_date['D'] = lambda x : time.mktime((2005,int(x.split('-')[0]), int(x.split('-')[1]),0,0,0,0,0,0))
+ order_date['M'] = lambda x : x
+ order_date['Y'] = lambda x : x
+
+ ar = area.T(size=(350,350),
+ x_axis = axis.X(label = fields[0]['name'], format="/a-30{}%s"),
+ y_axis = axis.Y(label = ', '.join(map(lambda x : x['name'], fields[1:]))))
+
+ idx = 0
+ date_idx = None
+ fct = {}
+ for f in fields:
+ field_id = (f['field_child3'] and f['field_child3'][0]) or (f['field_child2'] and f['field_child2'][0]) or (f['field_child1'] and f['field_child1'][0]) or (f['field_child0'] and f['field_child0'][0])
+ if field_id:
+ type = service.execute(cr.dbname, uid, 'ir.model.fields', 'read', [field_id],['ttype'])
+ if type[0]['ttype'] == 'date':
+ date_idx = idx
+ fct[idx] = process_date[report['frequency']]
+ else:
+ fct[idx] = lambda x : x
+ else:
+ fct[idx] = lambda x : x
+ idx+=1
+
+ # plot are usually displayed year by year
+ # so we do so if the first field is a date
+ data_by_year = {}
+ if date_idx != None:
+ for r in results:
+ key = process_date['Y'](r[date_idx])
+ if not data_by_year.has_key(key):
+ data_by_year[key] = []
+ for i in range(len(r)):
+ r[i] = fct[i](r[i])
+ data_by_year[key].append(r)
+ else:
+ data_by_year[''] = results
+
+
+ nb_bar = len(data_by_year)*(len(fields)-1)
+ colors = map(lambda x:fill_style.Plain(bgcolor=x), misc.choice_colors(nb_bar))
+
+ abscissa = {}
+ for line in data_by_year.keys():
+ fields_bar = []
+ # sum data and save it in a list. An item for a fields
+ for d in data_by_year[line]:
+ for idx in range(len(fields)-1):
+ fields_bar.append({})
+ if fields_bar[idx].has_key(d[0]):
+ fields_bar[idx][d[0]] += d[idx+1]
+ else:
+ fields_bar[idx][d[0]] = d[idx+1]
+ for idx in range(len(fields)-1):
+ data = {}
+ for k in fields_bar[idx].keys():
+ if data.has_key(k):
+ data[k] += fields_bar[idx][k]
+ else:
+ data[k] = fields_bar[idx][k]
+ data_cum = []
+ prev = 0.0
+ keys = data.keys()
+ keys.sort()
+ # cumulate if necessary
+ for k in keys:
+ data_cum.append([k, float(data[k])+float(prev)])
+ if fields[idx+1]['cumulate']:
+ prev += data[k]
+
+ idx0 = 0
+ plot = bar_plot.T(label=fields[idx+1]['name']+' '+str(line), data = data_cum, cluster=(idx0*(len(fields)-1)+idx,nb_bar), fill_style=colors[idx0*(len(fields)-1)+idx])
+ ar.add_plot(plot)
+ abscissa.update(fields_bar[idx])
+ idx0 += 1
+ abscissa = map(lambda x : [x, None], abscissa)
+ ar.x_coord = category_coord.T(abscissa,0)
+ ar.draw(can)
+
+ can.close()
+ self.obj = external_pdf(pdf_string.getvalue())
+ self.obj.render()
+ pdf_string.close()
+ return True
+
+ def _create_pie(self, cr, uid, ids, report, fields, results, context):
+ pdf_string = StringIO.StringIO()
+ can = canvas.init(fname=pdf_string, format='pdf')
+ ar = area.T(size=(350,350), legend=legend.T(),
+ x_grid_style = None, y_grid_style = None)
+ colors = map(lambda x:fill_style.Plain(bgcolor=x), misc.choice_colors(len(results)))
+
+ if reduce(lambda x,y : x+y, map(lambda x : x[1],results)) == 0.0:
+ raise(_('The sum of the data (2nd field) is null.\nWe can draw a pie chart !'))
+
+ plot = pie_plot.T(data=results, arc_offsets=[0,10,0,10],
+ shadow = (2, -2, fill_style.gray50),
+ label_offset = 25,
+ arrow_style = arrow.a3,
+ fill_styles=colors)
+ ar.add_plot(plot)
+ ar.draw(can)
+ can.close()
+ self.obj = external_pdf(pdf_string.getvalue())
+ self.obj.render()
+ pdf_string.close()
+ return True
+
+ def _create_table(self, uid, ids, report, fields, tree, results, context):
+ pageSize=common.pageSize.get(report['print_format'], [210.0,297.0])
+ if report['print_orientation']=='landscape':
+ pageSize=[pageSize[1],pageSize[0]]
+
+ impl = minidom.getDOMImplementation()
+ new_doc = impl.createDocument(None, "report", None)
+
+ # build header
+ config = new_doc.createElement("config")
+
+ def _append_node(name, text):
+ n = new_doc.createElement(name)
+ t = new_doc.createTextNode(text)
+ n.appendChild(t)
+ config.appendChild(n)
+
+ _append_node('date', time.strftime('%d/%m/%Y'))
+ _append_node('PageSize', '%.2fmm,%.2fmm' % tuple(pageSize))
+ _append_node('PageFormat', '%s' % report['print_format'])
+ _append_node('PageWidth', '%.2f' % (pageSize[0] * 2.8346,))
+ _append_node('PageHeight', '%.2f' %(pageSize[1] * 2.8346,))
+
+ length = pageSize[0]-30-reduce(lambda x,y:x+(y['width'] or 0), fields, 0)
+ count = 0
+ for f in fields:
+ if not f['width']: count+=1
+ for f in fields:
+ if not f['width']:
+ f['width']=round((float(length)/count)-0.5)
+
+ _append_node('tableSize', '%s' % ','.join(map(lambda x: '%.2fmm' % (x['width'],), fields)))
+ _append_node('report-header', '%s' % (report['title'],))
+ _append_node('report-footer', '%s' % (report['footer'],))
+
+ new_doc.childNodes[0].appendChild(config)
+ header = new_doc.createElement("header")
+
+ for f in fields:
+ field = new_doc.createElement("field")
+ field_txt = new_doc.createTextNode('%s' % (f['name'],))
+ field.appendChild(field_txt)
+ header.appendChild(field)
+
+ new_doc.childNodes[0].appendChild(header)
+
+ lines = new_doc.createElement("lines")
+ for line in results:
+ node_line = new_doc.createElement("row")
+ for f in range(len(fields)):
+ col = new_doc.createElement("col")
+ col.setAttribute('tree','no')
+ if line[f] != None:
+ txt = new_doc.createTextNode(str(line[f] or ''))
+ else:
+ txt = new_doc.createTextNode('/')
+ col.appendChild(txt)
+ node_line.appendChild(col)
+ lines.appendChild(node_line)
+
+ new_doc.childNodes[0].appendChild(lines)
+
+# file('/tmp/terp.xml','w+').write(new_doc.toxml())
+
+ styledoc = libxml2.parseFile(os.path.join(tools.config['root_path'],'addons/base/report/custom_new.xsl'))
+ style = libxslt.parseStylesheetDoc(styledoc)
+ doc = libxml2.parseDoc(new_doc.toxml())
+ rml_obj = style.applyStylesheet(doc, None)
+ rml = style.saveResultToString(rml_obj)
+
+ self.obj = render.rml(rml)
+ self.obj.render()
+ return True
report_custom('report.custom')
diff --git a/bin/report/int_to_text.py b/bin/report/int_to_text.py
index 552922f0973..e867ed6085d 100644
--- a/bin/report/int_to_text.py
+++ b/bin/report/int_to_text.py
@@ -28,55 +28,55 @@
##############################################################################
unites = {
- 0: '', 1:'un', 2:'deux', 3:'trois', 4:'quatre', 5:'cinq', 6:'six', 7:'sept', 8:'huit', 9:'neuf',
- 10:'dix', 11:'onze', 12:'douze', 13:'treize', 14:'quatorze', 15:'quinze', 16:'seize',
- 21:'vingt et un', 31:'trente et un', 41:'quarante et un', 51:'cinquante et un', 61:'soixante et un',
- 71:'septante et un', 91:'nonante et un', 80:'quatre-vingts'
+ 0: '', 1:'un', 2:'deux', 3:'trois', 4:'quatre', 5:'cinq', 6:'six', 7:'sept', 8:'huit', 9:'neuf',
+ 10:'dix', 11:'onze', 12:'douze', 13:'treize', 14:'quatorze', 15:'quinze', 16:'seize',
+ 21:'vingt et un', 31:'trente et un', 41:'quarante et un', 51:'cinquante et un', 61:'soixante et un',
+ 71:'septante et un', 91:'nonante et un', 80:'quatre-vingts'
}
dizaine = {
- 1: 'dix', 2:'vingt', 3:'trente',4:'quarante', 5:'cinquante', 6:'soixante', 7:'septante', 8:'quatre-vingt', 9:'nonante'
+ 1: 'dix', 2:'vingt', 3:'trente',4:'quarante', 5:'cinquante', 6:'soixante', 7:'septante', 8:'quatre-vingt', 9:'nonante'
}
centaine = {
- 0:'', 1: 'cent', 2:'deux cent', 3:'trois cent',4:'quatre cent', 5:'cinq cent', 6:'six cent', 7:'sept cent', 8:'huit cent', 9:'neuf cent'
+ 0:'', 1: 'cent', 2:'deux cent', 3:'trois cent',4:'quatre cent', 5:'cinq cent', 6:'six cent', 7:'sept cent', 8:'huit cent', 9:'neuf cent'
}
mille = {
- 0:'', 1:'mille'
+ 0:'', 1:'mille'
}
def _100_to_text(chiffre):
- if chiffre in unites:
- return unites[chiffre]
- else:
- if chiffre%10>0:
- return dizaine[chiffre / 10]+'-'+unites[chiffre % 10]
- else:
- return dizaine[chiffre / 10]
+ if chiffre in unites:
+ return unites[chiffre]
+ else:
+ if chiffre%10>0:
+ return dizaine[chiffre / 10]+'-'+unites[chiffre % 10]
+ else:
+ return dizaine[chiffre / 10]
def _1000_to_text(chiffre):
- d = _100_to_text(chiffre % 100)
- d2 = chiffre/100
- if d2>0 and d:
- return centaine[d2]+' '+d
- elif d2>1 and not(d):
- return centaine[d2]+'s'
- else:
- return centaine[d2] or d
+ d = _100_to_text(chiffre % 100)
+ d2 = chiffre/100
+ if d2>0 and d:
+ return centaine[d2]+' '+d
+ elif d2>1 and not(d):
+ return centaine[d2]+'s'
+ else:
+ return centaine[d2] or d
def _10000_to_text(chiffre):
- if chiffre==0:
- return 'zero'
- part1 = _1000_to_text(chiffre % 1000)
- part2 = mille.get(chiffre / 1000, _1000_to_text(chiffre / 1000)+' mille')
- if part2 and part1:
- part1 = ' '+part1
- return part2+part1
+ if chiffre==0:
+ return 'zero'
+ part1 = _1000_to_text(chiffre % 1000)
+ part2 = mille.get(chiffre / 1000, _1000_to_text(chiffre / 1000)+' mille')
+ if part2 and part1:
+ part1 = ' '+part1
+ return part2+part1
def int_to_text(i):
- return _10000_to_text(i)
+ return _10000_to_text(i)
if __name__=='__main__':
- for i in range(1,999999,139):
- print int_to_text(i)
+ for i in range(1,999999,139):
+ print int_to_text(i)
diff --git a/bin/report/interface.py b/bin/report/interface.py
index 63757ad6151..0ed5b73a07c 100644
--- a/bin/report/interface.py
+++ b/bin/report/interface.py
@@ -46,187 +46,187 @@ import urllib
# encode a value to a string in utf8 and converts XML entities
#
def toxml(val):
- if isinstance(val, str):
- str_utf8 = val
- elif isinstance(val, unicode):
- str_utf8 = val.encode('utf-8')
- else:
- str_utf8 = str(val)
- return str_utf8.replace('&', '&amp;').replace('<','&lt;').replace('>','&gt;')
+ if isinstance(val, str):
+ str_utf8 = val
+ elif isinstance(val, unicode):
+ str_utf8 = val.encode('utf-8')
+ else:
+ str_utf8 = str(val)
+ return str_utf8.replace('&', '&amp;').replace('<','&lt;').replace('>','&gt;')
class report_int(netsvc.Service):
- def __init__(self, name, audience='*'):
- assert not netsvc.service_exist(name), 'The report "%s" already exist!' % name
- super(report_int, self).__init__(name, audience)
- if name[0:7]<>'report.':
- raise Exception, 'ConceptionError, bad report name, should start with "report."'
- self.name = name
- self.id = 0
- self.name2 = '.'.join(name.split('.')[1:])
- self.joinGroup('report')
- self.exportMethod(self.create)
-
- def create(self, cr, uid, ids, datas, context=None):
- return False
+ def __init__(self, name, audience='*'):
+ assert not netsvc.service_exist(name), 'The report "%s" already exist!' % name
+ super(report_int, self).__init__(name, audience)
+ if name[0:7]<>'report.':
+ raise Exception, 'ConceptionError, bad report name, should start with "report."'
+ self.name = name
+ self.id = 0
+ self.name2 = '.'.join(name.split('.')[1:])
+ self.joinGroup('report')
+ self.exportMethod(self.create)
+
+ def create(self, cr, uid, ids, datas, context=None):
+ return False
"""
- Class to automatically build a document using the transformation process:
- XML -> DATAS -> RML -> PDF
- -> HTML
- using a XSL:RML transformation
+ Class to automatically build a document using the transformation process:
+ XML -> DATAS -> RML -> PDF
+ -> HTML
+ using a XSL:RML transformation
"""
class report_rml(report_int):
- def __init__(self, name, table, tmpl, xsl):
- super(report_rml, self).__init__(name)
- self.table = table
- self.tmpl = tmpl
- self.xsl = xsl
- self.bin_datas = {}
- self.generators = {
- '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)
- report_type = datas.get('report_type', 'pdf')
- create_doc = self.generators[report_type]
- pdf = create_doc(rml)
- return (pdf, report_type)
-
- def create_xml(self, cr, uid, ids, datas, context=None):
- if not context:
- context={}
- doc = print_xml.document(cr, uid, datas, {})
- self.bin_datas.update( doc.bin_datas or {})
- doc.parse(self.tmpl, ids, self.table, context)
- xml = doc.xml_get()
- doc.close()
- return self.post_process_xml_data(cr, uid, xml, context)
-
- def post_process_xml_data(self, cr, uid, xml, context=None):
- if not context:
- context={}
- # find the position of the 3rd tag
- # (skip the <?xml ...?> and the "root" tag)
- iter = re.finditer('<[^>]*>', xml)
- i = iter.next()
- i = iter.next()
- pos_xml = i.end()
-
- doc = print_xml.document(cr, uid, {}, {})
- tmpl_path = addons.get_module_resource('custom', 'corporate_defaults.xml')
- doc.parse(tmpl_path, [uid], 'res.users', context)
- corporate_header = doc.xml_get()
- doc.close()
-
- # find the position of the tag after the <?xml ...?> tag
- iter = re.finditer('<[^>]*>', corporate_header)
- i = iter.next()
- pos_header = i.end()
-
- return xml[:pos_xml] + corporate_header[pos_header:] + xml[pos_xml:]
-
- #
- # TODO: The translation doesn't work for "<tag t="1">textext<tag> tex</tag>text</tag>"
- #
- def create_rml(self, cr, xml, uid, context=None):
- if not context:
- context={}
- service = netsvc.LocalService("object_proxy")
-
- # In some case we might not use xsl ...
- if not self.xsl:
- return xml
-
- # load XSL (parse it to the XML level)
- styledoc = libxml2.parseDoc(tools.file_open(self.xsl).read())
- xsl_path, tail = os.path.split(self.xsl)
- for child in styledoc.children:
- if child.name == 'import':
- if child.hasProp('href'):
- imp_file = child.prop('href')
- _x, imp_file = tools.file_open(imp_file, subdir=xsl_path, pathinfo=True)
- child.setProp('href', urllib.quote(str(imp_file)))
-
- #TODO: get all the translation in one query. That means we have to:
- # * build a list of items to translate,
- # * issue the query to translate them,
- # * (re)build/update the stylesheet with the translated items
-
- # translate the XSL stylesheet
- def look_down(child, lang):
- while child is not None:
- if (child.type == "element") and child.hasProp('t'):
- #FIXME: use cursor
- res = service.execute(cr.dbname, uid, 'ir.translation',
- '_get_source', self.name2, 'xsl', lang, child.content)
- if res:
- child.setContent(res)
- look_down(child.children, lang)
- child = child.next
-
- if context.get('lang', False):
- look_down(styledoc.children, context['lang'])
-
- # parse XSL
- style = libxslt.parseStylesheetDoc(styledoc)
- # load XML (data)
- doc = libxml2.parseMemory(xml,len(xml))
- # create RML (apply XSL to XML data)
- result = style.applyStylesheet(doc, None)
- # save result to string
- xml = style.saveResultToString(result)
-
- style.freeStylesheet()
- doc.freeDoc()
- result.freeDoc()
- return xml
-
- def create_pdf(self, xml, logo=None):
- if logo:
- self.bin_datas['logo'] = logo
- else:
- if 'logo' in self.bin_datas:
- del self.bin_datas['logo']
- obj = render.rml(xml, self.bin_datas, tools.config['root_path'])
- obj.render()
- return obj.get()
-
- def create_html(self, xml, logo=None):
- obj = render.rml2html(xml, self.bin_datas)
- obj.render()
- return obj.get()
-
- def create_raw(self, xml, logo=None):
- return xml
-
- def create_sxw(self, path, logo=None):
- return path
+ def __init__(self, name, table, tmpl, xsl):
+ super(report_rml, self).__init__(name)
+ self.table = table
+ self.tmpl = tmpl
+ self.xsl = xsl
+ self.bin_datas = {}
+ self.generators = {
+ '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)
+ report_type = datas.get('report_type', 'pdf')
+ create_doc = self.generators[report_type]
+ pdf = create_doc(rml)
+ return (pdf, report_type)
+
+ def create_xml(self, cr, uid, ids, datas, context=None):
+ if not context:
+ context={}
+ doc = print_xml.document(cr, uid, datas, {})
+ self.bin_datas.update( doc.bin_datas or {})
+ doc.parse(self.tmpl, ids, self.table, context)
+ xml = doc.xml_get()
+ doc.close()
+ return self.post_process_xml_data(cr, uid, xml, context)
+
+ def post_process_xml_data(self, cr, uid, xml, context=None):
+ if not context:
+ context={}
+ # find the position of the 3rd tag
+ # (skip the <?xml ...?> and the "root" tag)
+ iter = re.finditer('<[^>]*>', xml)
+ i = iter.next()
+ i = iter.next()
+ pos_xml = i.end()
+
+ doc = print_xml.document(cr, uid, {}, {})
+ tmpl_path = addons.get_module_resource('custom', 'corporate_defaults.xml')
+ doc.parse(tmpl_path, [uid], 'res.users', context)
+ corporate_header = doc.xml_get()
+ doc.close()
+
+ # find the position of the tag after the <?xml ...?> tag
+ iter = re.finditer('<[^>]*>', corporate_header)
+ i = iter.next()
+ pos_header = i.end()
+
+ return xml[:pos_xml] + corporate_header[pos_header:] + xml[pos_xml:]
+
+ #
+ # TODO: The translation doesn't work for "<tag t="1">textext<tag> tex</tag>text</tag>"
+ #
+ def create_rml(self, cr, xml, uid, context=None):
+ if not context:
+ context={}
+ service = netsvc.LocalService("object_proxy")
+
+ # In some case we might not use xsl ...
+ if not self.xsl:
+ return xml
+
+ # load XSL (parse it to the XML level)
+ styledoc = libxml2.parseDoc(tools.file_open(self.xsl).read())
+ xsl_path, tail = os.path.split(self.xsl)
+ for child in styledoc.children:
+ if child.name == 'import':
+ if child.hasProp('href'):
+ imp_file = child.prop('href')
+ _x, imp_file = tools.file_open(imp_file, subdir=xsl_path, pathinfo=True)
+ child.setProp('href', urllib.quote(str(imp_file)))
+
+ #TODO: get all the translation in one query. That means we have to:
+ # * build a list of items to translate,
+ # * issue the query to translate them,
+ # * (re)build/update the stylesheet with the translated items
+
+ # translate the XSL stylesheet
+ def look_down(child, lang):
+ while child is not None:
+ if (child.type == "element") and child.hasProp('t'):
+ #FIXME: use cursor
+ res = service.execute(cr.dbname, uid, 'ir.translation',
+ '_get_source', self.name2, 'xsl', lang, child.content)
+ if res:
+ child.setContent(res)
+ look_down(child.children, lang)
+ child = child.next
+
+ if context.get('lang', False):
+ look_down(styledoc.children, context['lang'])
+
+ # parse XSL
+ style = libxslt.parseStylesheetDoc(styledoc)
+ # load XML (data)
+ doc = libxml2.parseMemory(xml,len(xml))
+ # create RML (apply XSL to XML data)
+ result = style.applyStylesheet(doc, None)
+ # save result to string
+ xml = style.saveResultToString(result)
+
+ style.freeStylesheet()
+ doc.freeDoc()
+ result.freeDoc()
+ return xml
+
+ def create_pdf(self, xml, logo=None):
+ if logo:
+ self.bin_datas['logo'] = logo
+ else:
+ if 'logo' in self.bin_datas:
+ del self.bin_datas['logo']
+ obj = render.rml(xml, self.bin_datas, tools.config['root_path'])
+ obj.render()
+ return obj.get()
+
+ def create_html(self, xml, logo=None):
+ obj = render.rml2html(xml, self.bin_datas)
+ obj.render()
+ return obj.get()
+
+ def create_raw(self, xml, logo=None):
+ return xml
+
+ def create_sxw(self, path, logo=None):
+ return path
from report_sxw import report_sxw
def register_all(db):
- opj = os.path.join
- cr = db.cursor()
- cr.execute("SELECT * FROM ir_act_report_xml WHERE auto ORDER BY id")
- result = cr.dictfetchall()
- cr.close()
- for r in result:
- if netsvc.service_exist('report.'+r['report_name']):
- continue
- if r['report_rml'] or r['report_rml_content_data']:
- report_sxw('report.'+r['report_name'], r['model'],
- opj('addons',r['report_rml'] or '/'), header=r['header'])
- if r['report_xsl']:
- report_rml('report.'+r['report_name'], r['model'],
- opj('addons',r['report_xml']),
- r['report_xsl'] and opj('addons',r['report_xsl']))
+ opj = os.path.join
+ cr = db.cursor()
+ cr.execute("SELECT * FROM ir_act_report_xml WHERE auto ORDER BY id")
+ result = cr.dictfetchall()
+ cr.close()
+ for r in result:
+ if netsvc.service_exist('report.'+r['report_name']):
+ continue
+ if r['report_rml'] or r['report_rml_content_data']:
+ report_sxw('report.'+r['report_name'], r['model'],
+ opj('addons',r['report_rml'] or '/'), header=r['header'])
+ if r['report_xsl']:
+ report_rml('report.'+r['report_name'], r['model'],
+ opj('addons',r['report_xml']),
+ r['report_xsl'] and opj('addons',r['report_xsl']))
diff --git a/bin/report/misc.py b/bin/report/misc.py
index 03df9d98c1b..a5926d65e28 100644
--- a/bin/report/misc.py
+++ b/bin/report/misc.py
@@ -28,14 +28,14 @@
from pychart import *
colorline = [color.T(r=((r+3) % 11)/10.0,
- g=((g+6) % 11)/10.0,
- b=((b+9) % 11)/10.0)
- for r in range(11) for g in range(11) for b in range(11)]
+ g=((g+6) % 11)/10.0,
+ b=((b+9) % 11)/10.0)
+ for r in range(11) for g in range(11) for b in range(11)]
def choice_colors(n):
- if n:
- return colorline[0:-1:len(colorline)/n]
- return []
+ if n:
+ return colorline[0:-1:len(colorline)/n]
+ return []
if __name__=='__main__':
- print choice_colors(10)
+ print choice_colors(10)
diff --git a/bin/report/print_fnc.py b/bin/report/print_fnc.py
index ae9a0c63b45..081222b758d 100644
--- a/bin/report/print_fnc.py
+++ b/bin/report/print_fnc.py
@@ -30,13 +30,13 @@
import time
functions = {
- 'today': lambda x: time.strftime('%d/%m/%Y', time.localtime()).decode('latin1')
+ 'today': lambda x: time.strftime('%d/%m/%Y', time.localtime()).decode('latin1')
}
#
# TODO: call an object internal function too
#
def print_fnc(fnc, arg):
- if fnc in functions:
- return functions[fnc](arg)
- return ''
+ if fnc in functions:
+ return functions[fnc](arg)
+ return ''
diff --git a/bin/report/print_xml.py b/bin/report/print_xml.py
index 75c700e3927..3be8b5419c4 100644
--- a/bin/report/print_xml.py
+++ b/bin/report/print_xml.py
@@ -38,85 +38,85 @@ from osv.orm import browse_null, browse_record
import pooler
class InheritDict(dict):
- # Might be usefull when we're doing name lookup for call or eval.
+ # Might be usefull when we're doing name lookup for call or eval.
- def __init__(self, parent=None):
- self.parent = parent
-
- def __getitem__(self, name):
- if name in self:
- return super(InheritDict, self).__getitem__(name)
- else:
- if not self.parent:
- raise KeyError
- else:
- return self.parent[name]
+ def __init__(self, parent=None):
+ self.parent = parent
+
+ def __getitem__(self, name):
+ if name in self:
+ return super(InheritDict, self).__getitem__(name)
+ else:
+ if not self.parent:
+ raise KeyError
+ else:
+ return self.parent[name]
def tounicode(val):
- if isinstance(val, str):
- unicode_val = unicode(val, 'utf-8')
- elif isinstance(val, unicode):
- unicode_val = val
- else:
- unicode_val = unicode(val)
- return unicode_val
+ if isinstance(val, str):
+ unicode_val = unicode(val, 'utf-8')
+ elif isinstance(val, unicode):
+ unicode_val = val
+ else:
+ unicode_val = unicode(val)
+ return unicode_val
class document(object):
- def __init__(self, cr, uid, datas, func=False):
- # create a new document
- self.cr = cr
- self.pool = pooler.get_pool(cr.dbname)
- self.doc = minidom.Document()
- self.func = func or {}
- self.datas = datas
- self.uid = uid
- self.bin_datas = {}
+ def __init__(self, cr, uid, datas, func=False):
+ # create a new document
+ self.cr = cr
+ self.pool = pooler.get_pool(cr.dbname)
+ self.doc = minidom.Document()
+ self.func = func or {}
+ self.datas = datas
+ self.uid = uid
+ self.bin_datas = {}
- def node_attrs_get(self, node):
- attrs = {}
- nattr = node.attributes
- for i in range(nattr.length):
- attr = nattr.item(i)
- attrs[attr.localName] = attr.nodeValue
-# attrs[attr.name] = attr.nodeValue
- return attrs
-
- def get_value(self, browser, field_path):
- fields = field_path.split('.')
+ def node_attrs_get(self, node):
+ attrs = {}
+ nattr = node.attributes
+ for i in range(nattr.length):
+ attr = nattr.item(i)
+ attrs[attr.localName] = attr.nodeValue
+# attrs[attr.name] = attr.nodeValue
+ return attrs
+
+ def get_value(self, browser, field_path):
+ 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 ''
- else:
- value = value[f]
-
- if isinstance(value, browse_null) or (type(value)==bool and not value):
- return ''
- else:
- return value
-
- def get_value2(self, browser, field_path):
- value = self.get_value(browser, field_path)
- if isinstance(value, browse_record):
- return value.id
- elif isinstance(value, browse_null):
- return False
- else:
- return value
-
- def eval(self, record, expr):
+ 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 ''
+ else:
+ value = value[f]
+
+ if isinstance(value, browse_null) or (type(value)==bool and not value):
+ return ''
+ else:
+ return value
+
+ def get_value2(self, browser, field_path):
+ value = self.get_value(browser, field_path)
+ if isinstance(value, browse_record):
+ return value.id
+ elif isinstance(value, browse_null):
+ return False
+ else:
+ return value
+
+ def eval(self, record, expr):
#TODO: support remote variables (eg address.title) in expr
# how to do that: parse the string, find dots, replace those dotted variables by temporary
# "simple ones", fetch the value of those variables and add them (temporarily) to the _data
@@ -126,239 +126,239 @@ class document(object):
# happen if the eval node is the first one using this browse_record
# the next line is a workaround for the problem: it causes the resource to be loaded
#Pinky: Why not this ? eval(expr, browser) ?
-# name = browser.name
-# data_dict = browser._data[self.get_value(browser, 'id')]
- return eval(expr)
+# name = browser.name
+# data_dict = browser._data[self.get_value(browser, 'id')]
+ return eval(expr)
- def parse_node(self, node, parent, browser, datas=None):
- # node is the node of the xml template to be parsed
- # 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
-
- attrs = self.node_attrs_get(node)
- if 'type' in attrs:
- if attrs['type']=='field':
- value = self.get_value(browser, attrs['name'])
+ def parse_node(self, node, parent, browser, datas=None):
+ # node is the node of the xml template to be parsed
+ # 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
+
+ attrs = self.node_attrs_get(node)
+ if 'type' in attrs:
+ if attrs['type']=='field':
+ value = self.get_value(browser, attrs['name'])
#TODO: test this
- if value == '' and 'default' in attrs:
- value = attrs['default']
- el = self.doc.createElement(node.localName)
- parent.appendChild(el)
- el_txt = self.doc.createTextNode(tounicode(value))
- el.appendChild(el_txt)
+ if value == '' and 'default' in attrs:
+ value = attrs['default']
+ el = self.doc.createElement(node.localName)
+ parent.appendChild(el)
+ el_txt = self.doc.createTextNode(tounicode(value))
+ el.appendChild(el_txt)
#TODO: test this
- for key, value in attrs.iteritems():
- if key not in ('type', 'name', 'default'):
- el.setAttribute(key, value)
+ for key, value in attrs.iteritems():
+ if key not in ('type', 'name', 'default'):
+ el.setAttribute(key, value)
- elif attrs['type']=='attachment':
- if isinstance(browser, list):
- model = browser[0]._table_name
- else:
- model = browser._table_name
+ elif attrs['type']=='attachment':
+ if isinstance(browser, list):
+ model = browser[0]._table_name
+ else:
+ model = browser._table_name
- value = self.get_value(browser, attrs['name'])
-
- service = netsvc.LocalService("object_proxy")
- ids = service.execute(self.cr.dbname, self.uid, 'ir.attachment', 'search', [('res_model','=',model),('res_id','=',int(value))])
- datas = service.execute(self.cr.dbname, self.uid, 'ir.attachment', 'read', ids)
-
- if len(datas):
- # if there are several, pick first
- datas = datas[0]
- fname = str(datas['datas_fname'])
- ext = fname.split('.')[-1].lower()
- if ext in ('jpg','jpeg', 'png'):
- import base64, StringIO
- dt = base64.decodestring(datas['datas'])
- fp = StringIO.StringIO(dt)
- i = str(len(self.bin_datas))
- self.bin_datas[i] = fp
-
- el = self.doc.createElement(node.localName)
- parent.appendChild(el)
- # node content is the length of the image
- el_txt = self.doc.createTextNode(i)
- el.appendChild(el_txt)
-
- elif attrs['type']=='data':
+ value = self.get_value(browser, attrs['name'])
+
+ service = netsvc.LocalService("object_proxy")
+ ids = service.execute(self.cr.dbname, self.uid, 'ir.attachment', 'search', [('res_model','=',model),('res_id','=',int(value))])
+ datas = service.execute(self.cr.dbname, self.uid, 'ir.attachment', 'read', ids)
+
+ if len(datas):
+ # if there are several, pick first
+ datas = datas[0]
+ fname = str(datas['datas_fname'])
+ ext = fname.split('.')[-1].lower()
+ if ext in ('jpg','jpeg', 'png'):
+ import base64, StringIO
+ dt = base64.decodestring(datas['datas'])
+ fp = StringIO.StringIO(dt)
+ i = str(len(self.bin_datas))
+ self.bin_datas[i] = fp
+
+ el = self.doc.createElement(node.localName)
+ parent.appendChild(el)
+ # node content is the length of the image
+ el_txt = self.doc.createTextNode(i)
+ el.appendChild(el_txt)
+
+ elif attrs['type']=='data':
#TODO: test this
- el = self.doc.createElement(node.localName)
- parent.appendChild(el)
- txt = self.datas.get('form', {}).get(attrs['name'], '')
- el_txt = self.doc.createTextNode(tounicode(txt))
- el.appendChild(el_txt)
+ el = self.doc.createElement(node.localName)
+ parent.appendChild(el)
+ txt = self.datas.get('form', {}).get(attrs['name'], '')
+ el_txt = self.doc.createTextNode(tounicode(txt))
+ el.appendChild(el_txt)
- elif attrs['type']=='function':
- el = self.doc.createElement(node.localName)
- parent.appendChild(el)
- if attrs['name'] in self.func:
- txt = self.func[attrs['name']](node)
- else:
- txt = print_fnc.print_fnc(attrs['name'], node)
- el_txt = self.doc.createTextNode(txt)
- el.appendChild(el_txt)
+ elif attrs['type']=='function':
+ el = self.doc.createElement(node.localName)
+ parent.appendChild(el)
+ if attrs['name'] in self.func:
+ txt = self.func[attrs['name']](node)
+ else:
+ txt = print_fnc.print_fnc(attrs['name'], node)
+ el_txt = self.doc.createTextNode(txt)
+ el.appendChild(el_txt)
- elif attrs['type']=='eval':
+ 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'])
- el_txt = self.doc.createTextNode(str(value))
- el.appendChild(el_txt)
+ if isinstance(browser, list):
+ print "ERROR: EVAL!"
+ el = self.doc.createElement(node.localName)
+ parent.appendChild(el)
+ value = self.eval(browser, attrs['expr'])
+ el_txt = self.doc.createTextNode(str(value))
+ el.appendChild(el_txt)
- elif attrs['type']=='fields':
- fields = attrs['name'].split(',')
- vals = {}
- for b in browser:
- value = tuple([self.get_value2(b, f) for f in fields])
- if not value in vals:
- vals[value]=[]
- vals[value].append(b)
- keys = vals.keys()
- keys.sort()
+ elif attrs['type']=='fields':
+ fields = attrs['name'].split(',')
+ vals = {}
+ for b in browser:
+ value = tuple([self.get_value2(b, f) for f in fields])
+ if not value in vals:
+ vals[value]=[]
+ vals[value].append(b)
+ keys = vals.keys()
+ keys.sort()
- if 'order' in attrs and attrs['order']=='desc':
- keys.reverse()
+ if 'order' in attrs and attrs['order']=='desc':
+ keys.reverse()
- v_list = [vals[k] for k in keys]
- for v in v_list:
- el = self.doc.createElement(node.localName)
- parent.appendChild(el)
- el_cld = node.firstChild
- while el_cld:
- self.parse_node(el_cld, el, v)
- el_cld = el_cld.nextSibling
+ v_list = [vals[k] for k in keys]
+ for v in v_list:
+ el = self.doc.createElement(node.localName)
+ parent.appendChild(el)
+ el_cld = node.firstChild
+ while el_cld:
+ self.parse_node(el_cld, el, v)
+ el_cld = el_cld.nextSibling
- elif attrs['type']=='call':
- if len(attrs['args']):
-#TODO: test this
- # fetches the values of the variables which names where passed in the args attribute
- args = [self.eval(browser, arg) for arg in attrs['args'].split(',')]
- else:
- args = []
-
- # get the object
- if attrs.has_key('model'):
- obj = self.pool.get(attrs['model'])
- else:
- if isinstance(browser, list):
- obj = browser[0]._table
- else:
- obj = browser._table
+ elif attrs['type']=='call':
+ if len(attrs['args']):
+#TODO: test this
+ # fetches the values of the variables which names where passed in the args attribute
+ args = [self.eval(browser, arg) for arg in attrs['args'].split(',')]
+ else:
+ args = []
+
+ # get the object
+ if attrs.has_key('model'):
+ obj = self.pool.get(attrs['model'])
+ else:
+ if isinstance(browser, list):
+ obj = browser[0]._table
+ else:
+ obj = browser._table
- # get the ids
- if attrs.has_key('ids'):
- ids = self.eval(browser, attrs['ids'])
- else:
- if isinstance(browser, list):
- ids = [b.id for b in browser]
- else:
- ids = [browser.id]
-
- # call the method itself
- newdatas = getattr(obj, attrs['name'])(self.cr, self.uid, ids, *args)
-
- def parse_result_tree(node, parent, datas):
- if node.nodeType == node.ELEMENT_NODE:
- el = self.doc.createElement(node.localName)
- 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:
- txt = self.doc.createTextNode(datas[atr['value']].decode('utf-8'))
- el.appendChild(txt)
- else:
- el_cld = node.firstChild
- while el_cld:
- parse_result_tree(el_cld, el, datas)
- el_cld = el_cld.nextSibling
- elif node.nodeType==node.TEXT_NODE:
- el = self.doc.createTextNode(node.nodeValue)
- parent.appendChild(el)
- else:
- pass
-
- if not isinstance(newdatas, list):
- newdatas = [newdatas]
- for newdata in newdatas:
- parse_result_tree(node, parent, newdata)
+ # get the ids
+ if attrs.has_key('ids'):
+ ids = self.eval(browser, attrs['ids'])
+ else:
+ if isinstance(browser, list):
+ ids = [b.id for b in browser]
+ else:
+ ids = [browser.id]
+
+ # call the method itself
+ newdatas = getattr(obj, attrs['name'])(self.cr, self.uid, ids, *args)
+
+ def parse_result_tree(node, parent, datas):
+ if node.nodeType == node.ELEMENT_NODE:
+ el = self.doc.createElement(node.localName)
+ 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:
+ txt = self.doc.createTextNode(datas[atr['value']].decode('utf-8'))
+ el.appendChild(txt)
+ else:
+ el_cld = node.firstChild
+ while el_cld:
+ parse_result_tree(el_cld, el, datas)
+ el_cld = el_cld.nextSibling
+ elif node.nodeType==node.TEXT_NODE:
+ el = self.doc.createTextNode(node.nodeValue)
+ parent.appendChild(el)
+ else:
+ pass
+
+ if not isinstance(newdatas, list):
+ newdatas = [newdatas]
+ for newdata in newdatas:
+ parse_result_tree(node, parent, newdata)
- elif attrs['type']=='zoom':
- value = self.get_value(browser, attrs['name'])
-
- if value:
- if not isinstance(value, list):
- v_list = [value]
- else:
- v_list = value
- for v in v_list:
- el = self.doc.createElement(node.localName)
- parent.appendChild(el)
- el_cld = node.firstChild
- while el_cld:
- self.parse_node(el_cld, el, v)
- el_cld = el_cld.nextSibling
- else:
- # if there is no "type" attribute in the node, copy it to the xml data and parse its childs
- el = self.doc.createElement(node.localName)
- parent.appendChild(el)
- el_cld = node.firstChild
- while el_cld:
- self.parse_node(el_cld, el, browser)
- el_cld = el_cld.nextSibling
+ elif attrs['type']=='zoom':
+ value = self.get_value(browser, attrs['name'])
+
+ if value:
+ if not isinstance(value, list):
+ v_list = [value]
+ else:
+ v_list = value
+ for v in v_list:
+ el = self.doc.createElement(node.localName)
+ parent.appendChild(el)
+ el_cld = node.firstChild
+ while el_cld:
+ self.parse_node(el_cld, el, v)
+ el_cld = el_cld.nextSibling
+ else:
+ # if there is no "type" attribute in the node, copy it to the xml data and parse its childs
+ el = self.doc.createElement(node.localName)
+ parent.appendChild(el)
+ el_cld = node.firstChild
+ while el_cld:
+ self.parse_node(el_cld, el, browser)
+ el_cld = el_cld.nextSibling
- elif node.nodeType==node.TEXT_NODE:
- # if it's a text node, copy it to the xml data
- el = self.doc.createTextNode(node.nodeValue)
- parent.appendChild(el)
- else:
- pass
+ elif node.nodeType==node.TEXT_NODE:
+ # if it's a text node, copy it to the xml data
+ el = self.doc.createTextNode(node.nodeValue)
+ parent.appendChild(el)
+ else:
+ pass
- def xml_get(self):
- return self.doc.toxml('utf-8')
+ def xml_get(self):
+ return self.doc.toxml('utf-8')
- def parse_tree(self, ids, model, context=None):
- if not context:
- context={}
- browser = self.pool.get(model).browse(self.cr, self.uid, ids, context)
- self.parse_node(self.dom.documentElement, self.doc, browser)
-
- def parse_string(self, xml, ids, model, context=None):
- if not context:
- context={}
- # parses the xml template to memory
- self.dom = minidom.parseString(xml)
-
- # create the xml data from the xml template
- self.parse_tree(ids, model, context)
+ def parse_tree(self, ids, model, context=None):
+ if not context:
+ context={}
+ browser = self.pool.get(model).browse(self.cr, self.uid, ids, context)
+ self.parse_node(self.dom.documentElement, self.doc, browser)
+
+ def parse_string(self, xml, ids, model, context=None):
+ if not context:
+ context={}
+ # parses the xml template to memory
+ self.dom = minidom.parseString(xml)
+
+ # create the xml data from the xml template
+ self.parse_tree(ids, model, context)
- def parse(self, filename, ids, model, context=None):
- if not context:
- context={}
- # parses the xml template to memory
- self.dom = minidom.parseString(tools.file_open(filename).read())
+ def parse(self, filename, ids, model, context=None):
+ if not context:
+ context={}
+ # parses the xml template to memory
+ self.dom = minidom.parseString(tools.file_open(filename).read())
- # create the xml data from the xml template
- self.parse_tree(ids, model, context)
+ # create the xml data from the xml template
+ self.parse_tree(ids, model, context)
- def close(self):
- self.doc = None
- self.dom = None
+ def close(self):
+ self.doc = None
+ self.dom = None
diff --git a/bin/report/printscreen/ps_form.py b/bin/report/printscreen/ps_form.py
index 2555ba1206a..f7bf398e61e 100644
--- a/bin/report/printscreen/ps_form.py
+++ b/bin/report/printscreen/ps_form.py
@@ -40,123 +40,123 @@ import libxslt
import time, os
class report_printscreen_list(report_int):
- def __init__(self, name):
- report_int.__init__(self, name)
-
- def _parse_node(self, root_node):
- result = []
- for node in root_node.childNodes:
- if node.localName == 'field':
- attrsa = node.attributes
- attrs = {}
- if not attrsa is None:
- for i in range(attrsa.length):
- attrs[attrsa.item(i).localName] = attrsa.item(i).nodeValue
- result.append(attrs['name'])
- else:
- result.extend(self._parse_node(node))
- return result
-
- def _parse_string(self, view):
- dom = minidom.parseString(view)
- return self._parse_node(dom)
-
- def create(self, cr, uid, ids, datas, context=None):
- if not context:
- context={}
- datas['ids'] = ids
- pool = pooler.get_pool(cr.dbname)
- model_id = pool.get('ir.model').search(cr, uid, [('model','=',model._name)])
- if model_id:
- model_desc = pool.get('ir.model').browse(cr, uid, model_id, context).name
- else:
- model_desc = model._description
-
- model = pool.get(datas['model'])
- result = model.fields_view_get(cr, uid, view_type='tree', context=context)
-
- fields_order = self._parse_string(result['arch'])
- rows = model.read(cr, uid, datas['ids'], result['fields'].keys() )
- res = self._create_table(uid, datas['ids'], result['fields'], fields_order, rows, context, model._description)
- return (self.obj.get(), 'pdf')
-
-
- def _create_table(self, uid, ids, fields, fields_order, results, context, title=''):
- pageSize=[297.0,210.0]
-
- impl = minidom.getDOMImplementation()
- new_doc = impl.createDocument(None, "report", None)
-
- # build header
- config = new_doc.createElement("config")
-
- def _append_node(name, text):
- n = new_doc.createElement(name)
- t = new_doc.createTextNode(text)
- n.appendChild(t)
- config.appendChild(n)
-
- _append_node('date', time.strftime('%d/%m/%Y'))
- _append_node('PageSize', '%.2fmm,%.2fmm' % tuple(pageSize))
- _append_node('PageWidth', '%.2f' % (pageSize[0] * 2.8346,))
- _append_node('PageHeight', '%.2f' %(pageSize[1] * 2.8346,))
-
- _append_node('report-header', title)
-
- l = []
- t = 0
- strmax = (pageSize[0]-40) * 2.8346
- for f in fields_order:
- s = 0
- if fields[f]['type'] in ('date','time','float','integer'):
- s = 60
- strmax -= s
- else:
- t += fields[f].get('size', 56) / 28 + 1
- l.append(s)
- for pos in range(len(l)):
- if not l[pos]:
- s = fields[fields_order[pos]].get('size', 56) / 28 + 1
- l[pos] = strmax * s / t
- _append_node('tableSize', ','.join(map(str,l)) )
- new_doc.childNodes[0].appendChild(config)
- header = new_doc.createElement("header")
-
- for f in fields_order:
- field = new_doc.createElement("field")
- field_txt = new_doc.createTextNode(str(fields[f]['string']))
- field.appendChild(field_txt)
- header.appendChild(field)
-
- new_doc.childNodes[0].appendChild(header)
-
- lines = new_doc.createElement("lines")
- for line in results:
- node_line = new_doc.createElement("row")
- for f in fields_order:
- if fields[f]['type']=='many2one' and line[f]:
- line[f] = line[f][1]
- if fields[f]['type'] in ('one2many','many2many') and line[f]:
- line[f] = '( '+str(len(line[f])) + ' )'
- col = new_doc.createElement("col")
- col.setAttribute('tree','no')
- if line[f] != None:
- txt = new_doc.createTextNode(str(line[f] or ''))
- else:
- txt = new_doc.createTextNode('/')
- col.appendChild(txt)
- node_line.appendChild(col)
- lines.appendChild(node_line)
- new_doc.childNodes[0].appendChild(lines)
-
- styledoc = libxml2.parseFile(os.path.join(tools.config['root_path'],'addons/base/report/custom_new.xsl'))
- style = libxslt.parseStylesheetDoc(styledoc)
- doc = libxml2.parseDoc(new_doc.toxml())
- rml_obj = style.applyStylesheet(doc, None)
- rml = style.saveResultToString(rml_obj)
-
- self.obj = render.rml(rml)
- self.obj.render()
- return True
+ def __init__(self, name):
+ report_int.__init__(self, name)
+
+ def _parse_node(self, root_node):
+ result = []
+ for node in root_node.childNodes:
+ if node.localName == 'field':
+ attrsa = node.attributes
+ attrs = {}
+ if not attrsa is None:
+ for i in range(attrsa.length):
+ attrs[attrsa.item(i).localName] = attrsa.item(i).nodeValue
+ result.append(attrs['name'])
+ else:
+ result.extend(self._parse_node(node))
+ return result
+
+ def _parse_string(self, view):
+ dom = minidom.parseString(view)
+ return self._parse_node(dom)
+
+ def create(self, cr, uid, ids, datas, context=None):
+ if not context:
+ context={}
+ datas['ids'] = ids
+ pool = pooler.get_pool(cr.dbname)
+ model_id = pool.get('ir.model').search(cr, uid, [('model','=',model._name)])
+ if model_id:
+ model_desc = pool.get('ir.model').browse(cr, uid, model_id, context).name
+ else:
+ model_desc = model._description
+
+ model = pool.get(datas['model'])
+ result = model.fields_view_get(cr, uid, view_type='tree', context=context)
+
+ fields_order = self._parse_string(result['arch'])
+ rows = model.read(cr, uid, datas['ids'], result['fields'].keys() )
+ res = self._create_table(uid, datas['ids'], result['fields'], fields_order, rows, context, model._description)
+ return (self.obj.get(), 'pdf')
+
+
+ def _create_table(self, uid, ids, fields, fields_order, results, context, title=''):
+ pageSize=[297.0,210.0]
+
+ impl = minidom.getDOMImplementation()
+ new_doc = impl.createDocument(None, "report", None)
+
+ # build header
+ config = new_doc.createElement("config")
+
+ def _append_node(name, text):
+ n = new_doc.createElement(name)
+ t = new_doc.createTextNode(text)
+ n.appendChild(t)
+ config.appendChild(n)
+
+ _append_node('date', time.strftime('%d/%m/%Y'))
+ _append_node('PageSize', '%.2fmm,%.2fmm' % tuple(pageSize))
+ _append_node('PageWidth', '%.2f' % (pageSize[0] * 2.8346,))
+ _append_node('PageHeight', '%.2f' %(pageSize[1] * 2.8346,))
+
+ _append_node('report-header', title)
+
+ l = []
+ t = 0
+ strmax = (pageSize[0]-40) * 2.8346
+ for f in fields_order:
+ s = 0
+ if fields[f]['type'] in ('date','time','float','integer'):
+ s = 60
+ strmax -= s
+ else:
+ t += fields[f].get('size', 56) / 28 + 1
+ l.append(s)
+ for pos in range(len(l)):
+ if not l[pos]:
+ s = fields[fields_order[pos]].get('size', 56) / 28 + 1
+ l[pos] = strmax * s / t
+ _append_node('tableSize', ','.join(map(str,l)) )
+ new_doc.childNodes[0].appendChild(config)
+ header = new_doc.createElement("header")
+
+ for f in fields_order:
+ field = new_doc.createElement("field")
+ field_txt = new_doc.createTextNode(str(fields[f]['string']))
+ field.appendChild(field_txt)
+ header.appendChild(field)
+
+ new_doc.childNodes[0].appendChild(header)
+
+ lines = new_doc.createElement("lines")
+ for line in results:
+ node_line = new_doc.createElement("row")
+ for f in fields_order:
+ if fields[f]['type']=='many2one' and line[f]:
+ line[f] = line[f][1]
+ if fields[f]['type'] in ('one2many','many2many') and line[f]:
+ line[f] = '( '+str(len(line[f])) + ' )'
+ col = new_doc.createElement("col")
+ col.setAttribute('tree','no')
+ if line[f] != None:
+ txt = new_doc.createTextNode(str(line[f] or ''))
+ else:
+ txt = new_doc.createTextNode('/')
+ col.appendChild(txt)
+ node_line.appendChild(col)
+ lines.appendChild(node_line)
+ new_doc.childNodes[0].appendChild(lines)
+
+ styledoc = libxml2.parseFile(os.path.join(tools.config['root_path'],'addons/base/report/custom_new.xsl'))
+ style = libxslt.parseStylesheetDoc(styledoc)
+ doc = libxml2.parseDoc(new_doc.toxml())
+ rml_obj = style.applyStylesheet(doc, None)
+ rml = style.saveResultToString(rml_obj)
+
+ self.obj = render.rml(rml)
+ self.obj.render()
+ return True
report_printscreen_list('report.printscreen.form')
diff --git a/bin/report/printscreen/ps_list.py b/bin/report/printscreen/ps_list.py
index e3ce11c8f73..a355be15679 100644
--- a/bin/report/printscreen/ps_list.py
+++ b/bin/report/printscreen/ps_list.py
@@ -40,166 +40,166 @@ import libxslt
import time, os
class report_printscreen_list(report_int):
- def __init__(self, name):
- report_int.__init__(self, name)
-
- def _parse_node(self, root_node):
- result = []
- for node in root_node.childNodes:
- if node.localName == 'field':
- attrsa = node.attributes
- attrs = {}
- if not attrsa is None:
- for i in range(attrsa.length):
- attrs[attrsa.item(i).localName] = attrsa.item(i).nodeValue
- result.append(attrs['name'])
- else:
- result.extend(self._parse_node(node))
- return result
-
- def _parse_string(self, view):
- dom = minidom.parseString(unicode(view, 'utf-8').encode('utf-8'))
- return self._parse_node(dom)
-
- def create(self, cr, uid, ids, datas, context=None):
- if not context:
- context={}
- pool = pooler.get_pool(cr.dbname)
- model = pool.get(datas['model'])
- model_id = pool.get('ir.model').search(cr, uid, [('model','=',model._name)])
- if model_id:
- model_desc = pool.get('ir.model').browse(cr, uid, model_id[0], context).name
- else:
- model_desc = model._description
-
- datas['ids'] = ids
- model = pooler.get_pool(cr.dbname).get(datas['model'])
-
- result = model.fields_view_get(cr, uid, view_type='tree', context=context)
- fields_order = self._parse_string(result['arch'])
- rows = model.read(cr, uid, datas['ids'], result['fields'].keys(), context )
- res = self._create_table(uid, datas['ids'], result['fields'], fields_order, rows, context, model_desc)
- return (self.obj.get(), 'pdf')
-
-
- def _create_table(self, uid, ids, fields, fields_order, results, context, title=''):
- pageSize=[297.0, 210.0]
-
- impl = minidom.getDOMImplementation()
- new_doc = impl.createDocument(None, "report", None)
-
- # build header
- config = new_doc.createElement("config")
-
- def _append_node(name, text):
- n = new_doc.createElement(name)
- t = new_doc.createTextNode(text)
- n.appendChild(t)
- config.appendChild(n)
-
- _append_node('date', time.strftime('%d/%m/%Y'))
- _append_node('PageSize', '%.2fmm,%.2fmm' % tuple(pageSize))
- _append_node('PageWidth', '%.2f' % (pageSize[0] * 2.8346,))
- _append_node('PageHeight', '%.2f' %(pageSize[1] * 2.8346,))
-
- _append_node('report-header', title)
- l = []
- t = 0
- rowcount=0;
- strmax = (pageSize[0]-40) * 2.8346
- temp = []
- count = len(fields_order)
- for i in range(0,count):
- temp.append(0)
-
- ince = -1;
- for f in fields_order:
- s = 0
- ince += 1
- if fields[f]['type'] in ('date','time','float','integer'):
- s = 60
- strmax -= s
- if fields[f]['type'] in ('float','integer'):
- temp[ince]=1;
- else:
- t += fields[f].get('size', 80) / 28 + 1
-
- l.append(s)
-
- for pos in range(len(l)):
- if not l[pos]:
- s = fields[fields_order[pos]].get('size', 80) / 28 + 1
- l[pos] = strmax * s / t
-
- _append_node('tableSize', ','.join(map(str,l)) )
- new_doc.childNodes[0].appendChild(config)
- header = new_doc.createElement("header")
-
- for f in fields_order:
- field = new_doc.createElement("field")
- field_txt = new_doc.createTextNode(str(fields[f]['string'] or ''))
- field.appendChild(field_txt)
- header.appendChild(field)
-
- new_doc.childNodes[0].appendChild(header)
-
- lines = new_doc.createElement("lines")
-
- tsum = []
- count = len(fields_order)
- for i in range(0,count):
- tsum.append(0)
-
- for line in results:
- node_line = new_doc.createElement("row")
-
- count = -1
- for f in fields_order:
- count += 1
- if fields[f]['type']=='many2one' and line[f]:
- line[f] = line[f][1]
- if fields[f]['type'] in ('one2many','many2many') and line[f]:
- line[f] = '( '+str(len(line[f])) + ' )'
- col = new_doc.createElement("col")
- col.setAttribute('para','yes')
- col.setAttribute('tree','no')
- if line[f] != None:
- txt = new_doc.createTextNode(str(line[f] or ''))
- if temp[count] == 1:
- tsum[count] = tsum[count] + line[f];
-
- else:
- txt = new_doc.createTextNode('/')
- col.appendChild(txt)
- node_line.appendChild(col)
- lines.appendChild(node_line)
- node_line = new_doc.createElement("row")
- lines.appendChild(node_line)
- node_line = new_doc.createElement("row")
- for f in range(0,count+1):
- col = new_doc.createElement("col")
- col.setAttribute('para','yes')
- col.setAttribute('tree','no')
- if tsum[f] != None:
- txt = new_doc.createTextNode(str(tsum[f] or ''))
- else:
- txt = new_doc.createTextNode('/')
- if f == 0:
- txt = new_doc.createTextNode('Total')
-
- col.appendChild(txt)
- node_line.appendChild(col)
- lines.appendChild(node_line)
-
- new_doc.childNodes[0].appendChild(lines)
-
- styledoc = libxml2.parseFile(os.path.join(tools.config['root_path'],'addons/base/report/custom_new.xsl'))
- style = libxslt.parseStylesheetDoc(styledoc)
- doc = libxml2.parseDoc(new_doc.toxml())
- rml_obj = style.applyStylesheet(doc, None)
- rml = style.saveResultToString(rml_obj)
- self.obj = render.rml(rml)
- self.obj.render()
- return True
+ def __init__(self, name):
+ report_int.__init__(self, name)
+
+ def _parse_node(self, root_node):
+ result = []
+ for node in root_node.childNodes:
+ if node.localName == 'field':
+ attrsa = node.attributes
+ attrs = {}
+ if not attrsa is None:
+ for i in range(attrsa.length):
+ attrs[attrsa.item(i).localName] = attrsa.item(i).nodeValue
+ result.append(attrs['name'])
+ else:
+ result.extend(self._parse_node(node))
+ return result
+
+ def _parse_string(self, view):
+ dom = minidom.parseString(unicode(view, 'utf-8').encode('utf-8'))
+ return self._parse_node(dom)
+
+ def create(self, cr, uid, ids, datas, context=None):
+ if not context:
+ context={}
+ pool = pooler.get_pool(cr.dbname)
+ model = pool.get(datas['model'])
+ model_id = pool.get('ir.model').search(cr, uid, [('model','=',model._name)])
+ if model_id:
+ model_desc = pool.get('ir.model').browse(cr, uid, model_id[0], context).name
+ else:
+ model_desc = model._description
+
+ datas['ids'] = ids
+ model = pooler.get_pool(cr.dbname).get(datas['model'])
+
+ result = model.fields_view_get(cr, uid, view_type='tree', context=context)
+ fields_order = self._parse_string(result['arch'])
+ rows = model.read(cr, uid, datas['ids'], result['fields'].keys(), context )
+ res = self._create_table(uid, datas['ids'], result['fields'], fields_order, rows, context, model_desc)
+ return (self.obj.get(), 'pdf')
+
+
+ def _create_table(self, uid, ids, fields, fields_order, results, context, title=''):
+ pageSize=[297.0, 210.0]
+
+ impl = minidom.getDOMImplementation()
+ new_doc = impl.createDocument(None, "report", None)
+
+ # build header
+ config = new_doc.createElement("config")
+
+ def _append_node(name, text):
+ n = new_doc.createElement(name)
+ t = new_doc.createTextNode(text)
+ n.appendChild(t)
+ config.appendChild(n)
+
+ _append_node('date', time.strftime('%d/%m/%Y'))
+ _append_node('PageSize', '%.2fmm,%.2fmm' % tuple(pageSize))
+ _append_node('PageWidth', '%.2f' % (pageSize[0] * 2.8346,))
+ _append_node('PageHeight', '%.2f' %(pageSize[1] * 2.8346,))
+
+ _append_node('report-header', title)
+ l = []
+ t = 0
+ rowcount=0;
+ strmax = (pageSize[0]-40) * 2.8346
+ temp = []
+ count = len(fields_order)
+ for i in range(0,count):
+ temp.append(0)
+
+ ince = -1;
+ for f in fields_order:
+ s = 0
+ ince += 1
+ if fields[f]['type'] in ('date','time','float','integer'):
+ s = 60
+ strmax -= s
+ if fields[f]['type'] in ('float','integer'):
+ temp[ince]=1;
+ else:
+ t += fields[f].get('size', 80) / 28 + 1
+
+ l.append(s)
+
+ for pos in range(len(l)):
+ if not l[pos]:
+ s = fields[fields_order[pos]].get('size', 80) / 28 + 1
+ l[pos] = strmax * s / t
+
+ _append_node('tableSize', ','.join(map(str,l)) )
+ new_doc.childNodes[0].appendChild(config)
+ header = new_doc.createElement("header")
+
+ for f in fields_order:
+ field = new_doc.createElement("field")
+ field_txt = new_doc.createTextNode(str(fields[f]['string'] or ''))
+ field.appendChild(field_txt)
+ header.appendChild(field)
+
+ new_doc.childNodes[0].appendChild(header)
+
+ lines = new_doc.createElement("lines")
+
+ tsum = []
+ count = len(fields_order)
+ for i in range(0,count):
+ tsum.append(0)
+
+ for line in results:
+ node_line = new_doc.createElement("row")
+
+ count = -1
+ for f in fields_order:
+ count += 1
+ if fields[f]['type']=='many2one' and line[f]:
+ line[f] = line[f][1]
+ if fields[f]['type'] in ('one2many','many2many') and line[f]:
+ line[f] = '( '+str(len(line[f])) + ' )'
+ col = new_doc.createElement("col")
+ col.setAttribute('para','yes')
+ col.setAttribute('tree','no')
+ if line[f] != None:
+ txt = new_doc.createTextNode(str(line[f] or ''))
+ if temp[count] == 1:
+ tsum[count] = tsum[count] + line[f];
+
+ else:
+ txt = new_doc.createTextNode('/')
+ col.appendChild(txt)
+ node_line.appendChild(col)
+ lines.appendChild(node_line)
+ node_line = new_doc.createElement("row")
+ lines.appendChild(node_line)
+ node_line = new_doc.createElement("row")
+ for f in range(0,count+1):
+ col = new_doc.createElement("col")
+ col.setAttribute('para','yes')
+ col.setAttribute('tree','no')
+ if tsum[f] != None:
+ txt = new_doc.createTextNode(str(tsum[f] or ''))
+ else:
+ txt = new_doc.createTextNode('/')
+ if f == 0:
+ txt = new_doc.createTextNode('Total')
+
+ col.appendChild(txt)
+ node_line.appendChild(col)
+ lines.appendChild(node_line)
+
+ new_doc.childNodes[0].appendChild(lines)
+
+ styledoc = libxml2.parseFile(os.path.join(tools.config['root_path'],'addons/base/report/custom_new.xsl'))
+ style = libxslt.parseStylesheetDoc(styledoc)
+ doc = libxml2.parseDoc(new_doc.toxml())
+ rml_obj = style.applyStylesheet(doc, None)
+ rml = style.saveResultToString(rml_obj)
+ self.obj = render.rml(rml)
+ self.obj.render()
+ return True
report_printscreen_list('report.printscreen.list')
diff --git a/bin/report/render/__init__.py b/bin/report/render/__init__.py
index 92a9a2247d7..263bc3c3e13 100644
--- a/bin/report/render/__init__.py
+++ b/bin/report/render/__init__.py
@@ -33,6 +33,6 @@ from rml import rml, rml2html
from render import render
try:
- import Image
+ import Image
except:
- print 'WARNING; Python Imaging not installed, you can use only .JPG pictures !'
+ print 'WARNING; Python Imaging not installed, you can use only .JPG pictures !'
diff --git a/bin/report/render/render.py b/bin/report/render/render.py
index 7f0649075ef..ea03b3cfc32 100644
--- a/bin/report/render/render.py
+++ b/bin/report/render/render.py
@@ -44,38 +44,38 @@ import threading
# _render
#
class render(object):
- def __init__(self, bin_datas={}, path='.'):
- self.done = False
- self.bin_datas = bin_datas
- self.path = path
-
- def _render(self):
- return None
+ def __init__(self, bin_datas={}, path='.'):
+ self.done = False
+ self.bin_datas = bin_datas
+ self.path = path
+
+ def _render(self):
+ return None
- def render(self):
- self.done = False
- result = self._render()
- self._result = result
- self.done = True
- return True
-
- def is_done(self):
- res = self.done
- return res
+ def render(self):
+ self.done = False
+ result = self._render()
+ self._result = result
+ self.done = True
+ return True
+
+ def is_done(self):
+ res = self.done
+ return res
- def get(self):
- if self.is_done():
- return self._result
- else:
- return None
+ def get(self):
+ if self.is_done():
+ return self._result
+ else:
+ return None
if __name__=='__main__':
- import time
- print 'Multi-thread code !'
- r = render()
- r.render()
- while not r.is_done():
- print 'not yet!'
- time.sleep(1)
- print 'done!'
+ import time
+ print 'Multi-thread code !'
+ r = render()
+ r.render()
+ while not r.is_done():
+ print 'not yet!'
+ time.sleep(1)
+ print 'done!'
diff --git a/bin/report/render/rml.py b/bin/report/render/rml.py
index 6be8dc55969..b497fb7b4f7 100644
--- a/bin/report/render/rml.py
+++ b/bin/report/render/rml.py
@@ -32,20 +32,20 @@ import rml2pdf
import rml2html as htmlizer
class rml(render.render):
- def __init__(self, xml, datas={}, path='.'):
- render.render.__init__(self, datas)
- self.xml = xml
- self.output_type = 'pdf'
- self.path = path
+ def __init__(self, xml, datas={}, path='.'):
+ render.render.__init__(self, datas)
+ self.xml = xml
+ self.output_type = 'pdf'
+ self.path = path
- def _render(self):
- return rml2pdf.parseString(self.xml, images=self.bin_datas, path=self.path)
+ def _render(self):
+ return rml2pdf.parseString(self.xml, images=self.bin_datas, path=self.path)
class rml2html(render.render):
- def __init__(self, xml, datas={}):
- super(rml2html, self).__init__(datas)
- self.xml = xml
- self.output_type = 'html'
-
- def _render(self):
- return htmlizer.parseString(self.xml)
+ def __init__(self, xml, datas={}):
+ super(rml2html, self).__init__(datas)
+ self.xml = xml
+ self.output_type = 'html'
+
+ def _render(self):
+ return htmlizer.parseString(self.xml)
diff --git a/bin/report/render/rml2html/rml2html.py b/bin/report/render/rml2html/rml2html.py
index 3d0477e3c38..898d5c19ac9 100755..100644
--- a/bin/report/render/rml2html/rml2html.py
+++ b/bin/report/render/rml2html/rml2html.py
@@ -52,341 +52,341 @@ import copy
import utils
class _flowable(object):
- def __init__(self, template, doc):
- self._tags = {
- 'title': self._tag_title,
- 'spacer': self._tag_spacer,
- 'para': self._tag_para,
- 'nextFrame': self._tag_next_frame,
- 'blockTable': self._tag_table,
- 'pageBreak': self._tag_page_break,
- 'setNextTemplate': self._tag_next_template,
- }
- self.template = template
- self.doc = doc
-
- def _tag_page_break(self, node):
- return '<br/>'*3
-
- def _tag_next_template(self, node):
- return ''
-
- def _tag_next_frame(self, node):
- result=self.template.frame_stop()
- result+='<br/>'
- result+=self.template.frame_start()
- return result
-
- def _tag_title(self, node):
- node.tagName='h1'
- return node.toxml()
-
- def _tag_spacer(self, node):
- length = 1+int(utils.unit_get(node.getAttribute('length')))/35
- return "<br/>"*length
-
- def _tag_table(self, node):
- node.tagName='table'
- if node.hasAttribute('colWidths'):
- sizes = map(lambda x: utils.unit_get(x), node.getAttribute('colWidths').split(','))
- tr = self.doc.createElement('tr')
- for s in sizes:
- td = self.doc.createElement('td')
- td.setAttribute("width", str(s))
- tr.appendChild(td)
- node.appendChild(tr)
- return node.toxml()
-
- def _tag_para(self, node):
- node.tagName='p'
- if node.hasAttribute('style'):
- node.setAttribute('class', node.getAttribute('style'))
- return node.toxml()
-
- def render(self, node):
- result = self.template.start()
- result += self.template.frame_start()
- for n in node.childNodes:
- if n.nodeType==node.ELEMENT_NODE:
- if n.localName in self._tags:
- result += self._tags[n.localName](n)
- else:
- pass
- #print 'tag', n.localName, 'not yet implemented!'
- result += self.template.frame_stop()
- result += self.template.end()
- return result
+ def __init__(self, template, doc):
+ self._tags = {
+ 'title': self._tag_title,
+ 'spacer': self._tag_spacer,
+ 'para': self._tag_para,
+ 'nextFrame': self._tag_next_frame,
+ 'blockTable': self._tag_table,
+ 'pageBreak': self._tag_page_break,
+ 'setNextTemplate': self._tag_next_template,
+ }
+ self.template = template
+ self.doc = doc
+
+ def _tag_page_break(self, node):
+ return '<br/>'*3
+
+ def _tag_next_template(self, node):
+ return ''
+
+ def _tag_next_frame(self, node):
+ result=self.template.frame_stop()
+ result+='<br/>'
+ result+=self.template.frame_start()
+ return result
+
+ def _tag_title(self, node):
+ node.tagName='h1'
+ return node.toxml()
+
+ def _tag_spacer(self, node):
+ length = 1+int(utils.unit_get(node.getAttribute('length')))/35
+ return "<br/>"*length
+
+ def _tag_table(self, node):
+ node.tagName='table'
+ if node.hasAttribute('colWidths'):
+ sizes = map(lambda x: utils.unit_get(x), node.getAttribute('colWidths').split(','))
+ tr = self.doc.createElement('tr')
+ for s in sizes:
+ td = self.doc.createElement('td')
+ td.setAttribute("width", str(s))
+ tr.appendChild(td)
+ node.appendChild(tr)
+ return node.toxml()
+
+ def _tag_para(self, node):
+ node.tagName='p'
+ if node.hasAttribute('style'):
+ node.setAttribute('class', node.getAttribute('style'))
+ return node.toxml()
+
+ def render(self, node):
+ result = self.template.start()
+ result += self.template.frame_start()
+ for n in node.childNodes:
+ if n.nodeType==node.ELEMENT_NODE:
+ if n.localName in self._tags:
+ result += self._tags[n.localName](n)
+ else:
+ pass
+ #print 'tag', n.localName, 'not yet implemented!'
+ result += self.template.frame_stop()
+ result += self.template.end()
+ return result
class _rml_tmpl_tag(object):
- def __init__(self, *args):
- pass
- def tag_start(self):
- return ''
- def tag_end(self):
- return False
- def tag_stop(self):
- return ''
- def tag_mergeable(self):
- return True
+ def __init__(self, *args):
+ pass
+ def tag_start(self):
+ return ''
+ def tag_end(self):
+ return False
+ def tag_stop(self):
+ return ''
+ def tag_mergeable(self):
+ return True
class _rml_tmpl_frame(_rml_tmpl_tag):
- def __init__(self, posx, width):
- self.width = width
- self.posx = posx
- def tag_start(self):
- return '<table border="0" width="%d"><tr><td width="%d">&nbsp;</td><td>' % (self.width+self.posx,self.posx)
- def tag_end(self):
- return True
- def tag_stop(self):
- return '</td></tr></table><br/>'
- def tag_mergeable(self):
- return False
-
- # An awfull workaround since I don't really understand the semantic behind merge.
- def merge(self, frame):
- pass
+ def __init__(self, posx, width):
+ self.width = width
+ self.posx = posx
+ def tag_start(self):
+ return '<table border="0" width="%d"><tr><td width="%d">&nbsp;</td><td>' % (self.width+self.posx,self.posx)
+ def tag_end(self):
+ return True
+ def tag_stop(self):
+ return '</td></tr></table><br/>'
+ def tag_mergeable(self):
+ return False
+
+ # An awfull workaround since I don't really understand the semantic behind merge.
+ def merge(self, frame):
+ pass
class _rml_tmpl_draw_string(_rml_tmpl_tag):
- def __init__(self, node, style):
- self.posx = utils.unit_get(node.getAttribute('x'))
- self.posy = utils.unit_get(node.getAttribute('y'))
- aligns = {
- 'drawString': 'left',
- 'drawRightString': 'right',
- 'drawCentredString': 'center'
- }
- align = aligns[node.localName]
- self.pos = [(self.posx, self.posy, align, utils.text_get(node), style.get('td'), style.font_size_get('td'))]
-
- def tag_start(self):
- self.pos.sort()
- res = '<table border="0" cellpadding="0" cellspacing="0"><tr>'
- posx = 0
- i = 0
- for (x,y,align,txt, style, fs) in self.pos:
- if align=="left":
- pos2 = len(txt)*fs
- res+='<td width="%d"></td><td style="%s" width="%d">%s</td>' % (x - posx, style, pos2, txt)
- posx = x+pos2
- if align=="right":
- res+='<td width="%d" align="right" style="%s">%s</td>' % (x - posx, style, txt)
- posx = x
- if align=="center":
- res+='<td width="%d" align="center" style="%s">%s</td>' % ((x - posx)*2, style, txt)
- posx = 2*x-posx
- i+=1
- res+='</tr></table>'
- return res
- def merge(self, ds):
- self.pos+=ds.pos
+ def __init__(self, node, style):
+ self.posx = utils.unit_get(node.getAttribute('x'))
+ self.posy = utils.unit_get(node.getAttribute('y'))
+ aligns = {
+ 'drawString': 'left',
+ 'drawRightString': 'right',
+ 'drawCentredString': 'center'
+ }
+ align = aligns[node.localName]
+ self.pos = [(self.posx, self.posy, align, utils.text_get(node), style.get('td'), style.font_size_get('td'))]
+
+ def tag_start(self):
+ self.pos.sort()
+ res = '<table border="0" cellpadding="0" cellspacing="0"><tr>'
+ posx = 0
+ i = 0
+ for (x,y,align,txt, style, fs) in self.pos:
+ if align=="left":
+ pos2 = len(txt)*fs
+ res+='<td width="%d"></td><td style="%s" width="%d">%s</td>' % (x - posx, style, pos2, txt)
+ posx = x+pos2
+ if align=="right":
+ res+='<td width="%d" align="right" style="%s">%s</td>' % (x - posx, style, txt)
+ posx = x
+ if align=="center":
+ res+='<td width="%d" align="center" style="%s">%s</td>' % ((x - posx)*2, style, txt)
+ posx = 2*x-posx
+ i+=1
+ res+='</tr></table>'
+ return res
+ def merge(self, ds):
+ self.pos+=ds.pos
class _rml_tmpl_draw_lines(_rml_tmpl_tag):
- def __init__(self, node, style):
- coord = [utils.unit_get(x) for x in utils.text_get(node).split(' ')]
- self.ok = False
- self.posx = coord[0]
- self.posy = coord[1]
- self.width = coord[2]-coord[0]
- self.ok = coord[1]==coord[3]
- self.style = style
- self.style = style.get('hr')
-
- def tag_start(self):
- if self.ok:
- return '<table border="0" cellpadding="0" cellspacing="0" width="%d"><tr><td width="%d"></td><td><hr width="100%%" style="margin:0px; %s"></td></tr></table>' % (self.posx+self.width,self.posx,self.style)
- else:
- return ''
+ def __init__(self, node, style):
+ coord = [utils.unit_get(x) for x in utils.text_get(node).split(' ')]
+ self.ok = False
+ self.posx = coord[0]
+ self.posy = coord[1]
+ self.width = coord[2]-coord[0]
+ self.ok = coord[1]==coord[3]
+ self.style = style
+ self.style = style.get('hr')
+
+ def tag_start(self):
+ if self.ok:
+ return '<table border="0" cellpadding="0" cellspacing="0" width="%d"><tr><td width="%d"></td><td><hr width="100%%" style="margin:0px; %s"></td></tr></table>' % (self.posx+self.width,self.posx,self.style)
+ else:
+ return ''
class _rml_stylesheet(object):
- def __init__(self, stylesheet, doc):
- self.doc = doc
- self.attrs = {}
- self._tags = {
- 'fontSize': lambda x: ('font-size',str(utils.unit_get(x))+'px'),
- 'alignment': lambda x: ('text-align',str(x))
- }
- result = ''
- for ps in stylesheet.getElementsByTagName('paraStyle'):
- attr = {}
- attrs = ps.attributes
- for i in range(attrs.length):
- name = attrs.item(i).localName
- attr[name] = ps.getAttribute(name)
- attrs = []
- for a in attr:
- if a in self._tags:
- attrs.append("%s:%s" % self._tags[a](attr[a]))
- if len(attrs):
- result += "p."+attr['name']+" {"+'; '.join(attrs)+"}\n"
- self.result = result
-
- def render(self):
- return self.result
+ def __init__(self, stylesheet, doc):
+ self.doc = doc
+ self.attrs = {}
+ self._tags = {
+ 'fontSize': lambda x: ('font-size',str(utils.unit_get(x))+'px'),
+ 'alignment': lambda x: ('text-align',str(x))
+ }
+ result = ''
+ for ps in stylesheet.getElementsByTagName('paraStyle'):
+ attr = {}
+ attrs = ps.attributes
+ for i in range(attrs.length):
+ name = attrs.item(i).localName
+ attr[name] = ps.getAttribute(name)
+ attrs = []
+ for a in attr:
+ if a in self._tags:
+ attrs.append("%s:%s" % self._tags[a](attr[a]))
+ if len(attrs):
+ result += "p."+attr['name']+" {"+'; '.join(attrs)+"}\n"
+ self.result = result
+
+ def render(self):
+ return self.result
class _rml_draw_style(object):
- def __init__(self):
- self.style = {}
- self._styles = {
- 'fill': lambda x: {'td': {'color':x.getAttribute('color')}},
- 'setFont': lambda x: {'td': {'font-size':x.getAttribute('size')+'px'}},
- 'stroke': lambda x: {'hr': {'color':x.getAttribute('color')}},
- }
- def update(self, node):
- if node.localName in self._styles:
- result = self._styles[node.localName](node)
- for key in result:
- if key in self.style:
- self.style[key].update(result[key])
- else:
- self.style[key] = result[key]
- def font_size_get(self,tag):
- size = utils.unit_get(self.style.get('td', {}).get('font-size','16'))
- return size
-
- def get(self,tag):
- if not tag in self.style:
- return ""
- return ';'.join(['%s:%s' % (x[0],x[1]) for x in self.style[tag].items()])
+ def __init__(self):
+ self.style = {}
+ self._styles = {
+ 'fill': lambda x: {'td': {'color':x.getAttribute('color')}},
+ 'setFont': lambda x: {'td': {'font-size':x.getAttribute('size')+'px'}},
+ 'stroke': lambda x: {'hr': {'color':x.getAttribute('color')}},
+ }
+ def update(self, node):
+ if node.localName in self._styles:
+ result = self._styles[node.localName](node)
+ for key in result:
+ if key in self.style:
+ self.style[key].update(result[key])
+ else:
+ self.style[key] = result[key]
+ def font_size_get(self,tag):
+ size = utils.unit_get(self.style.get('td', {}).get('font-size','16'))
+ return size
+
+ def get(self,tag):
+ if not tag in self.style:
+ return ""
+ return ';'.join(['%s:%s' % (x[0],x[1]) for x in self.style[tag].items()])
class _rml_template(object):
- def __init__(self, template):
- self.frame_pos = -1
- self.frames = []
- self.template_order = []
- self.page_template = {}
- self.loop = 0
- self._tags = {
- 'drawString': _rml_tmpl_draw_string,
- 'drawRightString': _rml_tmpl_draw_string,
- 'drawCentredString': _rml_tmpl_draw_string,
- 'lines': _rml_tmpl_draw_lines
- }
- self.style = _rml_draw_style()
- for pt in template.getElementsByTagName('pageTemplate'):
- frames = {}
- id = pt.getAttribute('id')
- self.template_order.append(id)
- for tmpl in pt.getElementsByTagName('frame'):
- posy = int(utils.unit_get(tmpl.getAttribute('y1'))) #+utils.unit_get(tmpl.getAttribute('height')))
- posx = int(utils.unit_get(tmpl.getAttribute('x1')))
- frames[(posy,posx,tmpl.getAttribute('id'))] = _rml_tmpl_frame(posx, utils.unit_get(tmpl.getAttribute('width')))
- for tmpl in template.getElementsByTagName('pageGraphics'):
- for n in tmpl.childNodes:
- if n.nodeType==n.ELEMENT_NODE:
- if n.localName in self._tags:
- t = self._tags[n.localName](n, self.style)
- frames[(t.posy,t.posx,n.localName)] = t
- else:
- self.style.update(n)
- keys = frames.keys()
- keys.sort()
- keys.reverse()
- self.page_template[id] = []
- for key in range(len(keys)):
- if key>0 and keys[key-1][0] == keys[key][0]:
- if type(self.page_template[id][-1]) == type(frames[keys[key]]):
- if self.page_template[id][-1].tag_mergeable():
- self.page_template[id][-1].merge(frames[keys[key]])
- continue
- self.page_template[id].append(frames[keys[key]])
- self.template = self.template_order[0]
-
- def _get_style(self):
- return self.style
-
- def set_next_template(self):
- self.template = self.template_order[(self.template_order.index(name)+1) % self.template_order]
- self.frame_pos = -1
-
- def set_template(self, name):
- self.template = name
- self.frame_pos = -1
-
- def frame_start(self):
- result = ''
- frames = self.page_template[self.template]
- ok = True
- while ok:
- self.frame_pos += 1
- if self.frame_pos>=len(frames):
- self.frame_pos=0
- self.loop=1
- ok = False
- continue
- f = frames[self.frame_pos]
- result+=f.tag_start()
- ok = not f.tag_end()
- if ok:
- result+=f.tag_stop()
- return result
-
- def frame_stop(self):
- frames = self.page_template[self.template]
- f = frames[self.frame_pos]
- result=f.tag_stop()
- return result
-
- def start(self):
- return ''
-
- def end(self):
- result = ''
- while not self.loop:
- result += self.frame_start()
- result += self.frame_stop()
- return result
+ def __init__(self, template):
+ self.frame_pos = -1
+ self.frames = []
+ self.template_order = []
+ self.page_template = {}
+ self.loop = 0
+ self._tags = {
+ 'drawString': _rml_tmpl_draw_string,
+ 'drawRightString': _rml_tmpl_draw_string,
+ 'drawCentredString': _rml_tmpl_draw_string,
+ 'lines': _rml_tmpl_draw_lines
+ }
+ self.style = _rml_draw_style()
+ for pt in template.getElementsByTagName('pageTemplate'):
+ frames = {}
+ id = pt.getAttribute('id')
+ self.template_order.append(id)
+ for tmpl in pt.getElementsByTagName('frame'):
+ posy = int(utils.unit_get(tmpl.getAttribute('y1'))) #+utils.unit_get(tmpl.getAttribute('height')))
+ posx = int(utils.unit_get(tmpl.getAttribute('x1')))
+ frames[(posy,posx,tmpl.getAttribute('id'))] = _rml_tmpl_frame(posx, utils.unit_get(tmpl.getAttribute('width')))
+ for tmpl in template.getElementsByTagName('pageGraphics'):
+ for n in tmpl.childNodes:
+ if n.nodeType==n.ELEMENT_NODE:
+ if n.localName in self._tags:
+ t = self._tags[n.localName](n, self.style)
+ frames[(t.posy,t.posx,n.localName)] = t
+ else:
+ self.style.update(n)
+ keys = frames.keys()
+ keys.sort()
+ keys.reverse()
+ self.page_template[id] = []
+ for key in range(len(keys)):
+ if key>0 and keys[key-1][0] == keys[key][0]:
+ if type(self.page_template[id][-1]) == type(frames[keys[key]]):
+ if self.page_template[id][-1].tag_mergeable():
+ self.page_template[id][-1].merge(frames[keys[key]])
+ continue
+ self.page_template[id].append(frames[keys[key]])
+ self.template = self.template_order[0]
+
+ def _get_style(self):
+ return self.style
+
+ def set_next_template(self):
+ self.template = self.template_order[(self.template_order.index(name)+1) % self.template_order]
+ self.frame_pos = -1
+
+ def set_template(self, name):
+ self.template = name
+ self.frame_pos = -1
+
+ def frame_start(self):
+ result = ''
+ frames = self.page_template[self.template]
+ ok = True
+ while ok:
+ self.frame_pos += 1
+ if self.frame_pos>=len(frames):
+ self.frame_pos=0
+ self.loop=1
+ ok = False
+ continue
+ f = frames[self.frame_pos]
+ result+=f.tag_start()
+ ok = not f.tag_end()
+ if ok:
+ result+=f.tag_stop()
+ return result
+
+ def frame_stop(self):
+ frames = self.page_template[self.template]
+ f = frames[self.frame_pos]
+ result=f.tag_stop()
+ return result
+
+ def start(self):
+ return ''
+
+ def end(self):
+ result = ''
+ while not self.loop:
+ result += self.frame_start()
+ result += self.frame_stop()
+ return result
class _rml_doc(object):
- def __init__(self, data):
- self.dom = xml.dom.minidom.parseString(data)
- self.filename = self.dom.documentElement.getAttribute('filename')
- self.result = ''
+ def __init__(self, data):
+ self.dom = xml.dom.minidom.parseString(data)
+ self.filename = self.dom.documentElement.getAttribute('filename')
+ self.result = ''
- def render(self, out):
- self.result += '''<!DOCTYPE HTML PUBLIC "-//w3c//DTD HTML 4.0 Frameset//EN">
+ def render(self, out):
+ self.result += '''<!DOCTYPE HTML PUBLIC "-//w3c//DTD HTML 4.0 Frameset//EN">
<html>
<head>
- <style type="text/css">
- p {margin:0px; font-size:12px;}
- td {font-size:14px;}
+ <style type="text/css">
+ p {margin:0px; font-size:12px;}
+ td {font-size:14px;}
'''
- style = self.dom.documentElement.getElementsByTagName('stylesheet')[0]
- s = _rml_stylesheet(style, self.dom)
- self.result += s.render()
- self.result+='''
- </style>
+ style = self.dom.documentElement.getElementsByTagName('stylesheet')[0]
+ s = _rml_stylesheet(style, self.dom)
+ self.result += s.render()
+ self.result+='''
+ </style>
</head>
<body>'''
- template = _rml_template(self.dom.documentElement.getElementsByTagName('template')[0])
- f = _flowable(template, self.dom)
- self.result += f.render(self.dom.documentElement.getElementsByTagName('story')[0])
- del f
- self.result += '</body></html>'
- out.write( self.result)
+ template = _rml_template(self.dom.documentElement.getElementsByTagName('template')[0])
+ f = _flowable(template, self.dom)
+ self.result += f.render(self.dom.documentElement.getElementsByTagName('story')[0])
+ del f
+ self.result += '</body></html>'
+ out.write( self.result)
def parseString(data, fout=None):
- r = _rml_doc(data)
- if fout:
- fp = file(fout,'wb')
- r.render(fp)
- fp.close()
- return fout
- else:
- fp = StringIO.StringIO()
- r.render(fp)
- return fp.getvalue()
+ r = _rml_doc(data)
+ if fout:
+ fp = file(fout,'wb')
+ r.render(fp)
+ fp.close()
+ return fout
+ else:
+ fp = StringIO.StringIO()
+ r.render(fp)
+ return fp.getvalue()
def trml2pdf_help():
- print 'Usage: rml2html input.rml >output.html'
- print 'Render the standard input (RML) and output an HTML file'
- sys.exit(0)
+ print 'Usage: rml2html input.rml >output.html'
+ print 'Render the standard input (RML) and output an HTML file'
+ sys.exit(0)
if __name__=="__main__":
- if len(sys.argv)>1:
- if sys.argv[1]=='--help':
- trml2pdf_help()
- print parseString(file(sys.argv[1], 'r').read()),
- else:
- print 'Usage: trml2pdf input.rml >output.pdf'
- print 'Try \'trml2pdf --help\' for more information.'
+ if len(sys.argv)>1:
+ if sys.argv[1]=='--help':
+ trml2pdf_help()
+ print parseString(file(sys.argv[1], 'r').read()),
+ else:
+ print 'Usage: trml2pdf input.rml >output.pdf'
+ print 'Try \'trml2pdf --help\' for more information.'
diff --git a/bin/report/render/rml2html/utils.py b/bin/report/render/rml2html/utils.py
index ad3a74445b8..2cef5ce80b2 100644
--- a/bin/report/render/rml2html/utils.py
+++ b/bin/report/render/rml2html/utils.py
@@ -47,48 +47,48 @@ import reportlab
import reportlab.lib.units
def text_get(node):
- rc = ''
- for node in node.childNodes:
- if node.nodeType == node.TEXT_NODE:
- rc = rc + node.data
- return rc
+ rc = ''
+ for node in node.childNodes:
+ if node.nodeType == node.TEXT_NODE:
+ rc = rc + node.data
+ return rc
units = [
- (re.compile('^(-?[0-9\.]+)\s*in$'), reportlab.lib.units.inch),
- (re.compile('^(-?[0-9\.]+)\s*cm$'), reportlab.lib.units.cm),
- (re.compile('^(-?[0-9\.]+)\s*mm$'), reportlab.lib.units.mm),
- (re.compile('^(-?[0-9\.]+)\s*px$'), 0.7),
- (re.compile('^(-?[0-9\.]+)\s*$'), 1)
+ (re.compile('^(-?[0-9\.]+)\s*in$'), reportlab.lib.units.inch),
+ (re.compile('^(-?[0-9\.]+)\s*cm$'), reportlab.lib.units.cm),
+ (re.compile('^(-?[0-9\.]+)\s*mm$'), reportlab.lib.units.mm),
+ (re.compile('^(-?[0-9\.]+)\s*px$'), 0.7),
+ (re.compile('^(-?[0-9\.]+)\s*$'), 1)
]
def unit_get(size):
- global units
- for unit in units:
- res = unit[0].search(size, 0)
- if res:
- return int(unit[1]*float(res.group(1))*1.3)
- return False
+ global units
+ for unit in units:
+ res = unit[0].search(size, 0)
+ if res:
+ return int(unit[1]*float(res.group(1))*1.3)
+ return False
def tuple_int_get(node, attr_name, default=None):
- if not node.hasAttribute(attr_name):
- return default
- res = [int(x) for x in node.getAttribute(attr_name).split(',')]
- return res
+ if not node.hasAttribute(attr_name):
+ return default
+ res = [int(x) for x in node.getAttribute(attr_name).split(',')]
+ return res
def bool_get(value):
- return (str(value)=="1") or (value.lower()=='yes')
+ return (str(value)=="1") or (value.lower()=='yes')
def attr_get(node, attrs, dict={}):
- res = {}
- for name in attrs:
- if node.hasAttribute(name):
- res[name] = unit_get(node.getAttribute(name))
- for key in dict:
- if node.hasAttribute(key):
- if dict[key]=='str':
- res[key] = str(node.getAttribute(key))
- elif dict[key]=='bool':
- res[key] = bool_get(node.getAttribute(key))
- elif dict[key]=='int':
- res[key] = int(node.getAttribute(key))
- return res
+ res = {}
+ for name in attrs:
+ if node.hasAttribute(name):
+ res[name] = unit_get(node.getAttribute(name))
+ for key in dict:
+ if node.hasAttribute(key):
+ if dict[key]=='str':
+ res[key] = str(node.getAttribute(key))
+ elif dict[key]=='bool':
+ res[key] = bool_get(node.getAttribute(key))
+ elif dict[key]=='int':
+ res[key] = int(node.getAttribute(key))
+ return res
diff --git a/bin/report/render/rml2pdf/color.py b/bin/report/render/rml2pdf/color.py
index 0e50e9f76f5..6cb772999a2 100644
--- a/bin/report/render/rml2pdf/color.py
+++ b/bin/report/render/rml2pdf/color.py
@@ -51,13 +51,13 @@ regex_t = re.compile('\(([0-9\.]*),([0-9\.]*),([0-9\.]*)\)')
regex_h = re.compile('#([0-9a-zA-Z][0-9a-zA-Z])([0-9a-zA-Z][0-9a-zA-Z])([0-9a-zA-Z][0-9a-zA-Z])')
def get(col_str):
- global allcols
- if col_str in allcols.keys():
- return allcols[col_str]
- res = regex_t.search(col_str, 0)
- if res:
- return (float(res.group(1)),float(res.group(2)),float(res.group(3)))
- res = regex_h.search(col_str, 0)
- if res:
- return tuple([ float(int(res.group(i),16))/255 for i in range(1,4)])
- return colors.red
+ global allcols
+ if col_str in allcols.keys():
+ return allcols[col_str]
+ res = regex_t.search(col_str, 0)
+ if res:
+ return (float(res.group(1)),float(res.group(2)),float(res.group(3)))
+ res = regex_h.search(col_str, 0)
+ if res:
+ return tuple([ float(int(res.group(i),16))/255 for i in range(1,4)])
+ return colors.red
diff --git a/bin/report/render/rml2pdf/trml2pdf.py b/bin/report/render/rml2pdf/trml2pdf.py
index 1aef11888e4..555a2769e04 100755..100644
--- a/bin/report/render/rml2pdf/trml2pdf.py
+++ b/bin/report/render/rml2pdf/trml2pdf.py
@@ -68,740 +68,740 @@ import os
encoding = 'utf-8'
def str2xml(s):
- return s.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')
+ return s.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')
def _child_get(node, childs):
- clds = []
- for n in node.childNodes:
- if (n.nodeType==n.ELEMENT_NODE) and (n.localName==childs):
- clds.append(n)
- return clds
+ clds = []
+ for n in node.childNodes:
+ if (n.nodeType==n.ELEMENT_NODE) and (n.localName==childs):
+ clds.append(n)
+ return clds
class PageCount(platypus.Flowable):
- def draw(self):
- self.canv.beginForm("pageCount")
- self.canv.setFont("Helvetica", utils.unit_get(str(8)))
- self.canv.drawString(0, 0, str(self.canv.getPageNumber()))
- self.canv.endForm()
+ def draw(self):
+ self.canv.beginForm("pageCount")
+ self.canv.setFont("Helvetica", utils.unit_get(str(8)))
+ self.canv.drawString(0, 0, str(self.canv.getPageNumber()))
+ self.canv.endForm()
class PageReset(platypus.Flowable):
- def draw(self):
- self.canv._pageNumber = 0
+ def draw(self):
+ self.canv._pageNumber = 0
class _rml_styles(object):
- def __init__(self, nodes):
- self.styles = {}
- self.names = {}
- self.table_styles = {}
- for node in nodes:
- for style in node.getElementsByTagName('blockTableStyle'):
- self.table_styles[style.getAttribute('id')] = self._table_style_get(style)
- for style in node.getElementsByTagName('paraStyle'):
- self.styles[style.getAttribute('name')] = self._para_style_update(style)
- for variable in node.getElementsByTagName('initialize'):
- for name in variable.getElementsByTagName('name'):
- self.names[ name.getAttribute('id')] = name.getAttribute('value')
-
- def _para_style_update(self, node):
- data = {}
- for attr in ['textColor', 'backColor', 'bulletColor', 'borderColor']:
- if node.hasAttribute(attr):
- data[attr] = color.get(node.getAttribute(attr))
- for attr in ['fontName', 'bulletFontName', 'bulletText']:
- if node.hasAttribute(attr):
- data[attr] = node.getAttribute(attr)
- for attr in ['fontSize', 'leftIndent', 'rightIndent', 'spaceBefore', 'spaceAfter',
- 'firstLineIndent', 'bulletIndent', 'bulletFontSize', 'leading',
- 'borderWidth','borderPadding','borderRadius']:
- if node.hasAttribute(attr):
- data[attr] = utils.unit_get(node.getAttribute(attr))
- if node.hasAttribute('alignment'):
- align = {
- 'right':reportlab.lib.enums.TA_RIGHT,
- 'center':reportlab.lib.enums.TA_CENTER,
- 'justify':reportlab.lib.enums.TA_JUSTIFY
- }
- data['alignment'] = align.get(node.getAttribute('alignment').lower(), reportlab.lib.enums.TA_LEFT)
- return data
-
- def _table_style_get(self, style_node):
- styles = []
- for node in style_node.childNodes:
- if node.nodeType==node.ELEMENT_NODE:
- start = utils.tuple_int_get(node, 'start', (0,0) )
- stop = utils.tuple_int_get(node, 'stop', (-1,-1) )
- if node.localName=='blockValign':
- styles.append(('VALIGN', start, stop, str(node.getAttribute('value'))))
- elif node.localName=='blockFont':
- styles.append(('FONT', start, stop, str(node.getAttribute('name'))))
- elif node.localName=='blockTextColor':
- styles.append(('TEXTCOLOR', start, stop, color.get(str(node.getAttribute('colorName')))))
- elif node.localName=='blockLeading':
- styles.append(('LEADING', start, stop, utils.unit_get(node.getAttribute('length'))))
- elif node.localName=='blockAlignment':
- styles.append(('ALIGNMENT', start, stop, str(node.getAttribute('value'))))
- elif node.localName=='blockSpan':
- styles.append(('SPAN', start, stop))
- elif node.localName=='blockLeftPadding':
- styles.append(('LEFTPADDING', start, stop, utils.unit_get(node.getAttribute('length'))))
- elif node.localName=='blockRightPadding':
- styles.append(('RIGHTPADDING', start, stop, utils.unit_get(node.getAttribute('length'))))
- elif node.localName=='blockTopPadding':
- styles.append(('TOPPADDING', start, stop, utils.unit_get(node.getAttribute('length'))))
- elif node.localName=='blockBottomPadding':
- styles.append(('BOTTOMPADDING', start, stop, utils.unit_get(node.getAttribute('length'))))
- elif node.localName=='blockBackground':
- styles.append(('BACKGROUND', start, stop, color.get(node.getAttribute('colorName'))))
- if node.hasAttribute('size'):
- styles.append(('FONTSIZE', start, stop, utils.unit_get(node.getAttribute('size'))))
- elif node.localName=='lineStyle':
- kind = node.getAttribute('kind')
- kind_list = [ 'GRID', 'BOX', 'OUTLINE', 'INNERGRID', 'LINEBELOW', 'LINEABOVE','LINEBEFORE', 'LINEAFTER' ]
- assert kind in kind_list
- thick = 1
- if node.hasAttribute('thickness'):
- thick = float(node.getAttribute('thickness'))
- styles.append((kind, start, stop, thick, color.get(node.getAttribute('colorName'))))
- return platypus.tables.TableStyle(styles)
-
- def para_style_get(self, node):
- style = False
- if node.hasAttribute('style'):
- if node.getAttribute('style') in self.styles:
- styles = reportlab.lib.styles.getSampleStyleSheet()
- sname = node.getAttribute('style')
- style = reportlab.lib.styles.ParagraphStyle(sname, styles["Normal"], **self.styles[sname])
- else:
- sys.stderr.write('Warning: style not found, %s - setting default!\n' % (node.getAttribute('style'),) )
- if not style:
- styles = reportlab.lib.styles.getSampleStyleSheet()
- style = copy.deepcopy(styles['Normal'])
- style.__dict__.update(self._para_style_update(node))
- return style
+ def __init__(self, nodes):
+ self.styles = {}
+ self.names = {}
+ self.table_styles = {}
+ for node in nodes:
+ for style in node.getElementsByTagName('blockTableStyle'):
+ self.table_styles[style.getAttribute('id')] = self._table_style_get(style)
+ for style in node.getElementsByTagName('paraStyle'):
+ self.styles[style.getAttribute('name')] = self._para_style_update(style)
+ for variable in node.getElementsByTagName('initialize'):
+ for name in variable.getElementsByTagName('name'):
+ self.names[ name.getAttribute('id')] = name.getAttribute('value')
+
+ def _para_style_update(self, node):
+ data = {}
+ for attr in ['textColor', 'backColor', 'bulletColor', 'borderColor']:
+ if node.hasAttribute(attr):
+ data[attr] = color.get(node.getAttribute(attr))
+ for attr in ['fontName', 'bulletFontName', 'bulletText']:
+ if node.hasAttribute(attr):
+ data[attr] = node.getAttribute(attr)
+ for attr in ['fontSize', 'leftIndent', 'rightIndent', 'spaceBefore', 'spaceAfter',
+ 'firstLineIndent', 'bulletIndent', 'bulletFontSize', 'leading',
+ 'borderWidth','borderPadding','borderRadius']:
+ if node.hasAttribute(attr):
+ data[attr] = utils.unit_get(node.getAttribute(attr))
+ if node.hasAttribute('alignment'):
+ align = {
+ 'right':reportlab.lib.enums.TA_RIGHT,
+ 'center':reportlab.lib.enums.TA_CENTER,
+ 'justify':reportlab.lib.enums.TA_JUSTIFY
+ }
+ data['alignment'] = align.get(node.getAttribute('alignment').lower(), reportlab.lib.enums.TA_LEFT)
+ return data
+
+ def _table_style_get(self, style_node):
+ styles = []
+ for node in style_node.childNodes:
+ if node.nodeType==node.ELEMENT_NODE:
+ start = utils.tuple_int_get(node, 'start', (0,0) )
+ stop = utils.tuple_int_get(node, 'stop', (-1,-1) )
+ if node.localName=='blockValign':
+ styles.append(('VALIGN', start, stop, str(node.getAttribute('value'))))
+ elif node.localName=='blockFont':
+ styles.append(('FONT', start, stop, str(node.getAttribute('name'))))
+ elif node.localName=='blockTextColor':
+ styles.append(('TEXTCOLOR', start, stop, color.get(str(node.getAttribute('colorName')))))
+ elif node.localName=='blockLeading':
+ styles.append(('LEADING', start, stop, utils.unit_get(node.getAttribute('length'))))
+ elif node.localName=='blockAlignment':
+ styles.append(('ALIGNMENT', start, stop, str(node.getAttribute('value'))))
+ elif node.localName=='blockSpan':
+ styles.append(('SPAN', start, stop))
+ elif node.localName=='blockLeftPadding':
+ styles.append(('LEFTPADDING', start, stop, utils.unit_get(node.getAttribute('length'))))
+ elif node.localName=='blockRightPadding':
+ styles.append(('RIGHTPADDING', start, stop, utils.unit_get(node.getAttribute('length'))))
+ elif node.localName=='blockTopPadding':
+ styles.append(('TOPPADDING', start, stop, utils.unit_get(node.getAttribute('length'))))
+ elif node.localName=='blockBottomPadding':
+ styles.append(('BOTTOMPADDING', start, stop, utils.unit_get(node.getAttribute('length'))))
+ elif node.localName=='blockBackground':
+ styles.append(('BACKGROUND', start, stop, color.get(node.getAttribute('colorName'))))
+ if node.hasAttribute('size'):
+ styles.append(('FONTSIZE', start, stop, utils.unit_get(node.getAttribute('size'))))
+ elif node.localName=='lineStyle':
+ kind = node.getAttribute('kind')
+ kind_list = [ 'GRID', 'BOX', 'OUTLINE', 'INNERGRID', 'LINEBELOW', 'LINEABOVE','LINEBEFORE', 'LINEAFTER' ]
+ assert kind in kind_list
+ thick = 1
+ if node.hasAttribute('thickness'):
+ thick = float(node.getAttribute('thickness'))
+ styles.append((kind, start, stop, thick, color.get(node.getAttribute('colorName'))))
+ return platypus.tables.TableStyle(styles)
+
+ def para_style_get(self, node):
+ style = False
+ if node.hasAttribute('style'):
+ if node.getAttribute('style') in self.styles:
+ styles = reportlab.lib.styles.getSampleStyleSheet()
+ sname = node.getAttribute('style')
+ style = reportlab.lib.styles.ParagraphStyle(sname, styles["Normal"], **self.styles[sname])
+ else:
+ sys.stderr.write('Warning: style not found, %s - setting default!\n' % (node.getAttribute('style'),) )
+ if not style:
+ styles = reportlab.lib.styles.getSampleStyleSheet()
+ style = copy.deepcopy(styles['Normal'])
+ style.__dict__.update(self._para_style_update(node))
+ return style
class _rml_doc(object):
- def __init__(self, data, images={}, path='.'):
- self.dom = xml.dom.minidom.parseString(data)
- self.filename = self.dom.documentElement.getAttribute('filename')
- self.images = images
- self.path = path
-
- def docinit(self, els):
- from reportlab.lib.fonts import addMapping
- from reportlab.pdfbase import pdfmetrics
- from reportlab.pdfbase.ttfonts import TTFont
-
- for node in els:
- for font in node.getElementsByTagName('registerFont'):
- name = font.getAttribute('fontName').encode('ascii')
- fname = font.getAttribute('fontFile').encode('ascii')
- pdfmetrics.registerFont(TTFont(name, fname ))
- addMapping(name, 0, 0, name) #normal
- addMapping(name, 0, 1, name) #italic
- addMapping(name, 1, 0, name) #bold
- addMapping(name, 1, 1, name) #italic and bold
-
- def _textual_image(self, node):
- import base64
- rc = ''
- for n in node.childNodes:
- if n.nodeType in (node.CDATA_SECTION_NODE, node.TEXT_NODE):
- rc += n.data
- return base64.decodestring(rc)
-
- def _images(self, el):
- result = {}
- for node in el.getElementsByTagName('image'):
- result[node.getAttribute('name')] = self._textual_image(node)
- return result
-
- def render(self, out):
- el = self.dom.documentElement.getElementsByTagName('docinit')
- if el:
- self.docinit(el)
-
- el = self.dom.documentElement.getElementsByTagName('stylesheet')
- self.styles = _rml_styles(el)
-
- el = self.dom.documentElement.getElementsByTagName('images')
- if el:
- self.images.update( self._images(el[0]) )
-
- el = self.dom.documentElement.getElementsByTagName('template')
- if len(el):
- pt_obj = _rml_template(out, el[0], self, images=self.images, path=self.path)
- pt_obj.render(self.dom.documentElement.getElementsByTagName('story'))
- else:
- self.canvas = canvas.Canvas(out)
- pd = self.dom.documentElement.getElementsByTagName('pageDrawing')[0]
- pd_obj = _rml_canvas(self.canvas, None, self, self.images, path=self.path)
- pd_obj.render(pd)
-
- self.canvas.showPage()
- self.canvas.save()
+ def __init__(self, data, images={}, path='.'):
+ self.dom = xml.dom.minidom.parseString(data)
+ self.filename = self.dom.documentElement.getAttribute('filename')
+ self.images = images
+ self.path = path
+
+ def docinit(self, els):
+ from reportlab.lib.fonts import addMapping
+ from reportlab.pdfbase import pdfmetrics
+ from reportlab.pdfbase.ttfonts import TTFont
+
+ for node in els:
+ for font in node.getElementsByTagName('registerFont'):
+ name = font.getAttribute('fontName').encode('ascii')
+ fname = font.getAttribute('fontFile').encode('ascii')
+ pdfmetrics.registerFont(TTFont(name, fname ))
+ addMapping(name, 0, 0, name) #normal
+ addMapping(name, 0, 1, name) #italic
+ addMapping(name, 1, 0, name) #bold
+ addMapping(name, 1, 1, name) #italic and bold
+
+ def _textual_image(self, node):
+ import base64
+ rc = ''
+ for n in node.childNodes:
+ if n.nodeType in (node.CDATA_SECTION_NODE, node.TEXT_NODE):
+ rc += n.data
+ return base64.decodestring(rc)
+
+ def _images(self, el):
+ result = {}
+ for node in el.getElementsByTagName('image'):
+ result[node.getAttribute('name')] = self._textual_image(node)
+ return result
+
+ def render(self, out):
+ el = self.dom.documentElement.getElementsByTagName('docinit')
+ if el:
+ self.docinit(el)
+
+ el = self.dom.documentElement.getElementsByTagName('stylesheet')
+ self.styles = _rml_styles(el)
+
+ el = self.dom.documentElement.getElementsByTagName('images')
+ if el:
+ self.images.update( self._images(el[0]) )
+
+ el = self.dom.documentElement.getElementsByTagName('template')
+ if len(el):
+ pt_obj = _rml_template(out, el[0], self, images=self.images, path=self.path)
+ pt_obj.render(self.dom.documentElement.getElementsByTagName('story'))
+ else:
+ self.canvas = canvas.Canvas(out)
+ pd = self.dom.documentElement.getElementsByTagName('pageDrawing')[0]
+ pd_obj = _rml_canvas(self.canvas, None, self, self.images, path=self.path)
+ pd_obj.render(pd)
+
+ self.canvas.showPage()
+ self.canvas.save()
class _rml_canvas(object):
- def __init__(self, canvas, doc_tmpl=None, doc=None, images={}, path='.'):
- self.canvas = canvas
- self.styles = doc.styles
- self.doc_tmpl = doc_tmpl
- self.doc = doc
- self.images = images
- self.path = path
-
- def _textual(self, node, x=0, y=0):
- rc = ''
- for n in node.childNodes:
- if n.nodeType == n.ELEMENT_NODE:
- if n.localName == 'seq':
- from reportlab.lib.sequencer import getSequencer
- seq = getSequencer()
- rc += str(seq.next(n.getAttribute('id')))
- if n.localName == 'pageCount':
- if x or y:
- self.canvas.translate(x,y)
- self.canvas.doForm('pageCount')
- if x or y:
- self.canvas.translate(-x,-y)
- if n.localName == 'pageNumber':
- rc += str(self.canvas.getPageNumber())
- elif n.nodeType in (node.CDATA_SECTION_NODE, node.TEXT_NODE):
- # this doesn't need to be "entities" encoded like flowables need to
- rc += n.data
- return rc.encode(encoding, 'replace')
-
- def _drawString(self, node):
- v = utils.attr_get(node, ['x','y'])
- self.canvas.drawString(text=self._textual(node, **v), **v)
- def _drawCenteredString(self, node):
- v = utils.attr_get(node, ['x','y'])
- self.canvas.drawCentredString(text=self._textual(node, **v), **v)
- def _drawRightString(self, node):
- v = utils.attr_get(node, ['x','y'])
- self.canvas.drawRightString(text=self._textual(node, **v), **v)
- def _rect(self, node):
- if node.hasAttribute('round'):
- self.canvas.roundRect(radius=utils.unit_get(node.getAttribute('round')), **utils.attr_get(node, ['x','y','width','height'], {'fill':'bool','stroke':'bool'}))
- else:
- self.canvas.rect(**utils.attr_get(node, ['x','y','width','height'], {'fill':'bool','stroke':'bool'}))
-
- def _ellipse(self, node):
- x1 = utils.unit_get(node.getAttribute('x'))
- x2 = utils.unit_get(node.getAttribute('width'))
- y1 = utils.unit_get(node.getAttribute('y'))
- y2 = utils.unit_get(node.getAttribute('height'))
- self.canvas.ellipse(x1,y1,x2,y2, **utils.attr_get(node, [], {'fill':'bool','stroke':'bool'}))
- def _curves(self, node):
- line_str = utils.text_get(node).split()
- lines = []
- while len(line_str)>7:
- self.canvas.bezier(*[utils.unit_get(l) for l in line_str[0:8]])
- line_str = line_str[8:]
- def _lines(self, node):
- line_str = utils.text_get(node).split()
- lines = []
- while len(line_str)>3:
- lines.append([utils.unit_get(l) for l in line_str[0:4]])
- line_str = line_str[4:]
- self.canvas.lines(lines)
- def _grid(self, node):
- xlist = [utils.unit_get(s) for s in node.getAttribute('xs').split(',')]
- ylist = [utils.unit_get(s) for s in node.getAttribute('ys').split(',')]
- self.canvas.grid(xlist, ylist)
- def _translate(self, node):
- dx = 0
- dy = 0
- if node.hasAttribute('dx'):
- dx = utils.unit_get(node.getAttribute('dx'))
- if node.hasAttribute('dy'):
- dy = utils.unit_get(node.getAttribute('dy'))
- self.canvas.translate(dx,dy)
-
- def _circle(self, node):
- self.canvas.circle(x_cen=utils.unit_get(node.getAttribute('x')), y_cen=utils.unit_get(node.getAttribute('y')), r=utils.unit_get(node.getAttribute('radius')), **utils.attr_get(node, [], {'fill':'bool','stroke':'bool'}))
-
- def _place(self, node):
- flows = _rml_flowable(self.doc, images=self.images, path=self.path).render(node)
- infos = utils.attr_get(node, ['x','y','width','height'])
-
- infos['y']+=infos['height']
- for flow in flows:
- w,h = flow.wrap(infos['width'], infos['height'])
- if w<=infos['width'] and h<=infos['height']:
- infos['y']-=h
- flow.drawOn(self.canvas,infos['x'],infos['y'])
- infos['height']-=h
- else:
- raise ValueError, "Not enough space"
-
- def _line_mode(self, node):
- ljoin = {'round':1, 'mitered':0, 'bevelled':2}
- lcap = {'default':0, 'round':1, 'square':2}
- if node.hasAttribute('width'):
- self.canvas.setLineWidth(utils.unit_get(node.getAttribute('width')))
- if node.hasAttribute('join'):
- self.canvas.setLineJoin(ljoin[node.getAttribute('join')])
- if node.hasAttribute('cap'):
- self.canvas.setLineCap(lcap[node.getAttribute('cap')])
- if node.hasAttribute('miterLimit'):
- self.canvas.setDash(utils.unit_get(node.getAttribute('miterLimit')))
- if node.hasAttribute('dash'):
- dashes = node.getAttribute('dash').split(',')
- for x in range(len(dashes)):
- dashes[x]=utils.unit_get(dashes[x])
- self.canvas.setDash(node.getAttribute('dash').split(','))
-
- def _image(self, node):
- import urllib
- from reportlab.lib.utils import ImageReader
-
- if not node.hasAttribute('file'):
-
- if node.hasAttribute('name'):
- image_data = self.images[node.getAttribute('name')]
- s = StringIO.StringIO(image_data)
- else:
- import base64
- image_data = base64.decodestring(node.firstChild.nodeValue)
- if not image_data: return False
- s = StringIO.StringIO(image_data)
- else:
- if node.getAttribute('file') in self.images:
- s = StringIO.StringIO(self.images[node.getAttribute('file')])
- else:
- try:
- u = urllib.urlopen(str(node.getAttribute('file')))
- s = StringIO.StringIO(u.read())
- except:
- u = file(os.path.join(self.path,str(node.getAttribute('file'))), 'rb')
- s = StringIO.StringIO(u.read())
- img = ImageReader(s)
- (sx,sy) = img.getSize()
-
- args = {}
- for tag in ('width','height','x','y'):
- if node.hasAttribute(tag):
- args[tag] = utils.unit_get(node.getAttribute(tag))
- if ('width' in args) and (not 'height' in args):
- args['height'] = sy * args['width'] / sx
- elif ('height' in args) and (not 'width' in args):
- args['width'] = sx * args['height'] / sy
- elif ('width' in args) and ('height' in args):
- if (float(args['width'])/args['height'])>(float(sx)>sy):
- args['width'] = sx * args['height'] / sy
- else:
- args['height'] = sy * args['width'] / sx
- self.canvas.drawImage(img, **args)
-
- def _path(self, node):
- self.path = self.canvas.beginPath()
- self.path.moveTo(**utils.attr_get(node, ['x','y']))
- for n in node.childNodes:
- if n.nodeType == node.ELEMENT_NODE:
- if n.localName=='moveto':
- vals = utils.text_get(n).split()
- self.path.moveTo(utils.unit_get(vals[0]), utils.unit_get(vals[1]))
- elif n.localName=='curvesto':
- vals = utils.text_get(n).split()
- while len(vals)>5:
- pos=[]
- while len(pos)<6:
- pos.append(utils.unit_get(vals.pop(0)))
- self.path.curveTo(*pos)
- elif (n.nodeType == node.TEXT_NODE):
- data = n.data.split() # Not sure if I must merge all TEXT_NODE ?
- while len(data)>1:
- x = utils.unit_get(data.pop(0))
- y = utils.unit_get(data.pop(0))
- self.path.lineTo(x,y)
- if (not node.hasAttribute('close')) or utils.bool_get(node.getAttribute('close')):
- self.path.close()
- self.canvas.drawPath(self.path, **utils.attr_get(node, [], {'fill':'bool','stroke':'bool'}))
-
- def render(self, node):
- tags = {
- 'drawCentredString': self._drawCenteredString,
- 'drawRightString': self._drawRightString,
- 'drawString': self._drawString,
- 'rect': self._rect,
- 'ellipse': self._ellipse,
- 'lines': self._lines,
- 'grid': self._grid,
- 'curves': self._curves,
- 'fill': lambda node: self.canvas.setFillColor(color.get(node.getAttribute('color'))),
- 'stroke': lambda node: self.canvas.setStrokeColor(color.get(node.getAttribute('color'))),
- 'setFont': lambda node: self.canvas.setFont(node.getAttribute('name'), utils.unit_get(node.getAttribute('size'))),
- 'place': self._place,
- 'circle': self._circle,
- 'lineMode': self._line_mode,
- 'path': self._path,
- 'rotate': lambda node: self.canvas.rotate(float(node.getAttribute('degrees'))),
- 'translate': self._translate,
- 'image': self._image
- }
- for nd in node.childNodes:
- if nd.nodeType==nd.ELEMENT_NODE:
- for tag in tags:
- if nd.localName==tag:
- tags[tag](nd)
- break
+ def __init__(self, canvas, doc_tmpl=None, doc=None, images={}, path='.'):
+ self.canvas = canvas
+ self.styles = doc.styles
+ self.doc_tmpl = doc_tmpl
+ self.doc = doc
+ self.images = images
+ self.path = path
+
+ def _textual(self, node, x=0, y=0):
+ rc = ''
+ for n in node.childNodes:
+ if n.nodeType == n.ELEMENT_NODE:
+ if n.localName == 'seq':
+ from reportlab.lib.sequencer import getSequencer
+ seq = getSequencer()
+ rc += str(seq.next(n.getAttribute('id')))
+ if n.localName == 'pageCount':
+ if x or y:
+ self.canvas.translate(x,y)
+ self.canvas.doForm('pageCount')
+ if x or y:
+ self.canvas.translate(-x,-y)
+ if n.localName == 'pageNumber':
+ rc += str(self.canvas.getPageNumber())
+ elif n.nodeType in (node.CDATA_SECTION_NODE, node.TEXT_NODE):
+ # this doesn't need to be "entities" encoded like flowables need to
+ rc += n.data
+ return rc.encode(encoding, 'replace')
+
+ def _drawString(self, node):
+ v = utils.attr_get(node, ['x','y'])
+ self.canvas.drawString(text=self._textual(node, **v), **v)
+ def _drawCenteredString(self, node):
+ v = utils.attr_get(node, ['x','y'])
+ self.canvas.drawCentredString(text=self._textual(node, **v), **v)
+ def _drawRightString(self, node):
+ v = utils.attr_get(node, ['x','y'])
+ self.canvas.drawRightString(text=self._textual(node, **v), **v)
+ def _rect(self, node):
+ if node.hasAttribute('round'):
+ self.canvas.roundRect(radius=utils.unit_get(node.getAttribute('round')), **utils.attr_get(node, ['x','y','width','height'], {'fill':'bool','stroke':'bool'}))
+ else:
+ self.canvas.rect(**utils.attr_get(node, ['x','y','width','height'], {'fill':'bool','stroke':'bool'}))
+
+ def _ellipse(self, node):
+ x1 = utils.unit_get(node.getAttribute('x'))
+ x2 = utils.unit_get(node.getAttribute('width'))
+ y1 = utils.unit_get(node.getAttribute('y'))
+ y2 = utils.unit_get(node.getAttribute('height'))
+ self.canvas.ellipse(x1,y1,x2,y2, **utils.attr_get(node, [], {'fill':'bool','stroke':'bool'}))
+ def _curves(self, node):
+ line_str = utils.text_get(node).split()
+ lines = []
+ while len(line_str)>7:
+ self.canvas.bezier(*[utils.unit_get(l) for l in line_str[0:8]])
+ line_str = line_str[8:]
+ def _lines(self, node):
+ line_str = utils.text_get(node).split()
+ lines = []
+ while len(line_str)>3:
+ lines.append([utils.unit_get(l) for l in line_str[0:4]])
+ line_str = line_str[4:]
+ self.canvas.lines(lines)
+ def _grid(self, node):
+ xlist = [utils.unit_get(s) for s in node.getAttribute('xs').split(',')]
+ ylist = [utils.unit_get(s) for s in node.getAttribute('ys').split(',')]
+ self.canvas.grid(xlist, ylist)
+ def _translate(self, node):
+ dx = 0
+ dy = 0
+ if node.hasAttribute('dx'):
+ dx = utils.unit_get(node.getAttribute('dx'))
+ if node.hasAttribute('dy'):
+ dy = utils.unit_get(node.getAttribute('dy'))
+ self.canvas.translate(dx,dy)
+
+ def _circle(self, node):
+ self.canvas.circle(x_cen=utils.unit_get(node.getAttribute('x')), y_cen=utils.unit_get(node.getAttribute('y')), r=utils.unit_get(node.getAttribute('radius')), **utils.attr_get(node, [], {'fill':'bool','stroke':'bool'}))
+
+ def _place(self, node):
+ flows = _rml_flowable(self.doc, images=self.images, path=self.path).render(node)
+ infos = utils.attr_get(node, ['x','y','width','height'])
+
+ infos['y']+=infos['height']
+ for flow in flows:
+ w,h = flow.wrap(infos['width'], infos['height'])
+ if w<=infos['width'] and h<=infos['height']:
+ infos['y']-=h
+ flow.drawOn(self.canvas,infos['x'],infos['y'])
+ infos['height']-=h
+ else:
+ raise ValueError, "Not enough space"
+
+ def _line_mode(self, node):
+ ljoin = {'round':1, 'mitered':0, 'bevelled':2}
+ lcap = {'default':0, 'round':1, 'square':2}
+ if node.hasAttribute('width'):
+ self.canvas.setLineWidth(utils.unit_get(node.getAttribute('width')))
+ if node.hasAttribute('join'):
+ self.canvas.setLineJoin(ljoin[node.getAttribute('join')])
+ if node.hasAttribute('cap'):
+ self.canvas.setLineCap(lcap[node.getAttribute('cap')])
+ if node.hasAttribute('miterLimit'):
+ self.canvas.setDash(utils.unit_get(node.getAttribute('miterLimit')))
+ if node.hasAttribute('dash'):
+ dashes = node.getAttribute('dash').split(',')
+ for x in range(len(dashes)):
+ dashes[x]=utils.unit_get(dashes[x])
+ self.canvas.setDash(node.getAttribute('dash').split(','))
+
+ def _image(self, node):
+ import urllib
+ from reportlab.lib.utils import ImageReader
+
+ if not node.hasAttribute('file'):
+
+ if node.hasAttribute('name'):
+ image_data = self.images[node.getAttribute('name')]
+ s = StringIO.StringIO(image_data)
+ else:
+ import base64
+ image_data = base64.decodestring(node.firstChild.nodeValue)
+ if not image_data: return False
+ s = StringIO.StringIO(image_data)
+ else:
+ if node.getAttribute('file') in self.images:
+ s = StringIO.StringIO(self.images[node.getAttribute('file')])
+ else:
+ try:
+ u = urllib.urlopen(str(node.getAttribute('file')))
+ s = StringIO.StringIO(u.read())
+ except:
+ u = file(os.path.join(self.path,str(node.getAttribute('file'))), 'rb')
+ s = StringIO.StringIO(u.read())
+ img = ImageReader(s)
+ (sx,sy) = img.getSize()
+
+ args = {}
+ for tag in ('width','height','x','y'):
+ if node.hasAttribute(tag):
+ args[tag] = utils.unit_get(node.getAttribute(tag))
+ if ('width' in args) and (not 'height' in args):
+ args['height'] = sy * args['width'] / sx
+ elif ('height' in args) and (not 'width' in args):
+ args['width'] = sx * args['height'] / sy
+ elif ('width' in args) and ('height' in args):
+ if (float(args['width'])/args['height'])>(float(sx)>sy):
+ args['width'] = sx * args['height'] / sy
+ else:
+ args['height'] = sy * args['width'] / sx
+ self.canvas.drawImage(img, **args)
+
+ def _path(self, node):
+ self.path = self.canvas.beginPath()
+ self.path.moveTo(**utils.attr_get(node, ['x','y']))
+ for n in node.childNodes:
+ if n.nodeType == node.ELEMENT_NODE:
+ if n.localName=='moveto':
+ vals = utils.text_get(n).split()
+ self.path.moveTo(utils.unit_get(vals[0]), utils.unit_get(vals[1]))
+ elif n.localName=='curvesto':
+ vals = utils.text_get(n).split()
+ while len(vals)>5:
+ pos=[]
+ while len(pos)<6:
+ pos.append(utils.unit_get(vals.pop(0)))
+ self.path.curveTo(*pos)
+ elif (n.nodeType == node.TEXT_NODE):
+ data = n.data.split() # Not sure if I must merge all TEXT_NODE ?
+ while len(data)>1:
+ x = utils.unit_get(data.pop(0))
+ y = utils.unit_get(data.pop(0))
+ self.path.lineTo(x,y)
+ if (not node.hasAttribute('close')) or utils.bool_get(node.getAttribute('close')):
+ self.path.close()
+ self.canvas.drawPath(self.path, **utils.attr_get(node, [], {'fill':'bool','stroke':'bool'}))
+
+ def render(self, node):
+ tags = {
+ 'drawCentredString': self._drawCenteredString,
+ 'drawRightString': self._drawRightString,
+ 'drawString': self._drawString,
+ 'rect': self._rect,
+ 'ellipse': self._ellipse,
+ 'lines': self._lines,
+ 'grid': self._grid,
+ 'curves': self._curves,
+ 'fill': lambda node: self.canvas.setFillColor(color.get(node.getAttribute('color'))),
+ 'stroke': lambda node: self.canvas.setStrokeColor(color.get(node.getAttribute('color'))),
+ 'setFont': lambda node: self.canvas.setFont(node.getAttribute('name'), utils.unit_get(node.getAttribute('size'))),
+ 'place': self._place,
+ 'circle': self._circle,
+ 'lineMode': self._line_mode,
+ 'path': self._path,
+ 'rotate': lambda node: self.canvas.rotate(float(node.getAttribute('degrees'))),
+ 'translate': self._translate,
+ 'image': self._image
+ }
+ for nd in node.childNodes:
+ if nd.nodeType==nd.ELEMENT_NODE:
+ for tag in tags:
+ if nd.localName==tag:
+ tags[tag](nd)
+ break
class _rml_draw(object):
- def __init__(self, node, styles, images={}, path='.'):
- self.node = node
- self.styles = styles
- self.canvas = None
- self.images = images
- self.path = path
-
- def render(self, canvas, doc):
- canvas.saveState()
- cnv = _rml_canvas(canvas, doc, self.styles, images=self.images, path=self.path)
- cnv.render(self.node)
- canvas.restoreState()
+ def __init__(self, node, styles, images={}, path='.'):
+ self.node = node
+ self.styles = styles
+ self.canvas = None
+ self.images = images
+ self.path = path
+
+ def render(self, canvas, doc):
+ canvas.saveState()
+ cnv = _rml_canvas(canvas, doc, self.styles, images=self.images, path=self.path)
+ cnv.render(self.node)
+ canvas.restoreState()
class _rml_flowable(object):
- def __init__(self, doc, images={}, path='.'):
- self.doc = doc
- self.styles = doc.styles
- self.images = images
- self.path = path
-
- def _textual(self, node):
- rc = ''
- for n in node.childNodes:
- if n.nodeType == node.ELEMENT_NODE:
- if n.localName == 'getName':
- newNode = self.doc.dom.createTextNode(self.styles.names.get(n.getAttribute('id'),'Unknown name'))
- node.insertBefore(newNode, n)
- node.removeChild(n)
- n = newNode
- elif n.localName == 'pageNumber':
- rc += '<pageNumber/>' # TODO: change this !
- else:
- #CHECKME: I wonder if this is useful since we don't stock the result. Maybe for the getName tag?
- self._textual(n)
- rc += n.toxml()
- elif n.nodeType in (node.CDATA_SECTION_NODE, node.TEXT_NODE):
- rc += str2xml(n.data)
- return rc.encode(encoding, 'replace')
-
- def _table(self, node):
- length = 0
- colwidths = None
- rowheights = None
- data = []
- childs = _child_get(node,'tr')
- if not childs:
- return None
- posy = 0
- styles = []
- for tr in childs:
- paraStyle = None
- if tr.hasAttribute('style'):
- st = copy.deepcopy(self.styles.table_styles[tr.getAttribute('style')])
- for s in st._cmds:
- s[1][1] = posy
- s[2][1] = posy
- styles.append(st)
- if tr.hasAttribute('paraStyle'):
- paraStyle = self.styles.styles[tr.getAttribute('paraStyle')]
-
- data2 = []
- posx = 0
- for td in _child_get(tr, 'td'):
- if td.hasAttribute('style'):
- st = copy.deepcopy(self.styles.table_styles[td.getAttribute('style')])
- for s in st._cmds:
- s[1][1] = posy
- s[2][1] = posy
- s[1][0] = posx
- s[2][0] = posx
- styles.append(st)
- if td.hasAttribute('paraStyle'):
- # TODO: merge styles
- paraStyle = self.styles.styles[td.getAttribute('paraStyle')]
- posx += 1
-
- flow = []
- for n in td.childNodes:
- if n.nodeType==node.ELEMENT_NODE:
- fl = self._flowable(n, extra_style=paraStyle)
- flow.append( fl )
- if not len(flow):
- flow = self._textual(td)
- data2.append( flow )
- if len(data2)>length:
- length=len(data2)
- for ab in data:
- while len(ab)<length:
- ab.append('')
- while len(data2)<length:
- data2.append('')
- data.append( data2 )
- posy += 1
- if node.hasAttribute('colWidths'):
- assert length == len(node.getAttribute('colWidths').split(','))
- colwidths = [utils.unit_get(f.strip()) for f in node.getAttribute('colWidths').split(',')]
- if node.hasAttribute('rowHeights'):
- rowheights = [utils.unit_get(f.strip()) for f in node.getAttribute('rowHeights').split(',')]
- if len(rowheights) == 1:
- rowheights = rowheights[0]
- table = platypus.Table(data = data, colWidths=colwidths, rowHeights=rowheights, **(utils.attr_get(node, ['splitByRow'] ,{'repeatRows':'int','repeatCols':'int'})))
- if node.hasAttribute('style'):
- table.setStyle(self.styles.table_styles[node.getAttribute('style')])
- for s in styles:
- table.setStyle(s)
- return table
-
- def _illustration(self, node):
- class Illustration(platypus.flowables.Flowable):
- def __init__(self, node, styles, self2):
- self.node = node
- self.styles = styles
- self.width = utils.unit_get(node.getAttribute('width'))
- self.height = utils.unit_get(node.getAttribute('height'))
- self.self2 = self2
- def wrap(self, *args):
- return (self.width, self.height)
- def draw(self):
- canvas = self.canv
- drw = _rml_draw(self.node, self.styles, images=self.self2.images, path=self.self2.path)
- drw.render(self.canv, None)
- return Illustration(node, self.styles, self)
-
- def _textual_image(self, node):
- import base64
- rc = ''
- for n in node.childNodes:
- if n.nodeType in (node.CDATA_SECTION_NODE, node.TEXT_NODE):
- rc += n.data
- return base64.decodestring(rc)
-
- def _flowable(self, node, extra_style=None):
- if node.localName=='para':
- style = self.styles.para_style_get(node)
- if extra_style:
- style.__dict__.update(extra_style)
- return platypus.Paragraph(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText':'str'})))
- elif node.localName=='barCode':
- try:
- from reportlab.graphics.barcode import code128
- from reportlab.graphics.barcode import code39
- from reportlab.graphics.barcode import code93
- from reportlab.graphics.barcode import common
- from reportlab.graphics.barcode import fourstate
- from reportlab.graphics.barcode import usps
- except Exception, e:
- print 'Warning: Reportlab barcode extension not installed !'
- return None
- args = utils.attr_get(node, [], {'ratio':'float','xdim':'unit','height':'unit','checksum':'bool','quiet':'bool'})
- codes = {
- 'codabar': lambda x: common.Codabar(x, **args),
- 'code11': lambda x: common.Code11(x, **args),
- 'code128': lambda x: code128.Code128(x, **args),
- 'standard39': lambda x: code39.Standard39(x, **args),
- 'standard93': lambda x: code93.Standard93(x, **args),
- 'i2of5': lambda x: common.I2of5(x, **args),
- 'extended39': lambda x: code39.Extended39(x, **args),
- 'extended93': lambda x: code93.Extended93(x, **args),
- 'msi': lambda x: common.MSI(x, **args),
- 'fim': lambda x: usps.FIM(x, **args),
- 'postnet': lambda x: usps.POSTNET(x, **args),
- }
- code = 'code128'
- if node.hasAttribute('code'):
- code = node.getAttribute('code').lower()
- return codes[code](self._textual(node))
- elif node.localName=='name':
- self.styles.names[ node.getAttribute('id')] = node.getAttribute('value')
- return None
- elif node.localName=='xpre':
- style = self.styles.para_style_get(node)
- return platypus.XPreformatted(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText':'str','dedent':'int','frags':'int'})))
- elif node.localName=='pre':
- style = self.styles.para_style_get(node)
- return platypus.Preformatted(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText':'str','dedent':'int'})))
- elif node.localName=='illustration':
- return self._illustration(node)
- elif node.localName=='blockTable':
- return self._table(node)
- elif node.localName=='title':
- styles = reportlab.lib.styles.getSampleStyleSheet()
- style = styles['Title']
- return platypus.Paragraph(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText':'str'})))
- elif re.match('^h([1-9]+[0-9]*)$', node.localName):
- styles = reportlab.lib.styles.getSampleStyleSheet()
- style = styles['Heading'+str(node.localName[1:])]
- return platypus.Paragraph(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText':'str'})))
- elif node.localName=='image':
- if not node.hasAttribute('file'):
- if node.hasAttribute('name'):
- image_data = self.doc.images[node.getAttribute('name')].read()
- else:
- import base64
- image_data = base64.decodestring(node.firstChild.nodeValue)
- image = StringIO.StringIO(image_data)
- return platypus.Image(image, mask=(250,255,250,255,250,255), **(utils.attr_get(node, ['width','height'])))
- else:
- return platypus.Image(node.getAttribute('file'), mask=(250,255,250,255,250,255), **(utils.attr_get(node, ['width','height'])))
-
- from reportlab.lib.utils import ImageReader
- name = str(node.getAttribute('file'))
- img = ImageReader(name)
- (sx,sy) = img.getSize()
-
- args = {}
- for tag in ('width','height'):
- if node.hasAttribute(tag):
- args[tag] = utils.unit_get(node.getAttribute(tag))
- if ('width' in args) and (not 'height' in args):
- args['height'] = sy * args['width'] / sx
- elif ('height' in args) and (not 'width' in args):
- args['width'] = sx * args['height'] / sy
- elif ('width' in args) and ('height' in args):
- if (float(args['width'])/args['height'])>(float(sx)>sy):
- args['width'] = sx * args['height'] / sy
- else:
- args['height'] = sy * args['width'] / sx
- return platypus.Image(name, mask=(250,255,250,255,250,255), **args)
- elif node.localName=='spacer':
- if node.hasAttribute('width'):
- width = utils.unit_get(node.getAttribute('width'))
- else:
- width = utils.unit_get('1cm')
- length = utils.unit_get(node.getAttribute('length'))
- return platypus.Spacer(width=width, height=length)
- elif node.localName=='section':
- return self.render(node)
- elif node.localName == 'pageNumberReset':
- return PageReset()
- elif node.localName in ('pageBreak', 'nextPage'):
- return platypus.PageBreak()
- elif node.localName=='condPageBreak':
- return platypus.CondPageBreak(**(utils.attr_get(node, ['height'])))
- elif node.localName=='setNextTemplate':
- return platypus.NextPageTemplate(str(node.getAttribute('name')))
- elif node.localName=='nextFrame':
- return platypus.CondPageBreak(1000) # TODO: change the 1000 !
- elif node.localName == 'setNextFrame':
- from reportlab.platypus.doctemplate import NextFrameFlowable
- return NextFrameFlowable(str(node.getAttribute('name')))
- elif node.localName == 'currentFrame':
- from reportlab.platypus.doctemplate import CurrentFrameFlowable
- return CurrentFrameFlowable(str(node.getAttribute('name')))
- elif node.localName == 'frameEnd':
- return EndFrameFlowable()
- else:
- sys.stderr.write('Warning: flowable not yet implemented: %s !\n' % (node.localName,))
- return None
-
- def render(self, node_story):
- story = []
- node = node_story.firstChild
- while node:
- if node.nodeType == node.ELEMENT_NODE:
- flow = self._flowable(node)
- if flow:
- if type(flow) == type([]):
- story = story + flow
- else:
- story.append(flow)
- node = node.nextSibling
- return story
+ def __init__(self, doc, images={}, path='.'):
+ self.doc = doc
+ self.styles = doc.styles
+ self.images = images
+ self.path = path
+
+ def _textual(self, node):
+ rc = ''
+ for n in node.childNodes:
+ if n.nodeType == node.ELEMENT_NODE:
+ if n.localName == 'getName':
+ newNode = self.doc.dom.createTextNode(self.styles.names.get(n.getAttribute('id'),'Unknown name'))
+ node.insertBefore(newNode, n)
+ node.removeChild(n)
+ n = newNode
+ elif n.localName == 'pageNumber':
+ rc += '<pageNumber/>' # TODO: change this !
+ else:
+ #CHECKME: I wonder if this is useful since we don't stock the result. Maybe for the getName tag?
+ self._textual(n)
+ rc += n.toxml()
+ elif n.nodeType in (node.CDATA_SECTION_NODE, node.TEXT_NODE):
+ rc += str2xml(n.data)
+ return rc.encode(encoding, 'replace')
+
+ def _table(self, node):
+ length = 0
+ colwidths = None
+ rowheights = None
+ data = []
+ childs = _child_get(node,'tr')
+ if not childs:
+ return None
+ posy = 0
+ styles = []
+ for tr in childs:
+ paraStyle = None
+ if tr.hasAttribute('style'):
+ st = copy.deepcopy(self.styles.table_styles[tr.getAttribute('style')])
+ for s in st._cmds:
+ s[1][1] = posy
+ s[2][1] = posy
+ styles.append(st)
+ if tr.hasAttribute('paraStyle'):
+ paraStyle = self.styles.styles[tr.getAttribute('paraStyle')]
+
+ data2 = []
+ posx = 0
+ for td in _child_get(tr, 'td'):
+ if td.hasAttribute('style'):
+ st = copy.deepcopy(self.styles.table_styles[td.getAttribute('style')])
+ for s in st._cmds:
+ s[1][1] = posy
+ s[2][1] = posy
+ s[1][0] = posx
+ s[2][0] = posx
+ styles.append(st)
+ if td.hasAttribute('paraStyle'):
+ # TODO: merge styles
+ paraStyle = self.styles.styles[td.getAttribute('paraStyle')]
+ posx += 1
+
+ flow = []
+ for n in td.childNodes:
+ if n.nodeType==node.ELEMENT_NODE:
+ fl = self._flowable(n, extra_style=paraStyle)
+ flow.append( fl )
+ if not len(flow):
+ flow = self._textual(td)
+ data2.append( flow )
+ if len(data2)>length:
+ length=len(data2)
+ for ab in data:
+ while len(ab)<length:
+ ab.append('')
+ while len(data2)<length:
+ data2.append('')
+ data.append( data2 )
+ posy += 1
+ if node.hasAttribute('colWidths'):
+ assert length == len(node.getAttribute('colWidths').split(','))
+ colwidths = [utils.unit_get(f.strip()) for f in node.getAttribute('colWidths').split(',')]
+ if node.hasAttribute('rowHeights'):
+ rowheights = [utils.unit_get(f.strip()) for f in node.getAttribute('rowHeights').split(',')]
+ if len(rowheights) == 1:
+ rowheights = rowheights[0]
+ table = platypus.Table(data = data, colWidths=colwidths, rowHeights=rowheights, **(utils.attr_get(node, ['splitByRow'] ,{'repeatRows':'int','repeatCols':'int'})))
+ if node.hasAttribute('style'):
+ table.setStyle(self.styles.table_styles[node.getAttribute('style')])
+ for s in styles:
+ table.setStyle(s)
+ return table
+
+ def _illustration(self, node):
+ class Illustration(platypus.flowables.Flowable):
+ def __init__(self, node, styles, self2):
+ self.node = node
+ self.styles = styles
+ self.width = utils.unit_get(node.getAttribute('width'))
+ self.height = utils.unit_get(node.getAttribute('height'))
+ self.self2 = self2
+ def wrap(self, *args):
+ return (self.width, self.height)
+ def draw(self):
+ canvas = self.canv
+ drw = _rml_draw(self.node, self.styles, images=self.self2.images, path=self.self2.path)
+ drw.render(self.canv, None)
+ return Illustration(node, self.styles, self)
+
+ def _textual_image(self, node):
+ import base64
+ rc = ''
+ for n in node.childNodes:
+ if n.nodeType in (node.CDATA_SECTION_NODE, node.TEXT_NODE):
+ rc += n.data
+ return base64.decodestring(rc)
+
+ def _flowable(self, node, extra_style=None):
+ if node.localName=='para':
+ style = self.styles.para_style_get(node)
+ if extra_style:
+ style.__dict__.update(extra_style)
+ return platypus.Paragraph(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText':'str'})))
+ elif node.localName=='barCode':
+ try:
+ from reportlab.graphics.barcode import code128
+ from reportlab.graphics.barcode import code39
+ from reportlab.graphics.barcode import code93
+ from reportlab.graphics.barcode import common
+ from reportlab.graphics.barcode import fourstate
+ from reportlab.graphics.barcode import usps
+ except Exception, e:
+ print 'Warning: Reportlab barcode extension not installed !'
+ return None
+ args = utils.attr_get(node, [], {'ratio':'float','xdim':'unit','height':'unit','checksum':'bool','quiet':'bool'})
+ codes = {
+ 'codabar': lambda x: common.Codabar(x, **args),
+ 'code11': lambda x: common.Code11(x, **args),
+ 'code128': lambda x: code128.Code128(x, **args),
+ 'standard39': lambda x: code39.Standard39(x, **args),
+ 'standard93': lambda x: code93.Standard93(x, **args),
+ 'i2of5': lambda x: common.I2of5(x, **args),
+ 'extended39': lambda x: code39.Extended39(x, **args),
+ 'extended93': lambda x: code93.Extended93(x, **args),
+ 'msi': lambda x: common.MSI(x, **args),
+ 'fim': lambda x: usps.FIM(x, **args),
+ 'postnet': lambda x: usps.POSTNET(x, **args),
+ }
+ code = 'code128'
+ if node.hasAttribute('code'):
+ code = node.getAttribute('code').lower()
+ return codes[code](self._textual(node))
+ elif node.localName=='name':
+ self.styles.names[ node.getAttribute('id')] = node.getAttribute('value')
+ return None
+ elif node.localName=='xpre':
+ style = self.styles.para_style_get(node)
+ return platypus.XPreformatted(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText':'str','dedent':'int','frags':'int'})))
+ elif node.localName=='pre':
+ style = self.styles.para_style_get(node)
+ return platypus.Preformatted(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText':'str','dedent':'int'})))
+ elif node.localName=='illustration':
+ return self._illustration(node)
+ elif node.localName=='blockTable':
+ return self._table(node)
+ elif node.localName=='title':
+ styles = reportlab.lib.styles.getSampleStyleSheet()
+ style = styles['Title']
+ return platypus.Paragraph(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText':'str'})))
+ elif re.match('^h([1-9]+[0-9]*)$', node.localName):
+ styles = reportlab.lib.styles.getSampleStyleSheet()
+ style = styles['Heading'+str(node.localName[1:])]
+ return platypus.Paragraph(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText':'str'})))
+ elif node.localName=='image':
+ if not node.hasAttribute('file'):
+ if node.hasAttribute('name'):
+ image_data = self.doc.images[node.getAttribute('name')].read()
+ else:
+ import base64
+ image_data = base64.decodestring(node.firstChild.nodeValue)
+ image = StringIO.StringIO(image_data)
+ return platypus.Image(image, mask=(250,255,250,255,250,255), **(utils.attr_get(node, ['width','height'])))
+ else:
+ return platypus.Image(node.getAttribute('file'), mask=(250,255,250,255,250,255), **(utils.attr_get(node, ['width','height'])))
+
+ from reportlab.lib.utils import ImageReader
+ name = str(node.getAttribute('file'))
+ img = ImageReader(name)
+ (sx,sy) = img.getSize()
+
+ args = {}
+ for tag in ('width','height'):
+ if node.hasAttribute(tag):
+ args[tag] = utils.unit_get(node.getAttribute(tag))
+ if ('width' in args) and (not 'height' in args):
+ args['height'] = sy * args['width'] / sx
+ elif ('height' in args) and (not 'width' in args):
+ args['width'] = sx * args['height'] / sy
+ elif ('width' in args) and ('height' in args):
+ if (float(args['width'])/args['height'])>(float(sx)>sy):
+ args['width'] = sx * args['height'] / sy
+ else:
+ args['height'] = sy * args['width'] / sx
+ return platypus.Image(name, mask=(250,255,250,255,250,255), **args)
+ elif node.localName=='spacer':
+ if node.hasAttribute('width'):
+ width = utils.unit_get(node.getAttribute('width'))
+ else:
+ width = utils.unit_get('1cm')
+ length = utils.unit_get(node.getAttribute('length'))
+ return platypus.Spacer(width=width, height=length)
+ elif node.localName=='section':
+ return self.render(node)
+ elif node.localName == 'pageNumberReset':
+ return PageReset()
+ elif node.localName in ('pageBreak', 'nextPage'):
+ return platypus.PageBreak()
+ elif node.localName=='condPageBreak':
+ return platypus.CondPageBreak(**(utils.attr_get(node, ['height'])))
+ elif node.localName=='setNextTemplate':
+ return platypus.NextPageTemplate(str(node.getAttribute('name')))
+ elif node.localName=='nextFrame':
+ return platypus.CondPageBreak(1000) # TODO: change the 1000 !
+ elif node.localName == 'setNextFrame':
+ from reportlab.platypus.doctemplate import NextFrameFlowable
+ return NextFrameFlowable(str(node.getAttribute('name')))
+ elif node.localName == 'currentFrame':
+ from reportlab.platypus.doctemplate import CurrentFrameFlowable
+ return CurrentFrameFlowable(str(node.getAttribute('name')))
+ elif node.localName == 'frameEnd':
+ return EndFrameFlowable()
+ else:
+ sys.stderr.write('Warning: flowable not yet implemented: %s !\n' % (node.localName,))
+ return None
+
+ def render(self, node_story):
+ story = []
+ node = node_story.firstChild
+ while node:
+ if node.nodeType == node.ELEMENT_NODE:
+ flow = self._flowable(node)
+ if flow:
+ if type(flow) == type([]):
+ story = story + flow
+ else:
+ story.append(flow)
+ node = node.nextSibling
+ return story
from reportlab.platypus.doctemplate import ActionFlowable
class EndFrameFlowable(ActionFlowable):
- def __init__(self,resume=0):
- ActionFlowable.__init__(self,('frameEnd',resume))
+ def __init__(self,resume=0):
+ ActionFlowable.__init__(self,('frameEnd',resume))
class TinyDocTemplate(platypus.BaseDocTemplate):
- def ___handle_pageBegin(self):
- self.page = self.page + 1
- self.pageTemplate.beforeDrawPage(self.canv,self)
- self.pageTemplate.checkPageSize(self.canv,self)
- self.pageTemplate.onPage(self.canv,self)
- for f in self.pageTemplate.frames: f._reset()
- self.beforePage()
- #keep a count of flowables added to this page. zero indicates bad stuff
- self._curPageFlowableCount = 0
- if hasattr(self,'_nextFrameIndex'):
- del self._nextFrameIndex
- for f in self.pageTemplate.frames:
- if f.id == 'first':
- self.frame = f
- break
- self.handle_frameBegin()
- def afterFlowable(self, flowable):
- if isinstance(flowable, PageReset):
- self.canv._pageNumber = 0
+ def ___handle_pageBegin(self):
+ self.page = self.page + 1
+ self.pageTemplate.beforeDrawPage(self.canv,self)
+ self.pageTemplate.checkPageSize(self.canv,self)
+ self.pageTemplate.onPage(self.canv,self)
+ for f in self.pageTemplate.frames: f._reset()
+ self.beforePage()
+ #keep a count of flowables added to this page. zero indicates bad stuff
+ self._curPageFlowableCount = 0
+ if hasattr(self,'_nextFrameIndex'):
+ del self._nextFrameIndex
+ for f in self.pageTemplate.frames:
+ if f.id == 'first':
+ self.frame = f
+ break
+ self.handle_frameBegin()
+ def afterFlowable(self, flowable):
+ if isinstance(flowable, PageReset):
+ self.canv._pageNumber = 0
class _rml_template(object):
- def __init__(self, out, node, doc, images={}, path='.'):
- self.images= images
- self.path = path
- if not node.hasAttribute('pageSize'):
- pageSize = (utils.unit_get('21cm'), utils.unit_get('29.7cm'))
- else:
- ps = map(lambda x:x.strip(), node.getAttribute('pageSize').replace(')', '').replace('(', '').split(','))
- pageSize = ( utils.unit_get(ps[0]),utils.unit_get(ps[1]) )
- cm = reportlab.lib.units.cm
- self.doc_tmpl = TinyDocTemplate(out, pagesize=pageSize, **utils.attr_get(node, ['leftMargin','rightMargin','topMargin','bottomMargin'], {'allowSplitting':'int','showBoundary':'bool','title':'str','author':'str'}))
- self.page_templates = []
- self.styles = doc.styles
- self.doc = doc
- pts = node.getElementsByTagName('pageTemplate')
- for pt in pts:
- frames = []
- for frame_el in pt.getElementsByTagName('frame'):
- frame = platypus.Frame( **(utils.attr_get(frame_el, ['x1','y1', 'width','height', 'leftPadding', 'rightPadding', 'bottomPadding', 'topPadding'], {'id':'str', 'showBoundary':'bool'})) )
- if utils.attr_get(frame_el, ['last']):
- frame.lastFrame = True
- frames.append( frame )
- gr = pt.getElementsByTagName('pageGraphics')
- if len(gr):
- drw = _rml_draw(gr[0], self.doc, images=images, path=self.path)
- self.page_templates.append( platypus.PageTemplate(frames=frames, onPage=drw.render, **utils.attr_get(pt, [], {'id':'str'}) ))
- else:
- self.page_templates.append( platypus.PageTemplate(frames=frames, **utils.attr_get(pt, [], {'id':'str'}) ))
- self.doc_tmpl.addPageTemplates(self.page_templates)
-
- def render(self, node_stories):
- fis = []
- r = _rml_flowable(self.doc,images=self.images, path=self.path)
- for node_story in node_stories:
- fis += r.render(node_story)
- if node_story==node_stories[-1]:
-
- fis.append(PageCount())
-
- fis.append(platypus.PageBreak())
-
- self.doc_tmpl.build(fis)
+ def __init__(self, out, node, doc, images={}, path='.'):
+ self.images= images
+ self.path = path
+ if not node.hasAttribute('pageSize'):
+ pageSize = (utils.unit_get('21cm'), utils.unit_get('29.7cm'))
+ else:
+ ps = map(lambda x:x.strip(), node.getAttribute('pageSize').replace(')', '').replace('(', '').split(','))
+ pageSize = ( utils.unit_get(ps[0]),utils.unit_get(ps[1]) )
+ cm = reportlab.lib.units.cm
+ self.doc_tmpl = TinyDocTemplate(out, pagesize=pageSize, **utils.attr_get(node, ['leftMargin','rightMargin','topMargin','bottomMargin'], {'allowSplitting':'int','showBoundary':'bool','title':'str','author':'str'}))
+ self.page_templates = []
+ self.styles = doc.styles
+ self.doc = doc
+ pts = node.getElementsByTagName('pageTemplate')
+ for pt in pts:
+ frames = []
+ for frame_el in pt.getElementsByTagName('frame'):
+ frame = platypus.Frame( **(utils.attr_get(frame_el, ['x1','y1', 'width','height', 'leftPadding', 'rightPadding', 'bottomPadding', 'topPadding'], {'id':'str', 'showBoundary':'bool'})) )
+ if utils.attr_get(frame_el, ['last']):
+ frame.lastFrame = True
+ frames.append( frame )
+ gr = pt.getElementsByTagName('pageGraphics')
+ if len(gr):
+ drw = _rml_draw(gr[0], self.doc, images=images, path=self.path)
+ self.page_templates.append( platypus.PageTemplate(frames=frames, onPage=drw.render, **utils.attr_get(pt, [], {'id':'str'}) ))
+ else:
+ self.page_templates.append( platypus.PageTemplate(frames=frames, **utils.attr_get(pt, [], {'id':'str'}) ))
+ self.doc_tmpl.addPageTemplates(self.page_templates)
+
+ def render(self, node_stories):
+ fis = []
+ r = _rml_flowable(self.doc,images=self.images, path=self.path)
+ for node_story in node_stories:
+ fis += r.render(node_story)
+ if node_story==node_stories[-1]:
+
+ fis.append(PageCount())
+
+ fis.append(platypus.PageBreak())
+
+ self.doc_tmpl.build(fis)
def parseString(data, fout=None, images={}, path='.'):
- r = _rml_doc(data, images, path)
- if fout:
- fp = file(fout,'wb')
- r.render(fp)
- fp.close()
- return fout
- else:
- fp = StringIO.StringIO()
- r.render(fp)
- return fp.getvalue()
+ r = _rml_doc(data, images, path)
+ if fout:
+ fp = file(fout,'wb')
+ r.render(fp)
+ fp.close()
+ return fout
+ else:
+ fp = StringIO.StringIO()
+ r.render(fp)
+ return fp.getvalue()
def trml2pdf_help():
- print 'Usage: trml2pdf input.rml >output.pdf'
- print 'Render the standard input (RML) and output a PDF file'
- sys.exit(0)
+ print 'Usage: trml2pdf input.rml >output.pdf'
+ print 'Render the standard input (RML) and output a PDF file'
+ sys.exit(0)
if __name__=="__main__":
- if len(sys.argv)>1:
- if sys.argv[1]=='--help':
- trml2pdf_help()
- print parseString(file(sys.argv[1], 'r').read()),
- else:
- print 'Usage: trml2pdf input.rml >output.pdf'
- print 'Try \'trml2pdf --help\' for more information.'
+ if len(sys.argv)>1:
+ if sys.argv[1]=='--help':
+ trml2pdf_help()
+ print parseString(file(sys.argv[1], 'r').read()),
+ else:
+ print 'Usage: trml2pdf input.rml >output.pdf'
+ print 'Try \'trml2pdf --help\' for more information.'
diff --git a/bin/report/render/rml2pdf/utils.py b/bin/report/render/rml2pdf/utils.py
index 555d00bdb13..5ee7997a5e5 100644
--- a/bin/report/render/rml2pdf/utils.py
+++ b/bin/report/render/rml2pdf/utils.py
@@ -48,47 +48,47 @@ import re
import reportlab
def text_get(node):
- rc = ''
- for node in node.childNodes:
- if node.nodeType == node.TEXT_NODE:
- rc = rc + node.data
- return rc
+ rc = ''
+ for node in node.childNodes:
+ if node.nodeType == node.TEXT_NODE:
+ rc = rc + node.data
+ return rc
units = [
- (re.compile('^(-?[0-9\.]+)\s*in$'), reportlab.lib.units.inch),
- (re.compile('^(-?[0-9\.]+)\s*cm$'), reportlab.lib.units.cm),
- (re.compile('^(-?[0-9\.]+)\s*mm$'), reportlab.lib.units.mm),
- (re.compile('^(-?[0-9\.]+)\s*$'), 1)
+ (re.compile('^(-?[0-9\.]+)\s*in$'), reportlab.lib.units.inch),
+ (re.compile('^(-?[0-9\.]+)\s*cm$'), reportlab.lib.units.cm),
+ (re.compile('^(-?[0-9\.]+)\s*mm$'), reportlab.lib.units.mm),
+ (re.compile('^(-?[0-9\.]+)\s*$'), 1)
]
def unit_get(size):
- global units
- for unit in units:
- res = unit[0].search(size, 0)
- if res:
- return unit[1]*float(res.group(1))
- return False
+ global units
+ for unit in units:
+ res = unit[0].search(size, 0)
+ if res:
+ return unit[1]*float(res.group(1))
+ return False
def tuple_int_get(node, attr_name, default=None):
- if not node.hasAttribute(attr_name):
- return default
- res = [int(x) for x in node.getAttribute(attr_name).split(',')]
- return res
+ if not node.hasAttribute(attr_name):
+ return default
+ res = [int(x) for x in node.getAttribute(attr_name).split(',')]
+ return res
def bool_get(value):
- return (str(value)=="1") or (value.lower()=='yes')
+ return (str(value)=="1") or (value.lower()=='yes')
def attr_get(node, attrs, dict={}):
- res = {}
- for name in attrs:
- if node.hasAttribute(name):
- res[name] = unit_get(node.getAttribute(name))
- for key in dict:
- if node.hasAttribute(key):
- if dict[key]=='str':
- res[key] = str(node.getAttribute(key))
- elif dict[key]=='bool':
- res[key] = bool_get(node.getAttribute(key))
- elif dict[key]=='int':
- res[key] = int(node.getAttribute(key))
- return res
+ res = {}
+ for name in attrs:
+ if node.hasAttribute(name):
+ res[name] = unit_get(node.getAttribute(name))
+ for key in dict:
+ if node.hasAttribute(key):
+ if dict[key]=='str':
+ res[key] = str(node.getAttribute(key))
+ elif dict[key]=='bool':
+ res[key] = bool_get(node.getAttribute(key))
+ elif dict[key]=='int':
+ res[key] = int(node.getAttribute(key))
+ return res
diff --git a/bin/report/render/simple.py b/bin/report/render/simple.py
index ea830250d71..a3a642a6119 100644
--- a/bin/report/render/simple.py
+++ b/bin/report/render/simple.py
@@ -40,52 +40,52 @@ import reportlab.lib
import copy
class simple(render.render):
- def _render(self):
- self.result = StringIO()
- parser = xml.dom.minidom.parseString(self.xml)
+ def _render(self):
+ self.result = StringIO()
+ parser = xml.dom.minidom.parseString(self.xml)
- title = parser.documentElement.tagName
- doc = SimpleDocTemplate(self.result, pagesize=A4, title=title,
- author='Tiny ERP, Fabien Pinckaers', leftmargin=10*mm, rightmargin=10*mm)
+ title = parser.documentElement.tagName
+ doc = SimpleDocTemplate(self.result, pagesize=A4, title=title,
+ author='Tiny ERP, Fabien Pinckaers', leftmargin=10*mm, rightmargin=10*mm)
- styles = reportlab.lib.styles.getSampleStyleSheet()
- title_style = copy.deepcopy(styles["Heading1"])
- title_style.alignment = reportlab.lib.enums.TA_CENTER
- story = [ Paragraph(title, title_style) ]
- style_level = {}
- nodes = [ (parser.documentElement,0) ]
- while len(nodes):
- node = nodes.pop(0)
- value = ''
- n=len(node[0].childNodes)-1
- while n>=0:
- if node[0].childNodes[n].nodeType==3:
- value += node[0].childNodes[n].nodeValue
- else:
- nodes.insert( 0, (node[0].childNodes[n], node[1]+1) )
- n-=1
- if not node[1] in style_level:
- style = copy.deepcopy(styles["Normal"])
- style.leftIndent=node[1]*6*mm
- style.firstLineIndent=-3*mm
- style_level[node[1]] = style
- story.append( Paragraph('<b>%s</b>: %s' % (node[0].tagName, value), style_level[node[1]]))
- doc.build(story)
- return self.result.getvalue()
+ styles = reportlab.lib.styles.getSampleStyleSheet()
+ title_style = copy.deepcopy(styles["Heading1"])
+ title_style.alignment = reportlab.lib.enums.TA_CENTER
+ story = [ Paragraph(title, title_style) ]
+ style_level = {}
+ nodes = [ (parser.documentElement,0) ]
+ while len(nodes):
+ node = nodes.pop(0)
+ value = ''
+ n=len(node[0].childNodes)-1
+ while n>=0:
+ if node[0].childNodes[n].nodeType==3:
+ value += node[0].childNodes[n].nodeValue
+ else:
+ nodes.insert( 0, (node[0].childNodes[n], node[1]+1) )
+ n-=1
+ if not node[1] in style_level:
+ style = copy.deepcopy(styles["Normal"])
+ style.leftIndent=node[1]*6*mm
+ style.firstLineIndent=-3*mm
+ style_level[node[1]] = style
+ story.append( Paragraph('<b>%s</b>: %s' % (node[0].tagName, value), style_level[node[1]]))
+ doc.build(story)
+ return self.result.getvalue()
if __name__=='__main__':
- import time
- s = simple('''<test>
- <author-list>
- <author>
- <name>Fabien Pinckaers</name>
- <age>23</age>
- </author>
- <author>
- <name>Michel Pinckaers</name>
- <age>53</age>
- </author>
- No other
- </author-list>
- </test>''')
- print s.render()
+ import time
+ s = simple('''<test>
+ <author-list>
+ <author>
+ <name>Fabien Pinckaers</name>
+ <age>23</age>
+ </author>
+ <author>
+ <name>Michel Pinckaers</name>
+ <age>53</age>
+ </author>
+ No other
+ </author-list>
+ </test>''')
+ print s.render()
diff --git a/bin/report/report_sxw.py b/bin/report/report_sxw.py
index 586527a13d0..13a3ca02f3b 100644
--- a/bin/report/report_sxw.py
+++ b/bin/report/report_sxw.py
@@ -51,611 +51,611 @@ HM_FORMAT = '%H:%M:%S'
import base64
if not hasattr(locale, 'nl_langinfo'):
- locale.nl_langinfo = lambda *a: '%x'
+ locale.nl_langinfo = lambda *a: '%x'
if not hasattr(locale, 'D_FMT'):
- locale.D_FMT = None
+ locale.D_FMT = None
rml_parents = {
- 'tr':1,
- 'li':1,
- 'story': 0,
- 'section': 0
+ 'tr':1,
+ 'li':1,
+ 'story': 0,
+ 'section': 0
}
rml_tag="para"
sxw_parents = {
- 'table-row': 1,
- 'list-item': 1,
- 'body': 0,
- 'section': 0,
+ 'table-row': 1,
+ 'list-item': 1,
+ 'body': 0,
+ 'section': 0,
}
sxw_tag = "p"
rml2sxw = {
- 'para': 'p',
+ 'para': 'p',
}
_LOCALE2WIN32 = {
- 'af_ZA': 'Afrikaans_South Africa',
- 'sq_AL': 'Albanian_Albania',
- 'ar_SA': 'Arabic_Saudi Arabia',
- 'eu_ES': 'Basque_Spain',
- 'be_BY': 'Belarusian_Belarus',
- 'bs_BA': 'Serbian (Latin)',
- 'bg_BG': 'Bulgarian_Bulgaria',
- 'ca_ES': 'Catalan_Spain',
- 'hr_HR': 'Croatian_Croatia',
- 'zh_CN': 'Chinese_China',
- 'zh_TW': 'Chinese_Taiwan',
- 'cs_CZ': 'Czech_Czech Republic',
- 'da_DK': 'Danish_Denmark',
- 'nl_NL': 'Dutch_Netherlands',
- 'et_EE': 'Estonian_Estonia',
- 'fa_IR': 'Farsi_Iran',
- 'ph_PH': 'Filipino_Philippines',
- 'fi_FI': 'Finnish_Finland',
- 'fr_FR': 'French_France',
- 'fr_BE': 'French_France',
- 'fr_CH': 'French_France',
- 'fr_CA': 'French_France',
- 'ga': 'Scottish Gaelic',
- 'gl_ES': 'Galician_Spain',
- 'ka_GE': 'Georgian_Georgia',
- 'de_DE': 'German_Germany',
- 'el_GR': 'Greek_Greece',
- 'gu': 'Gujarati_India',
- 'he_IL': 'Hebrew_Israel',
- 'hi_IN': 'Hindi',
- 'hu': 'Hungarian_Hungary',
- 'is_IS': 'Icelandic_Iceland',
- 'id_ID': 'Indonesian_indonesia',
- 'it_IT': 'Italian_Italy',
- 'ja_JP': 'Japanese_Japan',
- 'kn_IN': 'Kannada',
- 'km_KH': 'Khmer',
- 'ko_KR': 'Korean_Korea',
- 'lo_LA': 'Lao_Laos',
- 'lt_LT': 'Lithuanian_Lithuania',
- 'lat': 'Latvian_Latvia',
- 'ml_IN': 'Malayalam_India',
- 'id_ID': 'Indonesian_indonesia',
- 'mi_NZ': 'Maori',
- 'mn': 'Cyrillic_Mongolian',
- 'no_NO': 'Norwegian_Norway',
- 'nn_NO': 'Norwegian-Nynorsk_Norway',
- 'pl': 'Polish_Poland',
- 'pt_PT': 'Portuguese_Portugal',
- 'pt_BR': 'Portuguese_Brazil',
- 'ro_RO': 'Romanian_Romania',
- 'ru_RU': 'Russian_Russia',
- 'mi_NZ': 'Maori',
- 'sr_CS': 'Serbian (Cyrillic)_Serbia and Montenegro',
- 'sk_SK': 'Slovak_Slovakia',
- 'sl_SI': 'Slovenian_Slovenia',
- 'es_ES': 'Spanish_Spain',
- 'sv_SE': 'Swedish_Sweden',
- 'ta_IN': 'English_Australia',
- 'th_TH': 'Thai_Thailand',
- 'mi_NZ': 'Maori',
- 'tr_TR': 'Turkish_Turkey',
- 'uk_UA': 'Ukrainian_Ukraine',
- 'vi_VN': 'Vietnamese_Viet Nam',
+ 'af_ZA': 'Afrikaans_South Africa',
+ 'sq_AL': 'Albanian_Albania',
+ 'ar_SA': 'Arabic_Saudi Arabia',
+ 'eu_ES': 'Basque_Spain',
+ 'be_BY': 'Belarusian_Belarus',
+ 'bs_BA': 'Serbian (Latin)',
+ 'bg_BG': 'Bulgarian_Bulgaria',
+ 'ca_ES': 'Catalan_Spain',
+ 'hr_HR': 'Croatian_Croatia',
+ 'zh_CN': 'Chinese_China',
+ 'zh_TW': 'Chinese_Taiwan',
+ 'cs_CZ': 'Czech_Czech Republic',
+ 'da_DK': 'Danish_Denmark',
+ 'nl_NL': 'Dutch_Netherlands',
+ 'et_EE': 'Estonian_Estonia',
+ 'fa_IR': 'Farsi_Iran',
+ 'ph_PH': 'Filipino_Philippines',
+ 'fi_FI': 'Finnish_Finland',
+ 'fr_FR': 'French_France',
+ 'fr_BE': 'French_France',
+ 'fr_CH': 'French_France',
+ 'fr_CA': 'French_France',
+ 'ga': 'Scottish Gaelic',
+ 'gl_ES': 'Galician_Spain',
+ 'ka_GE': 'Georgian_Georgia',
+ 'de_DE': 'German_Germany',
+ 'el_GR': 'Greek_Greece',
+ 'gu': 'Gujarati_India',
+ 'he_IL': 'Hebrew_Israel',
+ 'hi_IN': 'Hindi',
+ 'hu': 'Hungarian_Hungary',
+ 'is_IS': 'Icelandic_Iceland',
+ 'id_ID': 'Indonesian_indonesia',
+ 'it_IT': 'Italian_Italy',
+ 'ja_JP': 'Japanese_Japan',
+ 'kn_IN': 'Kannada',
+ 'km_KH': 'Khmer',
+ 'ko_KR': 'Korean_Korea',
+ 'lo_LA': 'Lao_Laos',
+ 'lt_LT': 'Lithuanian_Lithuania',
+ 'lat': 'Latvian_Latvia',
+ 'ml_IN': 'Malayalam_India',
+ 'id_ID': 'Indonesian_indonesia',
+ 'mi_NZ': 'Maori',
+ 'mn': 'Cyrillic_Mongolian',
+ 'no_NO': 'Norwegian_Norway',
+ 'nn_NO': 'Norwegian-Nynorsk_Norway',
+ 'pl': 'Polish_Poland',
+ 'pt_PT': 'Portuguese_Portugal',
+ 'pt_BR': 'Portuguese_Brazil',
+ 'ro_RO': 'Romanian_Romania',
+ 'ru_RU': 'Russian_Russia',
+ 'mi_NZ': 'Maori',
+ 'sr_CS': 'Serbian (Cyrillic)_Serbia and Montenegro',
+ 'sk_SK': 'Slovak_Slovakia',
+ 'sl_SI': 'Slovenian_Slovenia',
+ 'es_ES': 'Spanish_Spain',
+ 'sv_SE': 'Swedish_Sweden',
+ 'ta_IN': 'English_Australia',
+ 'th_TH': 'Thai_Thailand',
+ 'mi_NZ': 'Maori',
+ 'tr_TR': 'Turkish_Turkey',
+ 'uk_UA': 'Ukrainian_Ukraine',
+ 'vi_VN': 'Vietnamese_Viet Nam',
}
class _format(object):
- def set_value(self, name, object, field):
- #super(_date_format, self).__init__(self)
- self.object = object
- self._field = field
- self.name=name
- lc, encoding = locale.getdefaultlocale()
- if not encoding:
- encoding = 'UTF-8'
- if encoding == 'utf':
- encoding = 'UTF-8'
- if encoding == 'cp1252':
- encoding= '1252'
- lang = self.object._context.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.object._context.get('lang', 'en_US') or 'en_US'))
+ def set_value(self, name, object, field):
+ #super(_date_format, self).__init__(self)
+ self.object = object
+ self._field = field
+ self.name=name
+ lc, encoding = locale.getdefaultlocale()
+ if not encoding:
+ encoding = 'UTF-8'
+ if encoding == 'utf':
+ encoding = 'UTF-8'
+ if encoding == 'cp1252':
+ encoding= '1252'
+ lang = self.object._context.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.object._context.get('lang', 'en_US') or 'en_US'))
class _float_format(float, _format):
- def __str__(self):
- if not self.object._context:
- return self.name
- digit = 2
- if hasattr(self._field, 'digits') and self._field.digits:
- digit = self._field.digits[1]
- return locale.format('%.' + str(digit) + 'f', self.name, True)
+ def __str__(self):
+ if not self.object._context:
+ return self.name
+ digit = 2
+ if hasattr(self._field, 'digits') and self._field.digits:
+ digit = self._field.digits[1]
+ return locale.format('%.' + str(digit) + 'f', self.name, True)
class _int_format(int, _format):
- def __str__(self):
- if not self.object._context:
- return self.name
- return locale.format('%d', self.name, True)
+ def __str__(self):
+ if not self.object._context:
+ return self.name
+ return locale.format('%d', self.name, True)
class _date_format(str, _format):
- def __str__(self):
- if not self.object._context:
- return self.name
- if self.name:
- datedata = time.strptime(self.name, DT_FORMAT)
- return time.strftime(locale.nl_langinfo(locale.D_FMT).replace('%y', '%Y'),
- datedata)
- return ''
+ def __str__(self):
+ if not self.object._context:
+ return self.name
+ if self.name:
+ datedata = time.strptime(self.name, DT_FORMAT)
+ return time.strftime(locale.nl_langinfo(locale.D_FMT).replace('%y', '%Y'),
+ datedata)
+ return ''
_fields_process = {
- 'float': _float_format,
- 'date': _date_format,
- 'integer': _int_format
+ 'float': _float_format,
+ 'date': _date_format,
+ 'integer': _int_format
}
#
# Context: {'node': node.dom}
#
class browse_record_list(list):
- def __init__(self, lst, context):
- super(browse_record_list, self).__init__(lst)
- self.context = context
-
- def __getattr__(self, name):
- res = browse_record_list([getattr(x,name) for x in self], self.context)
- return res
-
- def __str__(self):
- return "browse_record_list("+str(len(self))+")"
-
- def repeatIn(self, name):
- warnings.warn('Use repeatIn(object_list, \'variable\')', DeprecationWarning)
- node = self.context['_node']
- parents = self.context.get('parents', rml_parents)
- node.data = ''
- while True:
- if not node.parentNode:
- break
- node = node.parentNode
- if node.nodeType == node.ELEMENT_NODE and node.localName in parents:
- break
- parent_node = node
- if not len(self):
- return None
- nodes = [(0,node)]
- for i in range(1,len(self)):
- newnode = parent_node.cloneNode(1)
- n = parent_node.parentNode
- n.insertBefore(newnode, parent_node)
- nodes.append((i,newnode))
- for i,node in nodes:
- self.context[name] = self[i]
- self.context['_self']._parse_node(node)
- return None
+ def __init__(self, lst, context):
+ super(browse_record_list, self).__init__(lst)
+ self.context = context
+
+ def __getattr__(self, name):
+ res = browse_record_list([getattr(x,name) for x in self], self.context)
+ return res
+
+ def __str__(self):
+ return "browse_record_list("+str(len(self))+")"
+
+ def repeatIn(self, name):
+ warnings.warn('Use repeatIn(object_list, \'variable\')', DeprecationWarning)
+ node = self.context['_node']
+ parents = self.context.get('parents', rml_parents)
+ node.data = ''
+ while True:
+ if not node.parentNode:
+ break
+ node = node.parentNode
+ if node.nodeType == node.ELEMENT_NODE and node.localName in parents:
+ break
+ parent_node = node
+ if not len(self):
+ return None
+ nodes = [(0,node)]
+ for i in range(1,len(self)):
+ newnode = parent_node.cloneNode(1)
+ n = parent_node.parentNode
+ n.insertBefore(newnode, parent_node)
+ nodes.append((i,newnode))
+ for i,node in nodes:
+ self.context[name] = self[i]
+ self.context['_self']._parse_node(node)
+ return None
class rml_parse(object):
- def __init__(self, cr, uid, name, parents=rml_parents, tag=rml_tag, context=None):
- if not context:
- context={}
- self.cr = cr
- self.uid = uid
- self.pool = pooler.get_pool(cr.dbname)
- user = self.pool.get('res.users').browse(cr, uid, uid)
- self.localcontext = {
- 'user': user,
- 'company': user.company_id,
- 'repeatIn': self.repeatIn,
- 'setLang': self.setLang,
- 'setTag': self.setTag,
- 'removeParentNode': self.removeParentNode,
- 'format': self.format,
- 'formatLang': self.formatLang,
- 'logo' : user.company_id.logo,
- }
- self.localcontext.update(context)
- self.rml_header = user.company_id.rml_header
- self.rml_header2 = user.company_id.rml_header2
- self.logo = user.company_id.logo
- self.name = name
- self._regex = re.compile('\[\[(.+?)\]\]')
- self._transl_regex = re.compile('(\[\[.+?\]\])')
- self._node = None
- self.parents = parents
- self.tag = tag
- self._lang_cache = {}
-# self.already = {}
-
- def setTag(self, oldtag, newtag, attrs=None):
- if not attrs:
- attrs={}
- node = self._find_parent(self._node, [oldtag])
- if node:
- node.tagName = newtag
- for key, val in attrs.items():
- node.setAttribute(key, val)
- return None
-
- def format(self, text, oldtag=None):
- if not oldtag:
- oldtag = self.tag
- self._node.data = ''
- node = self._find_parent(self._node, [oldtag])
-
- pp = node.parentNode
- ns = node.nextSibling
- pp.removeChild(node)
- self._node = pp
- lst = text.split('\n')
- if not len(lst):
- return None
- nodes = []
- for i in range(len(lst)):
- newnode = node.cloneNode(1)
- newnode.tagName=rml_tag
- newnode.__dict__['childNodes'][0].__dict__['data'] = lst[i].decode('utf8')
- if ns:
- pp.insertBefore(newnode, ns)
- else:
- pp.appendChild(newnode)
- nodes.append((i, newnode))
-
- def removeParentNode(self, tag=None):
- if not tag:
- tag = self.tag
- if self.tag == sxw_tag and rml2sxw.get(tag, False):
- tag = rml2sxw[tag]
- node = self._find_parent(self._node, [tag])
- if node:
- parentNode = node.parentNode
- parentNode.removeChild(node)
- self._node = parentNode
-
- def setLang(self, lang):
- self.localcontext['lang'] = lang
- for obj in self.objects:
- obj._context['lang'] = lang
- for table in obj._cache:
- for id in obj._cache[table]:
- self._lang_cache.setdefault(obj._context['lang'], {}).setdefault(table,
- {}).update(obj._cache[table][id])
- if lang in self._lang_cache \
- and table in self._lang_cache[lang] \
- and id in self._lang_cache[lang][table]:
- obj._cache[table][id] = self._lang_cache[lang][table][id]
- else:
- obj._cache[table][id] = {'id': id}
-
- 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 = ''
- node = self._find_parent(self._node, nodes_parent or self.parents)
-
- pp = node.parentNode
- ns = node.nextSibling
- pp.removeChild(node)
- self._node = pp
-
- if not len(lst):
- return None
- nodes = []
- for i in range(len(lst)):
- newnode = node.cloneNode(1)
- if ns:
- pp.insertBefore(newnode, ns)
- else:
- pp.appendChild(newnode)
- nodes.append((i, newnode))
- for i, node in nodes:
- self.node_context[node] = {name: lst[i]}
- return None
-
- def _eval(self, expr):
- try:
- res = eval(expr, self.localcontext)
- if not res:
- res = ''
- except Exception,e:
- import traceback, sys
- tb_s = reduce(lambda x, y: x+y, traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback))
- netsvc.Logger().notifyChannel('report', netsvc.LOG_ERROR,
- 'report %s:\n%s\n%s\nexpr: %s' % (self.name, tb_s, str(e),
- expr.encode('utf-8')))
- res = ''
- return res
-
- def _find_parent(self, node, parents):
- while True:
- if not node.parentNode:
- return False
- node = node.parentNode
- if node.nodeType == node.ELEMENT_NODE and node.localName in parents:
- break
- return node
-
- def _parse_text(self, text, level=None):
- if not level:
- level=[]
- res = self._regex.findall(text)
- todo = []
- # translate the text
- # the "split [[]] if not match [[]]" is not very nice, but I
- # don't see how I could do it better...
- # what I'd like to do is a re.sub(NOT pattern, func, string)
- # but I don't know how to do that...
- # translate the RML file
- if 'lang' in self.localcontext:
- lang = self.localcontext['lang']
- if lang and text and not text.isspace():
- transl_obj = self.pool.get('ir.translation')
- piece_list = self._transl_regex.split(text)
- for pn in range(len(piece_list)):
- if not self._transl_regex.match(piece_list[pn]):
- source_string = piece_list[pn].replace('\n', ' ').strip()
- if len(source_string):
- translated_string = transl_obj._get_source(self.cr, self.uid, self.name, 'rml', lang, source_string)
- if translated_string:
- piece_list[pn] = piece_list[pn].replace(source_string, translated_string.decode('utf8'))
- text = ''.join(piece_list)
- for key in res:
- newtext = self._eval(key)
- for i in range(len(level)):
- if isinstance(newtext, list):
- newtext = newtext[level[i]]
- if isinstance(newtext, list):
- todo.append((key, newtext))
- else:
- #if not isinstance(newtext, basestring):
- newtext = str(newtext)
- # if there are two [[]] blocks the same, it will replace both
- # but it's ok because it should evaluate to the same thing
- # anyway
- text = text.replace('[['+key+']]', newtext.decode('utf8'))
- self._node.data = text
- if len(todo):
- for key, newtext in todo:
- parent_node = self._find_parent(self._node, parents)
- assert parents.get(parent_node.localName, False), 'No parent node found !'
- nodes = [parent_node]
- for i in range(len(newtext) - 1):
- newnode = parent_node.cloneNode(1)
- if parents.get(parent_node.localName, False):
- n = parent_node.parentNode
- parent_node.parentNode.insertAfter(newnode, parent_node)
- nodes.append(newnode)
- return False
- return text
-
- def _parse_node(self):
- level = []
- while True:
- if self._node.nodeType==self._node.ELEMENT_NODE:
- if self._node.hasAttribute('expr'):
- newattrs = self._eval(self._node.getAttribute('expr'))
- for key,val in newattrs.items():
- self._node.setAttribute(key,val)
-
- if self._node.hasChildNodes():
- self._node = self._node.firstChild
- elif self._node.nextSibling:
- self._node = self._node.nextSibling
- else:
- while self._node and not self._node.nextSibling:
- self._node = self._node.parentNode
- if not self._node:
- break
- self._node = self._node.nextSibling
- if self._node in self.node_context:
- self.localcontext.update(self.node_context[self._node])
- if self._node.nodeType in (self._node.CDATA_SECTION_NODE, self._node.TEXT_NODE):
-# if self._node in self.already:
-# self.already[self._node] += 1
-# print "second pass!", self.already[self._node], '---%s---' % self._node.data
-# else:
-# self.already[self._node] = 0
- self._parse_text(self._node.data, level)
- return True
-
- def _find_node(self, node, localname):
- if node.localName==localname:
- return node
- for tag in node.childNodes:
- if tag.nodeType==tag.ELEMENT_NODE:
- found = self._find_node(tag, localname)
- if found:
- return found
- return False
-
- def _add_header(self, node, header=1):
- if header==2:
- rml_head = self.rml_header2
- else:
- rml_head = self.rml_header
-
- # Refactor this patch, to use the minidom interface
- if self.logo and (rml_head.find('company.logo')<0 or rml_head.find('<image')<0) and rml_head.find('<!--image')<0:
- rml_head = rml_head.replace('<pageGraphics>','''<pageGraphics> <image x="10" y="26cm" height="70" width="90" >[[company.logo]] </image> ''')
- if not self.logo and rml_head.find('company.logo')>=0:
- rml_head = rml_head.replace('<image','<!--image')
- rml_head = rml_head.replace('</image>','</image-->')
-
- head_dom = xml.dom.minidom.parseString(rml_head)
- #for frame in head_dom.getElementsByTagName('frame'):
- # frame.parentNode.removeChild(frame)
- node2 = head_dom.documentElement
- for tag in node2.childNodes:
- if tag.nodeType==tag.ELEMENT_NODE:
- found = self._find_node(node, tag.localName)
- # rml_frames = found.getElementsByTagName('frame')
- if found:
- if tag.hasAttribute('position') and (tag.getAttribute('position')=='inside'):
- found.appendChild(tag)
- else:
- found.parentNode.replaceChild(tag, found)
- # for frame in rml_frames:
- # tag.appendChild(frame)
- return True
-
- def preprocess(self, objects, data, ids):
- self.localcontext['data'] = data
- self.localcontext['objects'] = objects
- self.datas = data
- self.ids = ids
- self.objects = objects
-
- def _parse(self, rml_dom, objects, data, header=0):
- self.node_context = {}
- self.dom = rml_dom
- self._node = self.dom.documentElement
- if header:
- self._add_header(self._node, header)
- self._parse_node()
- res = self.dom.documentElement.toxml('utf-8')
- return res
+ def __init__(self, cr, uid, name, parents=rml_parents, tag=rml_tag, context=None):
+ if not context:
+ context={}
+ self.cr = cr
+ self.uid = uid
+ self.pool = pooler.get_pool(cr.dbname)
+ user = self.pool.get('res.users').browse(cr, uid, uid)
+ self.localcontext = {
+ 'user': user,
+ 'company': user.company_id,
+ 'repeatIn': self.repeatIn,
+ 'setLang': self.setLang,
+ 'setTag': self.setTag,
+ 'removeParentNode': self.removeParentNode,
+ 'format': self.format,
+ 'formatLang': self.formatLang,
+ 'logo' : user.company_id.logo,
+ }
+ self.localcontext.update(context)
+ self.rml_header = user.company_id.rml_header
+ self.rml_header2 = user.company_id.rml_header2
+ self.logo = user.company_id.logo
+ self.name = name
+ self._regex = re.compile('\[\[(.+?)\]\]')
+ self._transl_regex = re.compile('(\[\[.+?\]\])')
+ self._node = None
+ self.parents = parents
+ self.tag = tag
+ self._lang_cache = {}
+# self.already = {}
+
+ def setTag(self, oldtag, newtag, attrs=None):
+ if not attrs:
+ attrs={}
+ node = self._find_parent(self._node, [oldtag])
+ if node:
+ node.tagName = newtag
+ for key, val in attrs.items():
+ node.setAttribute(key, val)
+ return None
+
+ def format(self, text, oldtag=None):
+ if not oldtag:
+ oldtag = self.tag
+ self._node.data = ''
+ node = self._find_parent(self._node, [oldtag])
+
+ pp = node.parentNode
+ ns = node.nextSibling
+ pp.removeChild(node)
+ self._node = pp
+ lst = text.split('\n')
+ if not len(lst):
+ return None
+ nodes = []
+ for i in range(len(lst)):
+ newnode = node.cloneNode(1)
+ newnode.tagName=rml_tag
+ newnode.__dict__['childNodes'][0].__dict__['data'] = lst[i].decode('utf8')
+ if ns:
+ pp.insertBefore(newnode, ns)
+ else:
+ pp.appendChild(newnode)
+ nodes.append((i, newnode))
+
+ def removeParentNode(self, tag=None):
+ if not tag:
+ tag = self.tag
+ if self.tag == sxw_tag and rml2sxw.get(tag, False):
+ tag = rml2sxw[tag]
+ node = self._find_parent(self._node, [tag])
+ if node:
+ parentNode = node.parentNode
+ parentNode.removeChild(node)
+ self._node = parentNode
+
+ def setLang(self, lang):
+ self.localcontext['lang'] = lang
+ for obj in self.objects:
+ obj._context['lang'] = lang
+ for table in obj._cache:
+ for id in obj._cache[table]:
+ self._lang_cache.setdefault(obj._context['lang'], {}).setdefault(table,
+ {}).update(obj._cache[table][id])
+ if lang in self._lang_cache \
+ and table in self._lang_cache[lang] \
+ and id in self._lang_cache[lang][table]:
+ obj._cache[table][id] = self._lang_cache[lang][table][id]
+ else:
+ obj._cache[table][id] = {'id': id}
+
+ 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 = ''
+ node = self._find_parent(self._node, nodes_parent or self.parents)
+
+ pp = node.parentNode
+ ns = node.nextSibling
+ pp.removeChild(node)
+ self._node = pp
+
+ if not len(lst):
+ return None
+ nodes = []
+ for i in range(len(lst)):
+ newnode = node.cloneNode(1)
+ if ns:
+ pp.insertBefore(newnode, ns)
+ else:
+ pp.appendChild(newnode)
+ nodes.append((i, newnode))
+ for i, node in nodes:
+ self.node_context[node] = {name: lst[i]}
+ return None
+
+ def _eval(self, expr):
+ try:
+ res = eval(expr, self.localcontext)
+ if not res:
+ res = ''
+ except Exception,e:
+ import traceback, sys
+ tb_s = reduce(lambda x, y: x+y, traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback))
+ netsvc.Logger().notifyChannel('report', netsvc.LOG_ERROR,
+ 'report %s:\n%s\n%s\nexpr: %s' % (self.name, tb_s, str(e),
+ expr.encode('utf-8')))
+ res = ''
+ return res
+
+ def _find_parent(self, node, parents):
+ while True:
+ if not node.parentNode:
+ return False
+ node = node.parentNode
+ if node.nodeType == node.ELEMENT_NODE and node.localName in parents:
+ break
+ return node
+
+ def _parse_text(self, text, level=None):
+ if not level:
+ level=[]
+ res = self._regex.findall(text)
+ todo = []
+ # translate the text
+ # the "split [[]] if not match [[]]" is not very nice, but I
+ # don't see how I could do it better...
+ # what I'd like to do is a re.sub(NOT pattern, func, string)
+ # but I don't know how to do that...
+ # translate the RML file
+ if 'lang' in self.localcontext:
+ lang = self.localcontext['lang']
+ if lang and text and not text.isspace():
+ transl_obj = self.pool.get('ir.translation')
+ piece_list = self._transl_regex.split(text)
+ for pn in range(len(piece_list)):
+ if not self._transl_regex.match(piece_list[pn]):
+ source_string = piece_list[pn].replace('\n', ' ').strip()
+ if len(source_string):
+ translated_string = transl_obj._get_source(self.cr, self.uid, self.name, 'rml', lang, source_string)
+ if translated_string:
+ piece_list[pn] = piece_list[pn].replace(source_string, translated_string.decode('utf8'))
+ text = ''.join(piece_list)
+ for key in res:
+ newtext = self._eval(key)
+ for i in range(len(level)):
+ if isinstance(newtext, list):
+ newtext = newtext[level[i]]
+ if isinstance(newtext, list):
+ todo.append((key, newtext))
+ else:
+ #if not isinstance(newtext, basestring):
+ newtext = str(newtext)
+ # if there are two [[]] blocks the same, it will replace both
+ # but it's ok because it should evaluate to the same thing
+ # anyway
+ text = text.replace('[['+key+']]', newtext.decode('utf8'))
+ self._node.data = text
+ if len(todo):
+ for key, newtext in todo:
+ parent_node = self._find_parent(self._node, parents)
+ assert parents.get(parent_node.localName, False), 'No parent node found !'
+ nodes = [parent_node]
+ for i in range(len(newtext) - 1):
+ newnode = parent_node.cloneNode(1)
+ if parents.get(parent_node.localName, False):
+ n = parent_node.parentNode
+ parent_node.parentNode.insertAfter(newnode, parent_node)
+ nodes.append(newnode)
+ return False
+ return text
+
+ def _parse_node(self):
+ level = []
+ while True:
+ if self._node.nodeType==self._node.ELEMENT_NODE:
+ if self._node.hasAttribute('expr'):
+ newattrs = self._eval(self._node.getAttribute('expr'))
+ for key,val in newattrs.items():
+ self._node.setAttribute(key,val)
+
+ if self._node.hasChildNodes():
+ self._node = self._node.firstChild
+ elif self._node.nextSibling:
+ self._node = self._node.nextSibling
+ else:
+ while self._node and not self._node.nextSibling:
+ self._node = self._node.parentNode
+ if not self._node:
+ break
+ self._node = self._node.nextSibling
+ if self._node in self.node_context:
+ self.localcontext.update(self.node_context[self._node])
+ if self._node.nodeType in (self._node.CDATA_SECTION_NODE, self._node.TEXT_NODE):
+# if self._node in self.already:
+# self.already[self._node] += 1
+# print "second pass!", self.already[self._node], '---%s---' % self._node.data
+# else:
+# self.already[self._node] = 0
+ self._parse_text(self._node.data, level)
+ return True
+
+ def _find_node(self, node, localname):
+ if node.localName==localname:
+ return node
+ for tag in node.childNodes:
+ if tag.nodeType==tag.ELEMENT_NODE:
+ found = self._find_node(tag, localname)
+ if found:
+ return found
+ return False
+
+ def _add_header(self, node, header=1):
+ if header==2:
+ rml_head = self.rml_header2
+ else:
+ rml_head = self.rml_header
+
+ # Refactor this patch, to use the minidom interface
+ if self.logo and (rml_head.find('company.logo')<0 or rml_head.find('<image')<0) and rml_head.find('<!--image')<0:
+ rml_head = rml_head.replace('<pageGraphics>','''<pageGraphics> <image x="10" y="26cm" height="70" width="90" >[[company.logo]] </image> ''')
+ if not self.logo and rml_head.find('company.logo')>=0:
+ rml_head = rml_head.replace('<image','<!--image')
+ rml_head = rml_head.replace('</image>','</image-->')
+
+ head_dom = xml.dom.minidom.parseString(rml_head)
+ #for frame in head_dom.getElementsByTagName('frame'):
+ # frame.parentNode.removeChild(frame)
+ node2 = head_dom.documentElement
+ for tag in node2.childNodes:
+ if tag.nodeType==tag.ELEMENT_NODE:
+ found = self._find_node(node, tag.localName)
+ # rml_frames = found.getElementsByTagName('frame')
+ if found:
+ if tag.hasAttribute('position') and (tag.getAttribute('position')=='inside'):
+ found.appendChild(tag)
+ else:
+ found.parentNode.replaceChild(tag, found)
+ # for frame in rml_frames:
+ # tag.appendChild(frame)
+ return True
+
+ def preprocess(self, objects, data, ids):
+ self.localcontext['data'] = data
+ self.localcontext['objects'] = objects
+ self.datas = data
+ self.ids = ids
+ self.objects = objects
+
+ def _parse(self, rml_dom, objects, data, header=0):
+ self.node_context = {}
+ self.dom = rml_dom
+ self._node = self.dom.documentElement
+ if header:
+ self._add_header(self._node, header)
+ self._parse_node()
+ res = self.dom.documentElement.toxml('utf-8')
+ return res
class report_sxw(report_rml):
- def __init__(self, name, table, rml, parser=rml_parse, header=True):
- report_rml.__init__(self, name, table, rml, '')
- self.name = name
- self.parser = parser
- self.header = header
-
- 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)
-
- def create(self, cr, uid, ids, data, context=None):
- logo = None
- if not context:
- context={}
- context = context.copy()
- pool = pooler.get_pool(cr.dbname)
- ir_actions_report_xml_obj = pool.get('ir.actions.report.xml')
- report_xml_ids = ir_actions_report_xml_obj.search(cr, uid,
- [('report_name', '=', self.name[7:])], context=context)
- report_type = 'pdf'
- report_xml = None
- if report_xml_ids:
- report_xml = ir_actions_report_xml_obj.browse(cr, uid, report_xml_ids[0],
- context=context)
- rml = report_xml.report_rml_content
- report_type = report_xml.report_type
- else:
- rml = tools.file_open(self.tmpl, subdir=None).read()
- report_type= data.get('report_type', report_type)
-
- if report_type == 'sxw' and report_xml:
- context['parents'] = sxw_parents
- sxw_io = StringIO.StringIO(report_xml.report_sxw_content)
- sxw_z = zipfile.ZipFile(sxw_io, mode='r')
- rml = sxw_z.read('content.xml')
- meta = sxw_z.read('meta.xml')
- sxw_z.close()
- rml_parser = self.parser(cr, uid, self.name2, context)
- rml_parser.parents = sxw_parents
- rml_parser.tag = sxw_tag
- objs = self.getObjects(cr, uid, ids, context)
- rml_parser.preprocess(objs, data, ids)
- rml_dom = xml.dom.minidom.parseString(rml)
-
- node = rml_dom.documentElement
-
- elements = node.getElementsByTagName("text:p")
-
- for pe in elements:
- e = pe.getElementsByTagName("text:drop-down")
- for de in e:
- pp=de.parentNode
- for cnd in de.childNodes:
- if cnd.nodeType in (cnd.CDATA_SECTION_NODE, cnd.TEXT_NODE):
- pe.appendChild(cnd)
- pp.removeChild(de)
-
-
-
- # Add Information : Resource ID and Model
- rml_dom_meta = xml.dom.minidom.parseString(meta)
- node = rml_dom_meta.documentElement
- elements = node.getElementsByTagName("meta:user-defined")
- for pe in elements:
- if pe.hasAttribute("meta:name"):
- if pe.getAttribute("meta:name") == "Info 3":
- pe.childNodes[0].data=data['id']
- if pe.getAttribute("meta:name") == "Info 4":
- pe.childNodes[0].data=data['model']
- meta = rml_dom_meta.documentElement.toxml('utf-8')
-
- rml2 = rml_parser._parse(rml_dom, objs, data, header=self.header)
- sxw_z = zipfile.ZipFile(sxw_io, mode='a')
- sxw_z.writestr('content.xml', "<?xml version='1.0' encoding='UTF-8'?>" + \
- rml2)
- sxw_z.writestr('meta.xml', "<?xml version='1.0' encoding='UTF-8'?>" + \
- meta)
-
- if self.header:
- #Add corporate header/footer
- rml = tools.file_open('custom/corporate_sxw_header.xml').read()
- rml_parser = self.parser(cr, uid, self.name2, context)
- rml_parser.parents = sxw_parents
- rml_parser.tag = sxw_tag
- objs = self.getObjects(cr, uid, ids, context)
- rml_parser.preprocess(objs, data, ids)
- rml_dom = xml.dom.minidom.parseString(rml)
- rml2 = rml_parser._parse(rml_dom, objs, data, header=self.header)
- sxw_z.writestr('styles.xml',"<?xml version='1.0' encoding='UTF-8'?>" + \
- rml2)
- sxw_z.close()
- rml2 = sxw_io.getvalue()
- sxw_io.close()
- else:
- context['parents'] = rml_parents
- rml_parser = self.parser(cr, uid, self.name2, context)
- rml_parser.parents = rml_parents
- rml_parser.tag = rml_tag
- objs = self.getObjects(cr, uid, ids, context)
- rml_parser.preprocess(objs, data, ids)
- rml_dom = xml.dom.minidom.parseString(rml)
- rml2 = rml_parser._parse(rml_dom, objs, data, header=self.header)
- #if os.name != "nt":
- # f = file("/tmp/debug.rml", "w")
- # f.write(rml2)
- # f.close()
- if rml_parser.logo:
- logo = base64.decodestring(rml_parser.logo)
-
- create_doc = self.generators[report_type]
- pdf = create_doc(rml2, logo)
- return (pdf, report_type)
+ def __init__(self, name, table, rml, parser=rml_parse, header=True):
+ report_rml.__init__(self, name, table, rml, '')
+ self.name = name
+ self.parser = parser
+ self.header = header
+
+ 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)
+
+ def create(self, cr, uid, ids, data, context=None):
+ logo = None
+ if not context:
+ context={}
+ context = context.copy()
+ pool = pooler.get_pool(cr.dbname)
+ ir_actions_report_xml_obj = pool.get('ir.actions.report.xml')
+ report_xml_ids = ir_actions_report_xml_obj.search(cr, uid,
+ [('report_name', '=', self.name[7:])], context=context)
+ report_type = 'pdf'
+ report_xml = None
+ if report_xml_ids:
+ report_xml = ir_actions_report_xml_obj.browse(cr, uid, report_xml_ids[0],
+ context=context)
+ rml = report_xml.report_rml_content
+ report_type = report_xml.report_type
+ else:
+ rml = tools.file_open(self.tmpl, subdir=None).read()
+ report_type= data.get('report_type', report_type)
+
+ if report_type == 'sxw' and report_xml:
+ context['parents'] = sxw_parents
+ sxw_io = StringIO.StringIO(report_xml.report_sxw_content)
+ sxw_z = zipfile.ZipFile(sxw_io, mode='r')
+ rml = sxw_z.read('content.xml')
+ meta = sxw_z.read('meta.xml')
+ sxw_z.close()
+ rml_parser = self.parser(cr, uid, self.name2, context)
+ rml_parser.parents = sxw_parents
+ rml_parser.tag = sxw_tag
+ objs = self.getObjects(cr, uid, ids, context)
+ rml_parser.preprocess(objs, data, ids)
+ rml_dom = xml.dom.minidom.parseString(rml)
+
+ node = rml_dom.documentElement
+
+ elements = node.getElementsByTagName("text:p")
+
+ for pe in elements:
+ e = pe.getElementsByTagName("text:drop-down")
+ for de in e:
+ pp=de.parentNode
+ for cnd in de.childNodes:
+ if cnd.nodeType in (cnd.CDATA_SECTION_NODE, cnd.TEXT_NODE):
+ pe.appendChild(cnd)
+ pp.removeChild(de)
+
+
+
+ # Add Information : Resource ID and Model
+ rml_dom_meta = xml.dom.minidom.parseString(meta)
+ node = rml_dom_meta.documentElement
+ elements = node.getElementsByTagName("meta:user-defined")
+ for pe in elements:
+ if pe.hasAttribute("meta:name"):
+ if pe.getAttribute("meta:name") == "Info 3":
+ pe.childNodes[0].data=data['id']
+ if pe.getAttribute("meta:name") == "Info 4":
+ pe.childNodes[0].data=data['model']
+ meta = rml_dom_meta.documentElement.toxml('utf-8')
+
+ rml2 = rml_parser._parse(rml_dom, objs, data, header=self.header)
+ sxw_z = zipfile.ZipFile(sxw_io, mode='a')
+ sxw_z.writestr('content.xml', "<?xml version='1.0' encoding='UTF-8'?>" + \
+ rml2)
+ sxw_z.writestr('meta.xml', "<?xml version='1.0' encoding='UTF-8'?>" + \
+ meta)
+
+ if self.header:
+ #Add corporate header/footer
+ rml = tools.file_open('custom/corporate_sxw_header.xml').read()
+ rml_parser = self.parser(cr, uid, self.name2, context)
+ rml_parser.parents = sxw_parents
+ rml_parser.tag = sxw_tag
+ objs = self.getObjects(cr, uid, ids, context)
+ rml_parser.preprocess(objs, data, ids)
+ rml_dom = xml.dom.minidom.parseString(rml)
+ rml2 = rml_parser._parse(rml_dom, objs, data, header=self.header)
+ sxw_z.writestr('styles.xml',"<?xml version='1.0' encoding='UTF-8'?>" + \
+ rml2)
+ sxw_z.close()
+ rml2 = sxw_io.getvalue()
+ sxw_io.close()
+ else:
+ context['parents'] = rml_parents
+ rml_parser = self.parser(cr, uid, self.name2, context)
+ rml_parser.parents = rml_parents
+ rml_parser.tag = rml_tag
+ objs = self.getObjects(cr, uid, ids, context)
+ rml_parser.preprocess(objs, data, ids)
+ rml_dom = xml.dom.minidom.parseString(rml)
+ rml2 = rml_parser._parse(rml_dom, objs, data, header=self.header)
+ #if os.name != "nt":
+ # f = file("/tmp/debug.rml", "w")
+ # f.write(rml2)
+ # f.close()
+ if rml_parser.logo:
+ logo = base64.decodestring(rml_parser.logo)
+
+ create_doc = self.generators[report_type]
+ pdf = create_doc(rml2, logo)
+ return (pdf, report_type)
diff --git a/bin/service/security.py b/bin/service/security.py
index a1a26ebed28..629f27b050d 100644
--- a/bin/service/security.py
+++ b/bin/service/security.py
@@ -32,44 +32,44 @@ import tools
_uid_cache = {}
def login(db, login, password):
- cr = pooler.get_db(db).cursor()
- cr.execute('select id from res_users where login=%s and password=%s and active', (login.encode('utf-8'), password.encode('utf-8')))
- res = cr.fetchone()
- cr.close()
- if res:
- return res[0]
- else:
- return False
+ cr = pooler.get_db(db).cursor()
+ cr.execute('select id from res_users where login=%s and password=%s and active', (login.encode('utf-8'), password.encode('utf-8')))
+ 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
- else:
- raise Exception('AccessDenied')
-
+ if passwd == tools.config['admin_passwd']:
+ return True
+ else:
+ raise Exception('AccessDenied')
+
def check(db, uid, passwd):
- if _uid_cache.get(db, {}).get(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))
- res = cr.fetchone()[0]
- cr.close()
- if not bool(res):
- raise Exception('AccessDenied')
- if res:
- if _uid_cache.has_key(db):
- ulist = _uid_cache[db]
- ulist[uid] = passwd
- else:
- _uid_cache[db] = {uid:passwd}
- return bool(res)
+ if _uid_cache.get(db, {}).get(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))
+ res = cr.fetchone()[0]
+ cr.close()
+ if not bool(res):
+ raise Exception('AccessDenied')
+ if res:
+ if _uid_cache.has_key(db):
+ ulist = _uid_cache[db]
+ ulist[uid] = passwd
+ else:
+ _uid_cache[db] = {uid:passwd}
+ return bool(res)
def access(db, uid, passwd, sec_level, ids):
- cr = pooler.get_db(db).cursor()
- cr.execute('select id from res_users where id=%s and password=%s', (uid, passwd))
- res = cr.fetchone()
- cr.close()
- if not res:
- raise Exception('Bad username or password')
- return res[0]
+ cr = pooler.get_db(db).cursor()
+ cr.execute('select id from res_users where id=%s and password=%s', (uid, passwd))
+ res = cr.fetchone()
+ cr.close()
+ if not res:
+ raise Exception('Bad username or password')
+ return res[0]
diff --git a/bin/service/web_services.py b/bin/service/web_services.py
index 896757f2be4..7d431a76a6d 100644
--- a/bin/service/web_services.py
+++ b/bin/service/web_services.py
@@ -45,292 +45,292 @@ from tools.translate import _
logging.basicConfig()
class db(netsvc.Service):
- def __init__(self, name="db"):
- netsvc.Service.__init__(self, name)
- self.joinGroup("web-services")
- self.exportMethod(self.create)
- self.exportMethod(self.get_progress)
- self.exportMethod(self.drop)
- self.exportMethod(self.dump)
- self.exportMethod(self.restore)
- self.exportMethod(self.list)
- self.exportMethod(self.list_lang)
- self.exportMethod(self.change_admin_password)
- self.actions = {}
- self.id = 0
- self.id_protect = threading.Semaphore()
-
- def create(self, password, db_name, demo, lang):
- security.check_super(password)
- self.id_protect.acquire()
- self.id += 1
- id = self.id
- self.id_protect.release()
-
- self.actions[id] = {'clean': False}
-
- db = sql_db.db_connect('template1', serialize=1)
- db.truedb.autocommit()
- cr = db.cursor()
- cr.execute('CREATE DATABASE ' + db_name + ' ENCODING \'unicode\'')
- cr.close()
- class DBInitialize(object):
- def __call__(self, serv, id, db_name, demo, lang):
- try:
- serv.actions[id]['progress'] = 0
- clean = False
- cr = sql_db.db_connect(db_name).cursor()
- tools.init_db(cr)
- cr.commit()
- cr.close()
- cr = None
- pool = pooler.get_pool(db_name, demo,serv.actions[id],
- update_module=True)
- if lang and lang != 'en_US':
- filename = tools.config["root_path"] + "/i18n/" + lang + ".csv"
- tools.trans_load(db_name, filename, lang)
- serv.actions[id]['clean'] = True
- cr = sql_db.db_connect(db_name).cursor()
- cr.execute('select login, password, name ' \
- 'from res_users ' \
- 'where login <> \'root\' order by login')
- serv.actions[id]['users'] = cr.dictfetchall()
- cr.close()
- except Exception, e:
- serv.actions[id]['clean'] = False
- serv.actions[id]['exception'] = e
- from StringIO import StringIO
- import traceback
- e_str = StringIO()
- traceback.print_exc(file=e_str)
- traceback_str = e_str.getvalue()
- e_str.close()
- print 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))
- dbi = DBInitialize()
- create_thread = threading.Thread(target=dbi,
- args=(self, id, db_name, demo, lang))
- create_thread.start()
- self.actions[id]['thread'] = create_thread
- return id
-
- def get_progress(self, password, id):
- security.check_super(password)
- if self.actions[id]['thread'].isAlive():
-# return addons.init_progress[db_name]
- return (min(self.actions[id].get('progress', 0),0.95), [])
- else:
- clean = self.actions[id]['clean']
- if clean:
- users = self.actions[id]['users']
- del self.actions[id]
- return (1.0, users)
- else:
- e = self.actions[id]['exception']
- del self.actions[id]
- raise Exception, e
-
- def drop(self, password, db_name):
- security.check_super(password)
- pooler.close_db(db_name)
- logger = netsvc.Logger()
-
- db = sql_db.db_connect('template1', serialize=1)
- db.truedb.autocommit()
- cr = db.cursor()
- try:
- try:
- cr.execute('DROP DATABASE ' + db_name)
- except:
- logger.notifyChannel("web-service", netsvc.LOG_ERROR,
- 'DROP DB: %s failed' % (db_name,))
- raise
- else:
- logger.notifyChannel("web-services", netsvc.LOG_INFO,
- 'DROP DB: %s' % (db_name))
- finally:
- cr.close()
- return True
-
- def dump(self, password, db_name):
- security.check_super(password)
- logger = netsvc.Logger()
-
- if tools.config['db_password']:
- logger.notifyChannel("web-service", netsvc.LOG_ERROR,
- 'DUMP DB: %s doesn\'t work with password' % (db_name,))
- raise Exception, "Couldn't dump database with password"
-
- cmd = ['pg_dump', '--format=c']
- if tools.config['db_user']:
- cmd.append('--username=' + tools.config['db_user'])
- if tools.config['db_host']:
- cmd.append('--host=' + tools.config['db_host'])
- if tools.config['db_port']:
- cmd.append('--port=' + tools.config['db_port'])
- cmd.append(db_name)
-
- stdin, stdout = tools.exec_pg_command_pipe(*tuple(cmd))
- stdin.close()
- data = stdout.read()
- res = stdout.close()
- if res:
- logger.notifyChannel("web-service", netsvc.LOG_ERROR,
- 'DUMP DB: %s failed\n%s' % (db_name, data))
- raise Exception, "Couldn't dump database"
- logger.notifyChannel("web-services", netsvc.LOG_INFO,
- 'DUMP DB: %s' % (db_name))
- return base64.encodestring(data)
-
- def restore(self, password, db_name, data):
- security.check_super(password)
- logger = netsvc.Logger()
-
- if self.db_exist(db_name):
- logger.notifyChannel("web-service", netsvc.LOG_WARNING,
- 'RESTORE DB: %s already exists' % (db_name,))
- raise Exception, "Database already exists"
-
- if tools.config['db_password']:
- logger.notifyChannel("web-service", netsvc.LOG_ERROR,
- 'RESTORE DB: %s doesn\'t work with password' % (db_name,))
- raise Exception, "Couldn't restore database with password"
-
- db = sql_db.db_connect('template1', serialize=1)
- db.truedb.autocommit()
- cr = db.cursor()
- cr.execute('CREATE DATABASE ' + db_name + ' ENCODING \'unicode\'')
- cr.close()
-
- cmd = ['pg_restore']
- if tools.config['db_user']:
- cmd.append('--username=' + tools.config['db_user'])
- if tools.config['db_host']:
- cmd.append('--host=' + tools.config['db_host'])
- if tools.config['db_port']:
- cmd.append('--port=' + tools.config['db_port'])
- cmd.append('--dbname=' + db_name)
- args2 = tuple(cmd)
-
- buf=base64.decodestring(data)
- if os.name == "nt":
- tmpfile = (os.environ['TMP'] or 'C:\\') + os.tmpnam()
- file(tmpfile, 'wb').write(buf)
- args2=list(args2)
- args2.append(' ' + tmpfile)
- args2=tuple(args2)
- stdin, stdout = tools.exec_pg_command_pipe(*args2)
- if not os.name == "nt":
- stdin.write(base64.decodestring(data))
- stdin.close()
- res = stdout.close()
- if res:
- raise Exception, "Couldn't restore database"
- logger.notifyChannel("web-services", netsvc.LOG_INFO,
- 'RESTORE DB: %s' % (db_name))
- return True
-
- def db_exist(self, db_name):
- try:
- db = sql_db.db_connect(db_name)
- db.truedb.close()
- return True
- except:
- return False
-
- def list(self):
- db = sql_db.db_connect('template1')
- try:
- cr = db.cursor()
- db_user = tools.config["db_user"]
- if not db_user and os.name == 'posix':
- import pwd
- db_user = pwd.getpwuid(os.getuid())[0]
- if not db_user:
- cr.execute("select usename from pg_user where usesysid=(select datdba from pg_database where datname=%s)", (tools.config["db_name"],))
- res = cr.fetchone()
- db_user = res and res[0]
- if db_user:
- cr.execute("select datname from pg_database where datdba=(select usesysid from pg_user where usename=%s) and datname not in ('template0', 'template1', 'postgres')", (db_user,))
- else:
- cr.execute("select datname from pg_database where datname not in('template0', 'template1','postgres')")
- res = [name for (name,) in cr.fetchall()]
- cr.close()
- except:
- res = []
- db.truedb.close()
- return res
-
- def change_admin_password(self, old_password, new_password):
- security.check_super(old_password)
- tools.config['admin_passwd'] = new_password
- tools.config.save()
- return True
-
- def list_lang(self):
- return tools.scan_languages()
- import glob
- file_list = glob.glob(os.path.join(tools.config['root_path'], 'i18n', '*.csv'))
- def lang_tuple(fname):
- lang_dict=tools.get_languages()
- lang = os.path.basename(fname).split(".")[0]
- return (lang, lang_dict.get(lang, lang))
- return [lang_tuple(fname) for fname in file_list]
+ def __init__(self, name="db"):
+ netsvc.Service.__init__(self, name)
+ self.joinGroup("web-services")
+ self.exportMethod(self.create)
+ self.exportMethod(self.get_progress)
+ self.exportMethod(self.drop)
+ self.exportMethod(self.dump)
+ self.exportMethod(self.restore)
+ self.exportMethod(self.list)
+ self.exportMethod(self.list_lang)
+ self.exportMethod(self.change_admin_password)
+ self.actions = {}
+ self.id = 0
+ self.id_protect = threading.Semaphore()
+
+ def create(self, password, db_name, demo, lang):
+ security.check_super(password)
+ self.id_protect.acquire()
+ self.id += 1
+ id = self.id
+ self.id_protect.release()
+
+ self.actions[id] = {'clean': False}
+
+ db = sql_db.db_connect('template1', serialize=1)
+ db.truedb.autocommit()
+ cr = db.cursor()
+ cr.execute('CREATE DATABASE ' + db_name + ' ENCODING \'unicode\'')
+ cr.close()
+ class DBInitialize(object):
+ def __call__(self, serv, id, db_name, demo, lang):
+ try:
+ serv.actions[id]['progress'] = 0
+ clean = False
+ cr = sql_db.db_connect(db_name).cursor()
+ tools.init_db(cr)
+ cr.commit()
+ cr.close()
+ cr = None
+ pool = pooler.get_pool(db_name, demo,serv.actions[id],
+ update_module=True)
+ if lang and lang != 'en_US':
+ filename = tools.config["root_path"] + "/i18n/" + lang + ".csv"
+ tools.trans_load(db_name, filename, lang)
+ serv.actions[id]['clean'] = True
+ cr = sql_db.db_connect(db_name).cursor()
+ cr.execute('select login, password, name ' \
+ 'from res_users ' \
+ 'where login <> \'root\' order by login')
+ serv.actions[id]['users'] = cr.dictfetchall()
+ cr.close()
+ except Exception, e:
+ serv.actions[id]['clean'] = False
+ serv.actions[id]['exception'] = e
+ from StringIO import StringIO
+ import traceback
+ e_str = StringIO()
+ traceback.print_exc(file=e_str)
+ traceback_str = e_str.getvalue()
+ e_str.close()
+ print 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))
+ dbi = DBInitialize()
+ create_thread = threading.Thread(target=dbi,
+ args=(self, id, db_name, demo, lang))
+ create_thread.start()
+ self.actions[id]['thread'] = create_thread
+ return id
+
+ def get_progress(self, password, id):
+ security.check_super(password)
+ if self.actions[id]['thread'].isAlive():
+# return addons.init_progress[db_name]
+ return (min(self.actions[id].get('progress', 0),0.95), [])
+ else:
+ clean = self.actions[id]['clean']
+ if clean:
+ users = self.actions[id]['users']
+ del self.actions[id]
+ return (1.0, users)
+ else:
+ e = self.actions[id]['exception']
+ del self.actions[id]
+ raise Exception, e
+
+ def drop(self, password, db_name):
+ security.check_super(password)
+ pooler.close_db(db_name)
+ logger = netsvc.Logger()
+
+ db = sql_db.db_connect('template1', serialize=1)
+ db.truedb.autocommit()
+ cr = db.cursor()
+ try:
+ try:
+ cr.execute('DROP DATABASE ' + db_name)
+ except:
+ logger.notifyChannel("web-service", netsvc.LOG_ERROR,
+ 'DROP DB: %s failed' % (db_name,))
+ raise
+ else:
+ logger.notifyChannel("web-services", netsvc.LOG_INFO,
+ 'DROP DB: %s' % (db_name))
+ finally:
+ cr.close()
+ return True
+
+ def dump(self, password, db_name):
+ security.check_super(password)
+ logger = netsvc.Logger()
+
+ if tools.config['db_password']:
+ logger.notifyChannel("web-service", netsvc.LOG_ERROR,
+ 'DUMP DB: %s doesn\'t work with password' % (db_name,))
+ raise Exception, "Couldn't dump database with password"
+
+ cmd = ['pg_dump', '--format=c']
+ if tools.config['db_user']:
+ cmd.append('--username=' + tools.config['db_user'])
+ if tools.config['db_host']:
+ cmd.append('--host=' + tools.config['db_host'])
+ if tools.config['db_port']:
+ cmd.append('--port=' + tools.config['db_port'])
+ cmd.append(db_name)
+
+ stdin, stdout = tools.exec_pg_command_pipe(*tuple(cmd))
+ stdin.close()
+ data = stdout.read()
+ res = stdout.close()
+ if res:
+ logger.notifyChannel("web-service", netsvc.LOG_ERROR,
+ 'DUMP DB: %s failed\n%s' % (db_name, data))
+ raise Exception, "Couldn't dump database"
+ logger.notifyChannel("web-services", netsvc.LOG_INFO,
+ 'DUMP DB: %s' % (db_name))
+ return base64.encodestring(data)
+
+ def restore(self, password, db_name, data):
+ security.check_super(password)
+ logger = netsvc.Logger()
+
+ if self.db_exist(db_name):
+ logger.notifyChannel("web-service", netsvc.LOG_WARNING,
+ 'RESTORE DB: %s already exists' % (db_name,))
+ raise Exception, "Database already exists"
+
+ if tools.config['db_password']:
+ logger.notifyChannel("web-service", netsvc.LOG_ERROR,
+ 'RESTORE DB: %s doesn\'t work with password' % (db_name,))
+ raise Exception, "Couldn't restore database with password"
+
+ db = sql_db.db_connect('template1', serialize=1)
+ db.truedb.autocommit()
+ cr = db.cursor()
+ cr.execute('CREATE DATABASE ' + db_name + ' ENCODING \'unicode\'')
+ cr.close()
+
+ cmd = ['pg_restore']
+ if tools.config['db_user']:
+ cmd.append('--username=' + tools.config['db_user'])
+ if tools.config['db_host']:
+ cmd.append('--host=' + tools.config['db_host'])
+ if tools.config['db_port']:
+ cmd.append('--port=' + tools.config['db_port'])
+ cmd.append('--dbname=' + db_name)
+ args2 = tuple(cmd)
+
+ buf=base64.decodestring(data)
+ if os.name == "nt":
+ tmpfile = (os.environ['TMP'] or 'C:\\') + os.tmpnam()
+ file(tmpfile, 'wb').write(buf)
+ args2=list(args2)
+ args2.append(' ' + tmpfile)
+ args2=tuple(args2)
+ stdin, stdout = tools.exec_pg_command_pipe(*args2)
+ if not os.name == "nt":
+ stdin.write(base64.decodestring(data))
+ stdin.close()
+ res = stdout.close()
+ if res:
+ raise Exception, "Couldn't restore database"
+ logger.notifyChannel("web-services", netsvc.LOG_INFO,
+ 'RESTORE DB: %s' % (db_name))
+ return True
+
+ def db_exist(self, db_name):
+ try:
+ db = sql_db.db_connect(db_name)
+ db.truedb.close()
+ return True
+ except:
+ return False
+
+ def list(self):
+ db = sql_db.db_connect('template1')
+ try:
+ cr = db.cursor()
+ db_user = tools.config["db_user"]
+ if not db_user and os.name == 'posix':
+ import pwd
+ db_user = pwd.getpwuid(os.getuid())[0]
+ if not db_user:
+ cr.execute("select usename from pg_user where usesysid=(select datdba from pg_database where datname=%s)", (tools.config["db_name"],))
+ res = cr.fetchone()
+ db_user = res and res[0]
+ if db_user:
+ cr.execute("select datname from pg_database where datdba=(select usesysid from pg_user where usename=%s) and datname not in ('template0', 'template1', 'postgres')", (db_user,))
+ else:
+ cr.execute("select datname from pg_database where datname not in('template0', 'template1','postgres')")
+ res = [name for (name,) in cr.fetchall()]
+ cr.close()
+ except:
+ res = []
+ db.truedb.close()
+ return res
+
+ def change_admin_password(self, old_password, new_password):
+ security.check_super(old_password)
+ tools.config['admin_passwd'] = new_password
+ tools.config.save()
+ return True
+
+ def list_lang(self):
+ return tools.scan_languages()
+ import glob
+ file_list = glob.glob(os.path.join(tools.config['root_path'], 'i18n', '*.csv'))
+ def lang_tuple(fname):
+ lang_dict=tools.get_languages()
+ lang = os.path.basename(fname).split(".")[0]
+ return (lang, lang_dict.get(lang, lang))
+ return [lang_tuple(fname) for fname in file_list]
db()
class common(netsvc.Service):
- def __init__(self,name="common"):
- netsvc.Service.__init__(self,name)
- self.joinGroup("web-services")
- self.exportMethod(self.ir_get)
- self.exportMethod(self.ir_set)
- self.exportMethod(self.ir_del)
- self.exportMethod(self.about)
- self.exportMethod(self.login)
- self.exportMethod(self.timezone_get)
-
- def ir_set(self, db, uid, password, keys, args, name, value, replace=True, isobject=False):
- security.check(db, uid, password)
- cr = pooler.get_db(db).cursor()
- res = ir.ir_set(cr,uid, keys, args, name, value, replace, isobject)
- cr.commit()
- cr.close()
- return res
-
- def ir_del(self, db, uid, password, id):
- security.check(db, uid, password)
- cr = pooler.get_db(db).cursor()
- res = ir.ir_del(cr,uid, id)
- cr.commit()
- cr.close()
- return res
-
- def ir_get(self, db, uid, password, keys, args=None, meta=None, context=None):
- if not args:
- args=[]
- if not context:
- context={}
- security.check(db, uid, password)
- cr = pooler.get_db(db).cursor()
- res = ir.ir_get(cr,uid, keys, args, meta, context)
- cr.commit()
- cr.close()
- return res
-
- def login(self, db, login, password):
- res = security.login(db, login, password)
- logger = netsvc.Logger()
- 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))
- return res or False
-
- def about(self):
- return _('''
+ def __init__(self,name="common"):
+ netsvc.Service.__init__(self,name)
+ self.joinGroup("web-services")
+ self.exportMethod(self.ir_get)
+ self.exportMethod(self.ir_set)
+ self.exportMethod(self.ir_del)
+ self.exportMethod(self.about)
+ self.exportMethod(self.login)
+ self.exportMethod(self.timezone_get)
+
+ def ir_set(self, db, uid, password, keys, args, name, value, replace=True, isobject=False):
+ security.check(db, uid, password)
+ cr = pooler.get_db(db).cursor()
+ res = ir.ir_set(cr,uid, keys, args, name, value, replace, isobject)
+ cr.commit()
+ cr.close()
+ return res
+
+ def ir_del(self, db, uid, password, id):
+ security.check(db, uid, password)
+ cr = pooler.get_db(db).cursor()
+ res = ir.ir_del(cr,uid, id)
+ cr.commit()
+ cr.close()
+ return res
+
+ def ir_get(self, db, uid, password, keys, args=None, meta=None, context=None):
+ if not args:
+ args=[]
+ if not context:
+ context={}
+ security.check(db, uid, password)
+ cr = pooler.get_db(db).cursor()
+ res = ir.ir_get(cr,uid, keys, args, meta, context)
+ cr.commit()
+ cr.close()
+ return res
+
+ def login(self, db, login, password):
+ res = security.login(db, login, password)
+ logger = netsvc.Logger()
+ 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))
+ return res or False
+
+ def about(self):
+ return _('''
OpenERP is an ERP+CRM program for small and medium businesses.
@@ -339,35 +339,35 @@ GNU Public Licence.
(c) 2003-TODAY, Fabien Pinckaers - Tiny sprl''')
- def timezone_get(self, db, login, password):
- return time.tzname[0]
+ def timezone_get(self, db, login, password):
+ return time.tzname[0]
common()
class objects_proxy(netsvc.Service):
- def __init__(self, name="object"):
- netsvc.Service.__init__(self,name)
- self.joinGroup('web-services')
- self.exportMethod(self.execute)
- self.exportMethod(self.exec_workflow)
- self.exportMethod(self.obj_list)
-
- def exec_workflow(self, db, uid, passwd, object, method, id):
- security.check(db, uid, passwd)
- service = netsvc.LocalService("object_proxy")
- res = service.exec_workflow(db, uid, object, method, id)
- return res
-
- def execute(self, db, uid, passwd, object, method, *args):
- security.check(db, uid, passwd)
- service = netsvc.LocalService("object_proxy")
- res = service.execute(db, uid, object, method, *args)
- return res
-
- def obj_list(self, db, uid, passwd):
- security.check(db, uid, passwd)
- service = netsvc.LocalService("object_proxy")
- res = service.obj_list()
- return res
+ def __init__(self, name="object"):
+ netsvc.Service.__init__(self,name)
+ self.joinGroup('web-services')
+ self.exportMethod(self.execute)
+ self.exportMethod(self.exec_workflow)
+ self.exportMethod(self.obj_list)
+
+ def exec_workflow(self, db, uid, passwd, object, method, id):
+ security.check(db, uid, passwd)
+ service = netsvc.LocalService("object_proxy")
+ res = service.exec_workflow(db, uid, object, method, id)
+ return res
+
+ def execute(self, db, uid, passwd, object, method, *args):
+ security.check(db, uid, passwd)
+ service = netsvc.LocalService("object_proxy")
+ res = service.execute(db, uid, object, method, *args)
+ return res
+
+ def obj_list(self, db, uid, passwd):
+ security.check(db, uid, passwd)
+ service = netsvc.LocalService("object_proxy")
+ res = service.obj_list()
+ return res
objects_proxy()
@@ -383,44 +383,44 @@ objects_proxy()
# TODO: change local request to OSE request/reply pattern
#
class wizard(netsvc.Service):
- def __init__(self, name='wizard'):
- netsvc.Service.__init__(self,name)
- self.joinGroup('web-services')
- self.exportMethod(self.execute)
- self.exportMethod(self.create)
- self.id = 0
- self.wiz_datas = {}
- self.wiz_name = {}
- self.wiz_uid = {}
-
- def _execute(self, db, uid, wiz_id, datas, action, context):
- self.wiz_datas[wiz_id].update(datas)
- wiz = netsvc.LocalService('wizard.'+self.wiz_name[wiz_id])
- return wiz.execute(db, uid, self.wiz_datas[wiz_id], action, context)
-
- def create(self, db, uid, passwd, wiz_name, datas=None):
- if not datas:
- datas={}
- security.check(db, uid, passwd)
+ def __init__(self, name='wizard'):
+ netsvc.Service.__init__(self,name)
+ self.joinGroup('web-services')
+ self.exportMethod(self.execute)
+ self.exportMethod(self.create)
+ self.id = 0
+ self.wiz_datas = {}
+ self.wiz_name = {}
+ self.wiz_uid = {}
+
+ def _execute(self, db, uid, wiz_id, datas, action, context):
+ self.wiz_datas[wiz_id].update(datas)
+ wiz = netsvc.LocalService('wizard.'+self.wiz_name[wiz_id])
+ return wiz.execute(db, uid, self.wiz_datas[wiz_id], action, context)
+
+ def create(self, db, uid, passwd, wiz_name, datas=None):
+ if not datas:
+ datas={}
+ security.check(db, uid, passwd)
#FIXME: this is not thread-safe
- self.id += 1
- self.wiz_datas[self.id] = {}
- self.wiz_name[self.id] = wiz_name
- self.wiz_uid[self.id] = uid
- return self.id
-
- def execute(self, db, uid, passwd, wiz_id, datas, action='init', context=None):
- if not context:
- context={}
- security.check(db, uid, passwd)
-
- if wiz_id in self.wiz_uid:
- if self.wiz_uid[wiz_id] == uid:
- return self._execute(db, uid, wiz_id, datas, action, context)
- else:
- raise Exception, 'AccessDenied'
- else:
- raise Exception, 'WizardNotFound'
+ self.id += 1
+ self.wiz_datas[self.id] = {}
+ self.wiz_name[self.id] = wiz_name
+ self.wiz_uid[self.id] = uid
+ return self.id
+
+ def execute(self, db, uid, passwd, wiz_id, datas, action='init', context=None):
+ if not context:
+ context={}
+ security.check(db, uid, passwd)
+
+ if wiz_id in self.wiz_uid:
+ if self.wiz_uid[wiz_id] == uid:
+ return self._execute(db, uid, wiz_id, datas, action, context)
+ else:
+ raise Exception, 'AccessDenied'
+ else:
+ raise Exception, 'WizardNotFound'
wizard()
#
@@ -430,85 +430,85 @@ wizard()
# False -> True
#
class report_spool(netsvc.Service):
- def __init__(self, name='report'):
- netsvc.Service.__init__(self, name)
- self.joinGroup('web-services')
- self.exportMethod(self.report)
- self.exportMethod(self.report_get)
- self._reports = {}
- self.id = 0
- self.id_protect = threading.Semaphore()
-
- def report(self, db, uid, passwd, object, ids, datas=None, context=None):
- if not datas:
- datas={}
- if not context:
- context={}
- security.check(db, uid, passwd)
-
- self.id_protect.acquire()
- self.id += 1
- id = self.id
- self.id_protect.release()
-
- self._reports[id] = {'uid': uid, 'result': False, 'state': False, 'exception': None}
-
- def go(id, uid, ids, datas, context):
- try:
- cr = pooler.get_db(db).cursor()
- obj = netsvc.LocalService('report.'+object)
- (result, format) = obj.create(cr, uid, ids, datas, context)
- cr.close()
- self._reports[id]['result'] = result
- self._reports[id]['format'] = format
- self._reports[id]['state'] = True
- except Exception, exception:
- import traceback
- import sys
- tb_s = reduce(lambda x, y: x+y, traceback.format_exception(
- sys.exc_type, sys.exc_value, sys.exc_traceback))
- logger = netsvc.Logger()
- logger.notifyChannel('web-service', netsvc.LOG_ERROR,
- 'Exception: %s\n%s' % (str(exception), tb_s))
- self._reports[id]['exception'] = exception
- self._reports[id]['state'] = True
- return True
-
- thread.start_new_thread(go, (id, uid, ids, datas, context))
- return id
-
- def _check_report(self, report_id):
- result = self._reports[report_id]
- if result['exception']:
- raise result['exception']
- res = {'state': result['state']}
- if res['state']:
- if tools.config['reportgz']:
- import zlib
- res2 = zlib.compress(result['result'])
- res['code'] = 'zlib'
- else:
- #CHECKME: why is this needed???
- if isinstance(result['result'], unicode):
- res2 = result['result'].encode('latin1', 'replace')
- else:
- res2 = result['result']
- if res2:
- res['result'] = base64.encodestring(res2)
- res['format'] = result['format']
- del self._reports[report_id]
- return res
-
- def report_get(self, db, uid, passwd, report_id):
- security.check(db, uid, passwd)
-
- if report_id in self._reports:
- if self._reports[report_id]['uid'] == uid:
- return self._check_report(report_id)
- else:
- raise Exception, 'AccessDenied'
- else:
- raise Exception, 'ReportNotFound'
+ def __init__(self, name='report'):
+ netsvc.Service.__init__(self, name)
+ self.joinGroup('web-services')
+ self.exportMethod(self.report)
+ self.exportMethod(self.report_get)
+ self._reports = {}
+ self.id = 0
+ self.id_protect = threading.Semaphore()
+
+ def report(self, db, uid, passwd, object, ids, datas=None, context=None):
+ if not datas:
+ datas={}
+ if not context:
+ context={}
+ security.check(db, uid, passwd)
+
+ self.id_protect.acquire()
+ self.id += 1
+ id = self.id
+ self.id_protect.release()
+
+ self._reports[id] = {'uid': uid, 'result': False, 'state': False, 'exception': None}
+
+ def go(id, uid, ids, datas, context):
+ try:
+ cr = pooler.get_db(db).cursor()
+ obj = netsvc.LocalService('report.'+object)
+ (result, format) = obj.create(cr, uid, ids, datas, context)
+ cr.close()
+ self._reports[id]['result'] = result
+ self._reports[id]['format'] = format
+ self._reports[id]['state'] = True
+ except Exception, exception:
+ import traceback
+ import sys
+ tb_s = reduce(lambda x, y: x+y, traceback.format_exception(
+ sys.exc_type, sys.exc_value, sys.exc_traceback))
+ logger = netsvc.Logger()
+ logger.notifyChannel('web-service', netsvc.LOG_ERROR,
+ 'Exception: %s\n%s' % (str(exception), tb_s))
+ self._reports[id]['exception'] = exception
+ self._reports[id]['state'] = True
+ return True
+
+ thread.start_new_thread(go, (id, uid, ids, datas, context))
+ return id
+
+ def _check_report(self, report_id):
+ result = self._reports[report_id]
+ if result['exception']:
+ raise result['exception']
+ res = {'state': result['state']}
+ if res['state']:
+ if tools.config['reportgz']:
+ import zlib
+ res2 = zlib.compress(result['result'])
+ res['code'] = 'zlib'
+ else:
+ #CHECKME: why is this needed???
+ if isinstance(result['result'], unicode):
+ res2 = result['result'].encode('latin1', 'replace')
+ else:
+ res2 = result['result']
+ if res2:
+ res['result'] = base64.encodestring(res2)
+ res['format'] = result['format']
+ del self._reports[report_id]
+ return res
+
+ def report_get(self, db, uid, passwd, report_id):
+ security.check(db, uid, passwd)
+
+ if report_id in self._reports:
+ if self._reports[report_id]['uid'] == uid:
+ return self._check_report(report_id)
+ else:
+ raise Exception, 'AccessDenied'
+ else:
+ raise Exception, 'ReportNotFound'
report_spool()
diff --git a/bin/sql_db.py b/bin/sql_db.py
index 33e4d1a3b1a..e089280a24f 100644
--- a/bin/sql_db.py
+++ b/bin/sql_db.py
@@ -31,9 +31,9 @@ import tools
import sys,os
#try:
-# import decimal
+# import decimal
#except ImportError:
-# from tools import decimal
+# from tools import decimal
import re
@@ -43,112 +43,112 @@ re_from = re.compile('.* from "?([a-zA-Z_0-9]+)"? .*$');
re_into = re.compile('.* into "?([a-zA-Z_0-9]+)"? .*$');
class fake_cursor:
- 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 execute(self, sql, params=None):
- if not params:
- params=()
- def base_string(s):
- if isinstance(s, unicode):
- return s.encode('utf-8')
- return s
- p=map(base_string, params)
- if isinstance(sql, unicode):
- sql = sql.encode('utf-8')
- if self.sql_log:
- now = mdt.now()
- if p:
- res = self.obj.execute(sql, p)
- else:
- res = self.obj.execute(sql)
- if self.sql_log:
- print "SQL LOG query:", sql
- print "SQL LOG params:", repr(p)
- self.count+=1
- res_from = re_from.match(sql.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())
- if res_into:
- self.sql_into_log.setdefault(res_into.group(1), [0, 0])
- self.sql_into_log[res_into.group(1)][0] += 1
- self.sql_into_log[res_into.group(1)][1] += mdt.now() - now
- return res
-
- def print_log(self, type='from'):
- print "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:
- print "table:", r[0], ":", str(r[1][1]), "/", r[1][0]
- sum+= r[1][1]
- print "SUM:%s/%d"% (sum, self.count)
-
- def close(self):
- if self.sql_log:
- self.print_log('from')
- self.print_log('into')
- 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
-
- def __getattr__(self, name):
- return getattr(self.obj, name)
+ 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 execute(self, sql, params=None):
+ if not params:
+ params=()
+ def base_string(s):
+ if isinstance(s, unicode):
+ return s.encode('utf-8')
+ return s
+ p=map(base_string, params)
+ if isinstance(sql, unicode):
+ sql = sql.encode('utf-8')
+ if self.sql_log:
+ now = mdt.now()
+ if p:
+ res = self.obj.execute(sql, p)
+ else:
+ res = self.obj.execute(sql)
+ if self.sql_log:
+ print "SQL LOG query:", sql
+ print "SQL LOG params:", repr(p)
+ self.count+=1
+ res_from = re_from.match(sql.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())
+ if res_into:
+ self.sql_into_log.setdefault(res_into.group(1), [0, 0])
+ self.sql_into_log[res_into.group(1)][0] += 1
+ self.sql_into_log[res_into.group(1)][1] += mdt.now() - now
+ return res
+
+ def print_log(self, type='from'):
+ print "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:
+ print "table:", r[0], ":", str(r[1][1]), "/", r[1][0]
+ sum+= r[1][1]
+ print "SUM:%s/%d"% (sum, self.count)
+
+ def close(self):
+ if self.sql_log:
+ self.print_log('from')
+ self.print_log('into')
+ 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
+
+ def __getattr__(self, name):
+ return getattr(self.obj, name)
class fakedb:
- def __init__(self, truedb, dbname):
- self.truedb = truedb
- self.dbname = dbname
-
- def cursor(self):
- return fake_cursor(self.truedb, {}, self.dbname)
+ def __init__(self, truedb, dbname):
+ self.truedb = truedb
+ self.dbname = dbname
+
+ def cursor(self):
+ return fake_cursor(self.truedb, {}, self.dbname)
def decimalize(symb):
- if symb is None: return None
- if isinstance(symb, float):
- return decimal.Decimal('%f' % symb)
- return decimal.Decimal(symb)
+ if symb is None: return None
+ if isinstance(symb, float):
+ return decimal.Decimal('%f' % symb)
+ return decimal.Decimal(symb)
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
+ 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))
+ #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))
diff --git a/bin/tiny_socket.py b/bin/tiny_socket.py
index ef575714c7d..843565406c7 100644
--- a/bin/tiny_socket.py
+++ b/bin/tiny_socket.py
@@ -30,61 +30,61 @@ import cPickle
import marshal
class Myexception(Exception):
- def __init__(self, faultCode, faultString):
- self.faultCode = faultCode
- self.faultString = faultString
- self.args = (faultCode, faultString)
+ def __init__(self, faultCode, faultString):
+ self.faultCode = faultCode
+ self.faultString = faultString
+ self.args = (faultCode, faultString)
class mysocket:
- def __init__(self, sock=None):
- if sock is None:
- self.sock = socket.socket(
- socket.AF_INET, socket.SOCK_STREAM)
- else:
- self.sock = sock
- self.sock.settimeout(120)
- def connect(self, host, port=False):
- if not port:
- protocol, buf = host.split('//')
- host, port = buf.split(':')
- self.sock.connect((host, int(port)))
- def disconnect(self):
- self.sock.shutdown(socket.SHUT_RDWR)
- self.sock.close()
- def mysend(self, msg, exception=False, traceback=None):
- msg = cPickle.dumps([msg,traceback])
- size = len(msg)
- self.sock.send('%8d' % size)
- self.sock.send(exception and "1" or "0")
- totalsent = 0
- while totalsent < size:
- sent = self.sock.send(msg[totalsent:])
- if sent == 0:
- raise RuntimeError, "socket connection broken"
- totalsent = totalsent + sent
- def myreceive(self):
- buf=''
- while len(buf) < 8:
- chunk = self.sock.recv(8 - len(buf))
- if chunk == '':
- raise RuntimeError, "socket connection broken"
- buf += chunk
- size = int(buf)
- buf = self.sock.recv(1)
- if buf != "0":
- exception = buf
- else:
- exception = False
- msg = ''
- while len(msg) < size:
- chunk = self.sock.recv(size-len(msg))
- if chunk == '':
- raise RuntimeError, "socket connection broken"
- msg = msg + chunk
- res = cPickle.loads(msg)
- if isinstance(res[0],Exception):
- if exception:
- raise Myexception(str(res[0]), str(res[1]))
- raise res[0]
- else:
- return res[0]
+ def __init__(self, sock=None):
+ if sock is None:
+ self.sock = socket.socket(
+ socket.AF_INET, socket.SOCK_STREAM)
+ else:
+ self.sock = sock
+ self.sock.settimeout(120)
+ def connect(self, host, port=False):
+ if not port:
+ protocol, buf = host.split('//')
+ host, port = buf.split(':')
+ self.sock.connect((host, int(port)))
+ def disconnect(self):
+ self.sock.shutdown(socket.SHUT_RDWR)
+ self.sock.close()
+ def mysend(self, msg, exception=False, traceback=None):
+ msg = cPickle.dumps([msg,traceback])
+ size = len(msg)
+ self.sock.send('%8d' % size)
+ self.sock.send(exception and "1" or "0")
+ totalsent = 0
+ while totalsent < size:
+ sent = self.sock.send(msg[totalsent:])
+ if sent == 0:
+ raise RuntimeError, "socket connection broken"
+ totalsent = totalsent + sent
+ def myreceive(self):
+ buf=''
+ while len(buf) < 8:
+ chunk = self.sock.recv(8 - len(buf))
+ if chunk == '':
+ raise RuntimeError, "socket connection broken"
+ buf += chunk
+ size = int(buf)
+ buf = self.sock.recv(1)
+ if buf != "0":
+ exception = buf
+ else:
+ exception = False
+ msg = ''
+ while len(msg) < size:
+ chunk = self.sock.recv(size-len(msg))
+ if chunk == '':
+ raise RuntimeError, "socket connection broken"
+ msg = msg + chunk
+ res = cPickle.loads(msg)
+ if isinstance(res[0],Exception):
+ if exception:
+ raise Myexception(str(res[0]), str(res[1]))
+ raise res[0]
+ else:
+ return res[0]
diff --git a/bin/tinyerp-server.py b/bin/tinyerp-server.py
index c022188ff72..bd08be09346 100755..100644
--- a/bin/tinyerp-server.py
+++ b/bin/tinyerp-server.py
@@ -75,8 +75,8 @@ import tools
import time
if sys.platform=='win32':
- import mx.DateTime
- mx.DateTime.strptime = lambda x,y: mx.DateTime.mktime(time.strptime(x, y))
+ import mx.DateTime
+ mx.DateTime.strptime = lambda x,y: mx.DateTime.mktime(time.strptime(x, y))
#os.chdir(tools.file_path_root)
@@ -98,18 +98,18 @@ import pooler
# try to connect to the database
try:
-# pooler.init()
- pass
+# pooler.init()
+ pass
except psycopg.OperationalError, err:
- logger.notifyChannel("init", netsvc.LOG_ERROR, "could not connect to database '%s'!" % (tools.config["db_name"],))
-
- msg = str(err).replace("FATAL:","").strip()
- db_msg = "database \"%s\" does not exist" % (tools.config["db_name"],)
-
- # Note: this is ugly but since psycopg only uses one exception for all errors
- # I don't think it's possible to do differently
- if msg == db_msg:
- print """
+ logger.notifyChannel("init", netsvc.LOG_ERROR, "could not connect to database '%s'!" % (tools.config["db_name"],))
+
+ msg = str(err).replace("FATAL:","").strip()
+ db_msg = "database \"%s\" does not exist" % (tools.config["db_name"],)
+
+ # Note: this is ugly but since psycopg only uses one exception for all errors
+ # I don't think it's possible to do differently
+ if msg == db_msg:
+ print """
this database does not exist
You need to create it using the command:
@@ -126,42 +126,42 @@ Two accounts will be created by default:
2. login: demo password : demo
""" % (tools.config["db_name"])
- else:
- print "\n "+msg+"\n"
- sys.exit(1)
+ else:
+ print "\n "+msg+"\n"
+ sys.exit(1)
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()
+ 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
+ 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:
+ 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()
+ 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...'
- import tools.upgrade
- (toinit, toupdate) = tools.upgrade.upgrade()
- for m in toinit:
- tools.config['init'][m] = 1
- for m in toupdate:
- tools.config['update'][m] = 1
+ print 'Upgrading new modules...'
+ import tools.upgrade
+ (toinit, toupdate) = tools.upgrade.upgrade()
+ for m in toinit:
+ tools.config['init'][m] = 1
+ for m in toupdate:
+ tools.config['update'][m] = 1
#----------------------------------------------------------
# import basic modules
@@ -175,27 +175,27 @@ import addons
addons.register_classes()
if tools.config['init'] or tools.config['update']:
- pooler.get_db_and_pool(tools.config['db_name'], update_module=True)
+ pooler.get_db_and_pool(tools.config['db_name'], update_module=True)
#----------------------------------------------------------
# translation stuff
#----------------------------------------------------------
if tools.config["translate_out"]:
- import csv
+ import csv
- logger.notifyChannel("init", netsvc.LOG_INFO, 'writing translation file for language %s to %s' % (tools.config["language"], tools.config["translate_out"]))
+ logger.notifyChannel("init", netsvc.LOG_INFO, 'writing translation file for language %s to %s' % (tools.config["language"], tools.config["translate_out"]))
- fileformat = os.path.splitext(tools.config["translate_out"])[-1][1:].lower()
- buf = file(tools.config["translate_out"], "w")
- tools.trans_export(tools.config["language"], tools.config["translate_modules"], buf, fileformat)
- buf.close()
-
- logger.notifyChannel("init", netsvc.LOG_INFO, 'translation file written succesfully')
- sys.exit(0)
+ fileformat = os.path.splitext(tools.config["translate_out"])[-1][1:].lower()
+ buf = file(tools.config["translate_out"], "w")
+ tools.trans_export(tools.config["language"], tools.config["translate_modules"], buf, fileformat)
+ buf.close()
+
+ logger.notifyChannel("init", netsvc.LOG_INFO, 'translation file written succesfully')
+ sys.exit(0)
if tools.config["translate_in"]:
- tools.trans_load(tools.config["db_name"], tools.config["translate_in"], tools.config["language"])
- sys.exit(0)
+ tools.trans_load(tools.config["db_name"], tools.config["translate_in"], tools.config["language"])
+ sys.exit(0)
#----------------------------------------------------------------------------------
# if we don't want the server to continue to run after initialization, we quit here
@@ -209,69 +209,69 @@ if tools.config["stop_after_init"]:
#----------------------------------------------------------
if tools.config['xmlrpc']:
- try:
- port = int(tools.config["port"])
- except Exception:
- logger.notifyChannel("init", netsvc.LOG_ERROR, "invalid port '%s'!" % (tools.config["port"],))
- sys.exit(1)
- interface = tools.config["interface"]
- secure = tools.config["secure"]
-
- httpd = netsvc.HttpDaemon(interface,port, secure)
-
- 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))
-
- #
- #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))
- #
+ try:
+ port = int(tools.config["port"])
+ except Exception:
+ logger.notifyChannel("init", netsvc.LOG_ERROR, "invalid port '%s'!" % (tools.config["port"],))
+ sys.exit(1)
+ interface = tools.config["interface"]
+ secure = tools.config["secure"]
+
+ httpd = netsvc.HttpDaemon(interface,port, secure)
+
+ 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))
+
+ #
+ #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:
- netport = int(tools.config["netport"])
- except Exception:
- logger.notifyChannel("init", netsvc.LOG_ERROR, "invalid port '%s'!" % (tools.config["netport"],))
- sys.exit(1)
- netinterface = tools.config["netinterface"]
-
- tinySocket = netsvc.TinySocketServerThread(netinterface, netport, False)
- logger.notifyChannel("web-services", netsvc.LOG_INFO, "starting netrpc service, port "+str(netport))
+ try:
+ netport = int(tools.config["netport"])
+ except Exception:
+ logger.notifyChannel("init", netsvc.LOG_ERROR, "invalid port '%s'!" % (tools.config["netport"],))
+ sys.exit(1)
+ netinterface = tools.config["netinterface"]
+
+ tinySocket = netsvc.TinySocketServerThread(netinterface, netport, False)
+ logger.notifyChannel("web-services", netsvc.LOG_INFO, "starting netrpc service, port "+str(netport))
def handler(signum, frame):
- from tools import config
- if tools.config['netrpc']:
- tinySocket.stop()
- if tools.config['xmlrpc']:
- httpd.stop()
- netsvc.Agent.quit()
- if config['pidfile']:
- os.unlink(config['pidfile'])
- sys.exit(0)
+ from tools import config
+ if tools.config['netrpc']:
+ tinySocket.stop()
+ if tools.config['xmlrpc']:
+ httpd.stop()
+ netsvc.Agent.quit()
+ if config['pidfile']:
+ os.unlink(config['pidfile'])
+ sys.exit(0)
from tools import config
if config['pidfile']:
- fd=open(config['pidfile'], 'w')
- pidtext="%d" % (os.getpid())
- fd.write(pidtext)
- fd.close()
+ fd=open(config['pidfile'], 'w')
+ pidtext="%d" % (os.getpid())
+ fd.write(pidtext)
+ fd.close()
signal.signal(signal.SIGINT, handler)
signal.signal(signal.SIGTERM, handler)
logger.notifyChannel("web-services", netsvc.LOG_INFO, 'the server is running, waiting for connections...')
if tools.config['netrpc']:
- tinySocket.start()
+ tinySocket.start()
if tools.config['xmlrpc']:
- httpd.start()
+ httpd.start()
#dispatcher.run()
while True:
- time.sleep(1)
+ time.sleep(1)
diff --git a/bin/tools/amount_to_text.py b/bin/tools/amount_to_text.py
index e7ef353a845..ae4ff453161 100644
--- a/bin/tools/amount_to_text.py
+++ b/bin/tools/amount_to_text.py
@@ -32,182 +32,182 @@
#-------------------------------------------------------------
unites = {
- 0: '', 1:'un', 2:'deux', 3:'trois', 4:'quatre', 5:'cinq', 6:'six', 7:'sept', 8:'huit', 9:'neuf',
- 10:'dix', 11:'onze', 12:'douze', 13:'treize', 14:'quatorze', 15:'quinze', 16:'seize',
- 21:'vingt et un', 31:'trente et un', 41:'quarante et un', 51:'cinquante et un', 61:'soixante et un',
- 71:'septante et un', 91:'nonante et un', 80:'quatre-vingts'
+ 0: '', 1:'un', 2:'deux', 3:'trois', 4:'quatre', 5:'cinq', 6:'six', 7:'sept', 8:'huit', 9:'neuf',
+ 10:'dix', 11:'onze', 12:'douze', 13:'treize', 14:'quatorze', 15:'quinze', 16:'seize',
+ 21:'vingt et un', 31:'trente et un', 41:'quarante et un', 51:'cinquante et un', 61:'soixante et un',
+ 71:'septante et un', 91:'nonante et un', 80:'quatre-vingts'
}
dizaine = {
- 1: 'dix', 2:'vingt', 3:'trente',4:'quarante', 5:'cinquante', 6:'soixante', 7:'septante', 8:'quatre-vingt', 9:'nonante'
+ 1: 'dix', 2:'vingt', 3:'trente',4:'quarante', 5:'cinquante', 6:'soixante', 7:'septante', 8:'quatre-vingt', 9:'nonante'
}
centaine = {
- 0:'', 1: 'cent', 2:'deux cent', 3:'trois cent',4:'quatre cent', 5:'cinq cent', 6:'six cent', 7:'sept cent', 8:'huit cent', 9:'neuf cent'
+ 0:'', 1: 'cent', 2:'deux cent', 3:'trois cent',4:'quatre cent', 5:'cinq cent', 6:'six cent', 7:'sept cent', 8:'huit cent', 9:'neuf cent'
}
mille = {
- 0:'', 1:'mille'
+ 0:'', 1:'mille'
}
def _100_to_text_fr(chiffre):
- if chiffre in unites:
- return unites[chiffre]
- else:
- if chiffre%10>0:
- return dizaine[chiffre / 10]+'-'+unites[chiffre % 10]
- else:
- return dizaine[chiffre / 10]
+ if chiffre in unites:
+ return unites[chiffre]
+ else:
+ if chiffre%10>0:
+ return dizaine[chiffre / 10]+'-'+unites[chiffre % 10]
+ else:
+ return dizaine[chiffre / 10]
def _1000_to_text_fr(chiffre):
- d = _100_to_text_fr(chiffre % 100)
- d2 = chiffre/100
- if d2>0 and d:
- return centaine[d2]+' '+d
- elif d2>1 and not(d):
- return centaine[d2]+'s'
- else:
- return centaine[d2] or d
+ d = _100_to_text_fr(chiffre % 100)
+ d2 = chiffre/100
+ if d2>0 and d:
+ return centaine[d2]+' '+d
+ elif d2>1 and not(d):
+ return centaine[d2]+'s'
+ else:
+ return centaine[d2] or d
def _10000_to_text_fr(chiffre):
- if chiffre==0:
- return 'zero'
- part1 = _1000_to_text_fr(chiffre % 1000)
- part2 = mille.get(chiffre / 1000, _1000_to_text_fr(chiffre / 1000)+' mille')
- if part2 and part1:
- part1 = ' '+part1
- return part2+part1
-
+ if chiffre==0:
+ return 'zero'
+ part1 = _1000_to_text_fr(chiffre % 1000)
+ part2 = mille.get(chiffre / 1000, _1000_to_text_fr(chiffre / 1000)+' mille')
+ if part2 and part1:
+ part1 = ' '+part1
+ return part2+part1
+
def amount_to_text_fr(number, currency):
- units_number = int(number)
- units_name = currency
- if units_number > 1:
- units_name += 's'
- units = _10000_to_text_fr(units_number)
- units = units_number and '%s %s' % (units, units_name) or ''
-
- cents_number = int(number * 100) % 100
- cents_name = (cents_number > 1) and 'cents' or 'cent'
- cents = _100_to_text_fr(cents_number)
- cents = cents_number and '%s %s' % (cents, cents_name) or ''
-
- if units and cents:
- cents = ' '+cents
-
- return units + cents
+ units_number = int(number)
+ units_name = currency
+ if units_number > 1:
+ units_name += 's'
+ units = _10000_to_text_fr(units_number)
+ units = units_number and '%s %s' % (units, units_name) or ''
+
+ cents_number = int(number * 100) % 100
+ cents_name = (cents_number > 1) and 'cents' or 'cent'
+ cents = _100_to_text_fr(cents_number)
+ cents = cents_number and '%s %s' % (cents, cents_name) or ''
+
+ if units and cents:
+ cents = ' '+cents
+
+ return units + cents
#-------------------------------------------------------------
# Dutch
#-------------------------------------------------------------
units_nl = {
- 0:'', 1:'een', 2:'twee', 3:'drie', 4:'vier', 5:'vijf', 6:'zes', 7:'zeven', 8:'acht', 9:'negen',
- 10:'tien', 11:'elf', 12:'twaalf', 13:'dertien', 14:'veertien'
+ 0:'', 1:'een', 2:'twee', 3:'drie', 4:'vier', 5:'vijf', 6:'zes', 7:'zeven', 8:'acht', 9:'negen',
+ 10:'tien', 11:'elf', 12:'twaalf', 13:'dertien', 14:'veertien'
}
tens_nl = {
- 1: 'tien', 2:'twintig', 3:'dertig',4:'veertig', 5:'vijftig', 6:'zestig', 7:'zeventig', 8:'tachtig', 9:'negentig'
+ 1: 'tien', 2:'twintig', 3:'dertig',4:'veertig', 5:'vijftig', 6:'zestig', 7:'zeventig', 8:'tachtig', 9:'negentig'
}
hundreds_nl = {
- 0:'', 1: 'honderd',
+ 0:'', 1: 'honderd',
}
thousands_nl = {
- 0:'', 1:'duizend'
+ 0:'', 1:'duizend'
}
def _100_to_text_nl(number):
- if number in units_nl:
- return units_nl[number]
- else:
- if number%10 > 0:
- if number>10 and number<20:
- return units_nl[number % 10]+tens_nl[number / 10]
- else:
- units = units_nl[number % 10]
- if units[-1] == 'e':
- joinword = 'ën'
- else:
- joinword = 'en'
- return units+joinword+tens_nl[number / 10]
- else:
- return tens_nl[number / 10]
+ if number in units_nl:
+ return units_nl[number]
+ else:
+ if number%10 > 0:
+ if number>10 and number<20:
+ return units_nl[number % 10]+tens_nl[number / 10]
+ else:
+ units = units_nl[number % 10]
+ if units[-1] == 'e':
+ joinword = 'ën'
+ else:
+ joinword = 'en'
+ return units+joinword+tens_nl[number / 10]
+ else:
+ return tens_nl[number / 10]
def _1000_to_text_nl(number):
- part1 = _100_to_text_nl(number % 100)
- part2 = hundreds_nl.get(number / 100, units_nl[number/100] + hundreds_nl[1])
- if part2 and part1:
- part1 = ' ' + part1
- return part2 + part1
+ part1 = _100_to_text_nl(number % 100)
+ part2 = hundreds_nl.get(number / 100, units_nl[number/100] + hundreds_nl[1])
+ if part2 and part1:
+ part1 = ' ' + part1
+ return part2 + part1
def _10000_to_text_nl(number):
- if number==0:
- return 'nul'
- part1 = _1000_to_text_nl(number % 1000)
- if thousands_nl.has_key(number / 1000):
- part2 = thousands_nl[number / 1000]
- else:
- if (number / 1000 % 100 > 0) and (number / 1000 > 100):
- space = ' '
- else:
- space = ''
- part2 = _1000_to_text_nl(number / 1000) + space + thousands_nl[1]
- if part2 and part1:
- part1 = ' ' + part1
- return part2 + part1
-
+ if number==0:
+ return 'nul'
+ part1 = _1000_to_text_nl(number % 1000)
+ if thousands_nl.has_key(number / 1000):
+ part2 = thousands_nl[number / 1000]
+ else:
+ if (number / 1000 % 100 > 0) and (number / 1000 > 100):
+ space = ' '
+ else:
+ space = ''
+ part2 = _1000_to_text_nl(number / 1000) + space + thousands_nl[1]
+ if part2 and part1:
+ part1 = ' ' + part1
+ return part2 + part1
+
def amount_to_text_nl(number, currency):
- units_number = int(number)
- units_name = currency
- units = _10000_to_text_nl(units_number)
- units = units_number and '%s %s' % (units, units_name) or ''
-
- cents_number = int(number * 100) % 100
- cents_name = 'cent'
- cents = _100_to_text_nl(cents_number)
- cents = cents_number and '%s %s' % (cents, cents_name) or ''
-
- if units and cents:
- cents = ' ' + cents
-
- return units + cents
+ units_number = int(number)
+ units_name = currency
+ units = _10000_to_text_nl(units_number)
+ units = units_number and '%s %s' % (units, units_name) or ''
+
+ cents_number = int(number * 100) % 100
+ cents_name = 'cent'
+ cents = _100_to_text_nl(cents_number)
+ cents = cents_number and '%s %s' % (cents, cents_name) or ''
+
+ if units and cents:
+ cents = ' ' + cents
+
+ return units + cents
#-------------------------------------------------------------
# Generic functions
#-------------------------------------------------------------
_translate_funcs = {'fr' : amount_to_text_fr, 'nl' : amount_to_text_nl}
-
+
#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
def amount_to_text(nbr, lang='fr', currency='euro'):
- """
- Converts an integer to its textual representation, using the language set in the context if any.
- Example:
- 1654: mille six cent cinquante-quatre.
- """
- if nbr > 1000000:
-#TODO: use logger
- print "WARNING: number too large '%d', can't translate it!" % (nbr,)
- return str(nbr)
-
- if not _translate_funcs.has_key(lang):
-#TODO: use logger
- print "WARNING: no translation function found for lang: '%s'" % (lang,)
+ """
+ Converts an integer to its textual representation, using the language set in the context if any.
+ Example:
+ 1654: mille six cent cinquante-quatre.
+ """
+ if nbr > 1000000:
+#TODO: use logger
+ print "WARNING: number too large '%d', can't translate it!" % (nbr,)
+ 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
- lang = 'fr'
- return _translate_funcs[lang](nbr, currency)
+ lang = 'fr'
+ return _translate_funcs[lang](nbr, currency)
if __name__=='__main__':
- from sys import argv
-
- lang = 'nl'
- if len(argv) < 2:
- for i in range(1,200):
- print i, ">>", amount_to_text(i, lang)
- for i in range(200,999999,139):
- print i, ">>", amount_to_text(i, lang)
- else:
- print amount_to_text(int(argv[1]), lang)
+ from sys import argv
+
+ lang = 'nl'
+ if len(argv) < 2:
+ for i in range(1,200):
+ print i, ">>", amount_to_text(i, lang)
+ for i in range(200,999999,139):
+ print i, ">>", amount_to_text(i, lang)
+ else:
+ print amount_to_text(int(argv[1]), lang)
diff --git a/bin/tools/config.py b/bin/tools/config.py
index 72f0f98091f..5b279a9eed2 100644
--- a/bin/tools/config.py
+++ b/bin/tools/config.py
@@ -31,208 +31,208 @@ import netsvc,logging
class configmanager(object):
- def __init__(self, fname=None):
- self.options = {
- 'verbose': False,
- 'interface': '', # this will bind the server to all interfaces
- 'port': '8069',
- 'netinterface': '',
- 'netport': '8070',
- 'db_host': False,
- 'db_port': False,
- 'db_name': 'terp',
- 'db_user': False,
- 'db_password': False,
- 'db_maxconn': 64,
- 'reportgz': False,
- 'netrpc': True,
- 'xmlrpc': True,
- 'soap': False,
- 'translate_in': None,
- 'translate_out': None,
- 'language': None,
- 'pg_path': None,
- 'admin_passwd': 'admin',
- 'addons_path': None,
- 'root_path': None,
- 'debug_mode': False,
- 'commit_mode': False,
- 'pidfile': None,
- 'logfile': None,
- 'secure': False,
- 'smtp_server': 'localhost',
- 'smtp_user': False,
- 'smtp_password': False,
- '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
- }
-
- assert_exit_levels = (netsvc.LOG_CRITICAL, netsvc.LOG_ERROR, netsvc.LOG_WARNING, netsvc.LOG_INFO, netsvc.LOG_DEBUG)
-
- parser = optparse.OptionParser(version=tinyerp_version_string)
-
- parser.add_option("-c", "--config", dest="config", help="specify alternate config file")
- parser.add_option("-s", "--save", action="store_true", dest="save", default=False, help="save configuration to ~/.terp_serverrc")
- parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False, help="enable debugging")
- parser.add_option("--pidfile", dest="pidfile", help="file where the server pid will be stored")
- parser.add_option("--logfile", dest="logfile", help="file where the server log will be stored")
-
- parser.add_option("-n", "--interface", dest="interface", help="specify the TCP IP address")
- parser.add_option("-p", "--port", dest="port", help="specify the TCP port")
- parser.add_option("--net_interface", dest="netinterface", help="specify the TCP IP address for netrpc")
- parser.add_option("--net_port", dest="netport", help="specify the TCP port for netrpc")
- parser.add_option("--no-netrpc", dest="netrpc", action="store_false", default=True, help="disable netrpc")
- parser.add_option("--no-xmlrpc", dest="xmlrpc", action="store_false", default=True, help="disable xmlrpc")
-
- parser.add_option("-i", "--init", dest="init", help="init a module (use \"all\" for all modules)")
- parser.add_option("--without-demo", dest="without_demo", help="load demo data for a module (use \"all\" for all modules)", default=False)
- parser.add_option("-u", "--update", dest="update", help="update a module (use \"all\" for all modules)")
- # 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("-S", "--secure", dest="secure", action="store_true", help="launch server over https instead of http", default=False)
- parser.add_option('--smtp', dest='smtp_server', default='', help='specify the SMTP server for sending email')
- parser.add_option('--smtp-user', dest='smtp_user', default='', help='specify the SMTP username for sending email')
- parser.add_option('--smtp-password', dest='smtp_password', default='', help='specify the SMTP password for sending email')
- parser.add_option('--price_accuracy', dest='price_accuracy', default='2', help='specify the price accuracy')
-
- group = optparse.OptionGroup(parser, "Modules related options")
- group.add_option("-g", "--upgrade", action="store_true", dest="upgrade", default=False, help="Upgrade/install/uninstall modules")
-
- group = optparse.OptionGroup(parser, "Database related options")
- group.add_option("-d", "--database", dest="db_name", help="specify the database name")
- group.add_option("-r", "--db_user", dest="db_user", help="specify the database user name")
- group.add_option("-w", "--db_password", dest="db_password", help="specify the database password")
- group.add_option("--pg_path", dest="pg_path", help="specify the pg executable path")
- group.add_option("--db_host", dest="db_host", help="specify the database host")
- group.add_option("--db_port", dest="db_port", help="specify the database port")
- group.add_option("--db_maxconn", dest="db_maxconn", default='64', help="specify the the maximum number of physical connections to posgresql")
- group.add_option("-C", "--commit-mode", dest="commit_mode", action="store_true", help="Several commit during one file importation. Use this for big data importation.", default=False)
- parser.add_option_group(group)
-
- group = optparse.OptionGroup(parser, "Internationalisation options",
- "Use these options to translate Tiny ERP to another language."
- "See i18n section of the user manual. Options '-l' and '-d' are mandatory.")
-
- group.add_option('-l', "--language", dest="language", help="specify the language of the translation file. Use it with --i18n-export and --i18n-import")
- group.add_option("--i18n-export", dest="translate_out", help="export all sentences to be translated to a CSV or a PO file and exit")
- group.add_option("--i18n-import", dest="translate_in", help="import a CSV or a PO file with translations and exit")
- group.add_option("--modules", dest="translate_modules", help="specify modules to export. Use in combination with --i18n-export")
- group.add_option("--addons-path", dest="addons_path", help="specify an alternative addons path.")
- parser.add_option_group(group)
-
- (opt, args) = parser.parse_args()
-
- assert not ((opt.translate_in or opt.translate_out) and (not opt.language or not opt.db_name)), "the i18n-import and i18n-export options cannot be used without the language (-l) and database (-d) options"
-
- # place/search the config file on Win32 near the server installation
- # (../etc from the server)
- # if the server is run by an unprivileged user, he has to specify location of a config file where he has the rights to write,
- # else he won't be able to save the configurations, or even to start the server...
- if os.name == 'nt':
- rcfilepath = os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), 'tinyerp-server.conf')
- else:
- rcfilepath = os.path.expanduser('~/.terp_serverrc')
-
- self.rcfile = fname or opt.config or os.environ.get('TERP_SERVER') or rcfilepath
- self.load()
-
-
- # Verify that we want to log or not, if not the output will go to stdout
- if self.options['logfile'] in ('None', 'False'):
- self.options['logfile'] = False
- # the same for the pidfile
- if self.options['pidfile'] in ('None', 'False'):
- self.options['pidfile'] = False
-
- for arg in ('interface', 'port', 'db_name', 'db_user', 'db_password', 'db_host',
- 'db_port', 'logfile', 'pidfile', 'secure', 'smtp_server', 'smtp_user', 'smtp_password', 'price_accuracy', 'netinterface', 'netport', 'db_maxconn', 'commit_mode', 'addons_path'):
- if getattr(opt, arg):
- self.options[arg] = getattr(opt, arg)
-
- for arg in ('language', 'translate_out', 'translate_in',
- 'upgrade', 'verbose', 'debug_mode',
- 'stop_after_init', 'without_demo', 'netrpc', 'xmlrpc'):
- 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())
-
- 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]))
- if not self.options['addons_path'] or self.options['addons_path']=='None':
- self.options['addons_path'] = os.path.join(self.options['root_path'], 'addons')
-
- init = {}
- if opt.init:
- for i in opt.init.split(','):
- init[i] = 1
- self.options['init'] = init
- self.options["demo"] = not opt.without_demo and self.options['init'] or {}
-
- update = {}
- if opt.update:
- for i in opt.update.split(','):
- update[i] = 1
- self.options['update'] = update
-
- self.options['translate_modules'] = opt.translate_modules and map(lambda m: m.strip(), opt.translate_modules.split(',')) or ['all']
- self.options['translate_modules'].sort()
-
- if opt.pg_path:
- self.options['pg_path'] = opt.pg_path
-
- if self.options.get('language', False):
- assert len(self.options['language'])<=5, 'ERROR: The Lang name must take max 5 chars, Eg: -lfr_BE'
- if opt.save:
- self.save()
-
- def load(self):
- p = ConfigParser.ConfigParser()
- try:
- p.read([self.rcfile])
- for (name,value) in p.items('options'):
- if value=='True' or value=='true':
- value = True
- if value=='False' or value=='false':
- value = False
- self.options[name] = value
- except IOError:
- pass
- except ConfigParser.NoSectionError:
- pass
-
- def save(self):
- p = ConfigParser.ConfigParser()
- p.add_section('options')
- for o in [opt for opt in self.options.keys() if opt not in ('version','language','translate_out','translate_in','init','update')]:
- p.set('options', o, self.options[o])
-
- # try to create the directories and write the file
- try:
- if not os.path.exists(os.path.dirname(self.rcfile)):
- os.makedirs(os.path.dirname(self.rcfile))
- try:
- p.write(file(self.rcfile, 'w'))
- except IOError:
- sys.stderr.write("ERROR: couldn't write the config file\n")
-
- except OSError:
- # what to do if impossible?
- sys.stderr.write("ERROR: couldn't create the config directory\n")
-
- def get(self, key, default=None):
- return self.options.get(key, default)
-
- def __setitem__(self, key, value):
- self.options[key] = value
-
- def __getitem__(self, key):
- return self.options[key]
+ def __init__(self, fname=None):
+ self.options = {
+ 'verbose': False,
+ 'interface': '', # this will bind the server to all interfaces
+ 'port': '8069',
+ 'netinterface': '',
+ 'netport': '8070',
+ 'db_host': False,
+ 'db_port': False,
+ 'db_name': 'terp',
+ 'db_user': False,
+ 'db_password': False,
+ 'db_maxconn': 64,
+ 'reportgz': False,
+ 'netrpc': True,
+ 'xmlrpc': True,
+ 'soap': False,
+ 'translate_in': None,
+ 'translate_out': None,
+ 'language': None,
+ 'pg_path': None,
+ 'admin_passwd': 'admin',
+ 'addons_path': None,
+ 'root_path': None,
+ 'debug_mode': False,
+ 'commit_mode': False,
+ 'pidfile': None,
+ 'logfile': None,
+ 'secure': False,
+ 'smtp_server': 'localhost',
+ 'smtp_user': False,
+ 'smtp_password': False,
+ '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
+ }
+
+ assert_exit_levels = (netsvc.LOG_CRITICAL, netsvc.LOG_ERROR, netsvc.LOG_WARNING, netsvc.LOG_INFO, netsvc.LOG_DEBUG)
+
+ parser = optparse.OptionParser(version=tinyerp_version_string)
+
+ parser.add_option("-c", "--config", dest="config", help="specify alternate config file")
+ parser.add_option("-s", "--save", action="store_true", dest="save", default=False, help="save configuration to ~/.terp_serverrc")
+ parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False, help="enable debugging")
+ parser.add_option("--pidfile", dest="pidfile", help="file where the server pid will be stored")
+ parser.add_option("--logfile", dest="logfile", help="file where the server log will be stored")
+
+ parser.add_option("-n", "--interface", dest="interface", help="specify the TCP IP address")
+ parser.add_option("-p", "--port", dest="port", help="specify the TCP port")
+ parser.add_option("--net_interface", dest="netinterface", help="specify the TCP IP address for netrpc")
+ parser.add_option("--net_port", dest="netport", help="specify the TCP port for netrpc")
+ parser.add_option("--no-netrpc", dest="netrpc", action="store_false", default=True, help="disable netrpc")
+ parser.add_option("--no-xmlrpc", dest="xmlrpc", action="store_false", default=True, help="disable xmlrpc")
+
+ parser.add_option("-i", "--init", dest="init", help="init a module (use \"all\" for all modules)")
+ parser.add_option("--without-demo", dest="without_demo", help="load demo data for a module (use \"all\" for all modules)", default=False)
+ parser.add_option("-u", "--update", dest="update", help="update a module (use \"all\" for all modules)")
+ # 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("-S", "--secure", dest="secure", action="store_true", help="launch server over https instead of http", default=False)
+ parser.add_option('--smtp', dest='smtp_server', default='', help='specify the SMTP server for sending email')
+ parser.add_option('--smtp-user', dest='smtp_user', default='', help='specify the SMTP username for sending email')
+ parser.add_option('--smtp-password', dest='smtp_password', default='', help='specify the SMTP password for sending email')
+ parser.add_option('--price_accuracy', dest='price_accuracy', default='2', help='specify the price accuracy')
+
+ group = optparse.OptionGroup(parser, "Modules related options")
+ group.add_option("-g", "--upgrade", action="store_true", dest="upgrade", default=False, help="Upgrade/install/uninstall modules")
+
+ group = optparse.OptionGroup(parser, "Database related options")
+ group.add_option("-d", "--database", dest="db_name", help="specify the database name")
+ group.add_option("-r", "--db_user", dest="db_user", help="specify the database user name")
+ group.add_option("-w", "--db_password", dest="db_password", help="specify the database password")
+ group.add_option("--pg_path", dest="pg_path", help="specify the pg executable path")
+ group.add_option("--db_host", dest="db_host", help="specify the database host")
+ group.add_option("--db_port", dest="db_port", help="specify the database port")
+ group.add_option("--db_maxconn", dest="db_maxconn", default='64', help="specify the the maximum number of physical connections to posgresql")
+ group.add_option("-C", "--commit-mode", dest="commit_mode", action="store_true", help="Several commit during one file importation. Use this for big data importation.", default=False)
+ parser.add_option_group(group)
+
+ group = optparse.OptionGroup(parser, "Internationalisation options",
+ "Use these options to translate Tiny ERP to another language."
+ "See i18n section of the user manual. Options '-l' and '-d' are mandatory.")
+
+ group.add_option('-l', "--language", dest="language", help="specify the language of the translation file. Use it with --i18n-export and --i18n-import")
+ group.add_option("--i18n-export", dest="translate_out", help="export all sentences to be translated to a CSV or a PO file and exit")
+ group.add_option("--i18n-import", dest="translate_in", help="import a CSV or a PO file with translations and exit")
+ group.add_option("--modules", dest="translate_modules", help="specify modules to export. Use in combination with --i18n-export")
+ group.add_option("--addons-path", dest="addons_path", help="specify an alternative addons path.")
+ parser.add_option_group(group)
+
+ (opt, args) = parser.parse_args()
+
+ assert not ((opt.translate_in or opt.translate_out) and (not opt.language or not opt.db_name)), "the i18n-import and i18n-export options cannot be used without the language (-l) and database (-d) options"
+
+ # place/search the config file on Win32 near the server installation
+ # (../etc from the server)
+ # if the server is run by an unprivileged user, he has to specify location of a config file where he has the rights to write,
+ # else he won't be able to save the configurations, or even to start the server...
+ if os.name == 'nt':
+ rcfilepath = os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), 'tinyerp-server.conf')
+ else:
+ rcfilepath = os.path.expanduser('~/.terp_serverrc')
+
+ self.rcfile = fname or opt.config or os.environ.get('TERP_SERVER') or rcfilepath
+ self.load()
+
+
+ # Verify that we want to log or not, if not the output will go to stdout
+ if self.options['logfile'] in ('None', 'False'):
+ self.options['logfile'] = False
+ # the same for the pidfile
+ if self.options['pidfile'] in ('None', 'False'):
+ self.options['pidfile'] = False
+
+ for arg in ('interface', 'port', 'db_name', 'db_user', 'db_password', 'db_host',
+ 'db_port', 'logfile', 'pidfile', 'secure', 'smtp_server', 'smtp_user', 'smtp_password', 'price_accuracy', 'netinterface', 'netport', 'db_maxconn', 'commit_mode', 'addons_path'):
+ if getattr(opt, arg):
+ self.options[arg] = getattr(opt, arg)
+
+ for arg in ('language', 'translate_out', 'translate_in',
+ 'upgrade', 'verbose', 'debug_mode',
+ 'stop_after_init', 'without_demo', 'netrpc', 'xmlrpc'):
+ 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())
+
+ 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]))
+ if not self.options['addons_path'] or self.options['addons_path']=='None':
+ self.options['addons_path'] = os.path.join(self.options['root_path'], 'addons')
+
+ init = {}
+ if opt.init:
+ for i in opt.init.split(','):
+ init[i] = 1
+ self.options['init'] = init
+ self.options["demo"] = not opt.without_demo and self.options['init'] or {}
+
+ update = {}
+ if opt.update:
+ for i in opt.update.split(','):
+ update[i] = 1
+ self.options['update'] = update
+
+ self.options['translate_modules'] = opt.translate_modules and map(lambda m: m.strip(), opt.translate_modules.split(',')) or ['all']
+ self.options['translate_modules'].sort()
+
+ if opt.pg_path:
+ self.options['pg_path'] = opt.pg_path
+
+ if self.options.get('language', False):
+ assert len(self.options['language'])<=5, 'ERROR: The Lang name must take max 5 chars, Eg: -lfr_BE'
+ if opt.save:
+ self.save()
+
+ def load(self):
+ p = ConfigParser.ConfigParser()
+ try:
+ p.read([self.rcfile])
+ for (name,value) in p.items('options'):
+ if value=='True' or value=='true':
+ value = True
+ if value=='False' or value=='false':
+ value = False
+ self.options[name] = value
+ except IOError:
+ pass
+ except ConfigParser.NoSectionError:
+ pass
+
+ def save(self):
+ p = ConfigParser.ConfigParser()
+ p.add_section('options')
+ for o in [opt for opt in self.options.keys() if opt not in ('version','language','translate_out','translate_in','init','update')]:
+ p.set('options', o, self.options[o])
+
+ # try to create the directories and write the file
+ try:
+ if not os.path.exists(os.path.dirname(self.rcfile)):
+ os.makedirs(os.path.dirname(self.rcfile))
+ try:
+ p.write(file(self.rcfile, 'w'))
+ except IOError:
+ sys.stderr.write("ERROR: couldn't write the config file\n")
+
+ except OSError:
+ # what to do if impossible?
+ sys.stderr.write("ERROR: couldn't create the config directory\n")
+
+ def get(self, key, default=None):
+ return self.options.get(key, default)
+
+ def __setitem__(self, key, value):
+ self.options[key] = value
+
+ def __getitem__(self, key):
+ return self.options[key]
config = configmanager()
diff --git a/bin/tools/convert.py b/bin/tools/convert.py
index 0e3bb482019..3157505325f 100644
--- a/bin/tools/convert.py
+++ b/bin/tools/convert.py
@@ -44,737 +44,737 @@ from lxml import etree
class ConvertError(Exception):
- def __init__(self, doc, orig_excpt):
- self.d = doc
- self.orig = orig_excpt
+ def __init__(self, doc, orig_excpt):
+ self.d = doc
+ self.orig = orig_excpt
- def __str__(self):
- return 'Exception:\n\t%s\nUsing file:\n%s' % (self.orig, self.d)
+ def __str__(self):
+ return 'Exception:\n\t%s\nUsing file:\n%s' % (self.orig, self.d)
def _ref(self, cr):
- return lambda x: self.id_get(cr, False, x)
+ return lambda x: self.id_get(cr, False, x)
def _obj(pool, cr, uid, model_str, context=None):
- model = pool.get(model_str)
- return lambda x: model.browse(cr, uid, x, context=context)
+ model = pool.get(model_str)
+ return lambda x: model.browse(cr, uid, x, context=context)
def _eval_xml(self,node, pool, cr, uid, idref, context=None):
- if context is None:
- context = {}
- if node.nodeType == node.TEXT_NODE:
- return node.data.encode("utf8")
- elif node.nodeType == node.ELEMENT_NODE:
- if node.nodeName in ('field','value'):
- t = node.getAttribute('type') or 'char'
- f_model = node.getAttribute("model").encode('ascii')
- if len(node.getAttribute('search')):
- f_search = node.getAttribute("search").encode('utf-8')
- f_use = node.getAttribute("use").encode('ascii')
- f_name = node.getAttribute("name").encode('utf-8')
- if len(f_use)==0:
- f_use = "id"
- q = eval(f_search, idref)
- ids = pool.get(f_model).search(cr, uid, q)
- if f_use<>'id':
- ids = map(lambda x: x[f_use], pool.get(f_model).read(cr, uid, ids, [f_use]))
- _cols = pool.get(f_model)._columns
- if (f_name in _cols) and _cols[f_name]._type=='many2many':
- return ids
- f_val = False
- if len(ids):
- f_val = ids[0]
- if isinstance(f_val, tuple):
- f_val = f_val[0]
- return f_val
- a_eval = node.getAttribute('eval')
- if len(a_eval):
- import time
- idref['time'] = time
- import release
- idref['version'] = release.version.rsplit('.', 1)[0]
- idref['ref'] = lambda x: self.id_get(cr, False, x)
- if len(f_model):
- idref['obj'] = _obj(self.pool, cr, uid, f_model, context=context)
- try:
- import pytz
- except:
- logger = netsvc.Logger()
- logger.notifyChannel("init", netsvc.LOG_INFO, 'could not find pytz library')
- class pytzclass(object):
- all_timezones=[]
- pytz=pytzclass()
- idref['pytz'] = pytz
- return eval(a_eval, idref)
- if t == 'xml':
- def _process(s, idref):
- m = re.findall('[^%]%\((.*?)\)[ds]', s)
- for id in m:
- if not id in idref:
- idref[id]=self.id_get(cr, False, id)
- return s % idref
- txt = '<?xml version="1.0"?>\n'+_process("".join([i.toxml().encode("utf8") for i in node.childNodes]), idref)
-# txt = '<?xml version="1.0"?>\n'+"".join([i.toxml().encode("utf8") for i in node.childNodes]) % idref
-
- return txt
- if t in ('char', 'int', 'float'):
- d = ""
- for n in [i for i in node.childNodes]:
- d+=str(_eval_xml(self,n,pool,cr,uid,idref))
- if t == 'int':
- d = d.strip()
- if d=='None':
- return None
- else:
- d=int(d.strip())
- elif t=='float':
- d=float(d.strip())
- return d
- elif t in ('list','tuple'):
- res=[]
- for n in [i for i in node.childNodes if (i.nodeType == i.ELEMENT_NODE and i.nodeName=='value')]:
- res.append(_eval_xml(self,n,pool,cr,uid,idref))
- if t=='tuple':
- return tuple(res)
- return res
- elif node.nodeName=="getitem":
- for n in [i for i in node.childNodes if (i.nodeType == i.ELEMENT_NODE)]:
- res=_eval_xml(self,n,pool,cr,uid,idref)
- if not res:
- raise LookupError
- elif node.getAttribute('type') in ("int", "list"):
- return res[int(node.getAttribute('index'))]
- else:
- return res[node.getAttribute('index').encode("utf8")]
- elif node.nodeName=="function":
- args = []
- a_eval = node.getAttribute('eval')
- if len(a_eval):
- idref['ref'] = lambda x: self.id_get(cr, False, x)
- args = eval(a_eval, idref)
- for n in [i for i in node.childNodes if (i.nodeType == i.ELEMENT_NODE)]:
- args.append(_eval_xml(self,n, pool, cr, uid, idref, context))
- model = pool.get(node.getAttribute('model'))
- method = node.getAttribute('name')
- res = getattr(model, method)(cr, uid, *args)
- return res
- elif node.nodeName=="test":
- d = ""
- for n in [i for i in node.childNodes]:
- d+=str(_eval_xml(self,n,pool,cr,uid,idref, context=context))
- return d
+ if context is None:
+ context = {}
+ if node.nodeType == node.TEXT_NODE:
+ return node.data.encode("utf8")
+ elif node.nodeType == node.ELEMENT_NODE:
+ if node.nodeName in ('field','value'):
+ t = node.getAttribute('type') or 'char'
+ f_model = node.getAttribute("model").encode('ascii')
+ if len(node.getAttribute('search')):
+ f_search = node.getAttribute("search").encode('utf-8')
+ f_use = node.getAttribute("use").encode('ascii')
+ f_name = node.getAttribute("name").encode('utf-8')
+ if len(f_use)==0:
+ f_use = "id"
+ q = eval(f_search, idref)
+ ids = pool.get(f_model).search(cr, uid, q)
+ if f_use<>'id':
+ ids = map(lambda x: x[f_use], pool.get(f_model).read(cr, uid, ids, [f_use]))
+ _cols = pool.get(f_model)._columns
+ if (f_name in _cols) and _cols[f_name]._type=='many2many':
+ return ids
+ f_val = False
+ if len(ids):
+ f_val = ids[0]
+ if isinstance(f_val, tuple):
+ f_val = f_val[0]
+ return f_val
+ a_eval = node.getAttribute('eval')
+ if len(a_eval):
+ import time
+ idref['time'] = time
+ import release
+ idref['version'] = release.version.rsplit('.', 1)[0]
+ idref['ref'] = lambda x: self.id_get(cr, False, x)
+ if len(f_model):
+ idref['obj'] = _obj(self.pool, cr, uid, f_model, context=context)
+ try:
+ import pytz
+ except:
+ logger = netsvc.Logger()
+ logger.notifyChannel("init", netsvc.LOG_INFO, 'could not find pytz library')
+ class pytzclass(object):
+ all_timezones=[]
+ pytz=pytzclass()
+ idref['pytz'] = pytz
+ return eval(a_eval, idref)
+ if t == 'xml':
+ def _process(s, idref):
+ m = re.findall('[^%]%\((.*?)\)[ds]', s)
+ for id in m:
+ if not id in idref:
+ idref[id]=self.id_get(cr, False, id)
+ return s % idref
+ txt = '<?xml version="1.0"?>\n'+_process("".join([i.toxml().encode("utf8") for i in node.childNodes]), idref)
+# txt = '<?xml version="1.0"?>\n'+"".join([i.toxml().encode("utf8") for i in node.childNodes]) % idref
+
+ return txt
+ if t in ('char', 'int', 'float'):
+ d = ""
+ for n in [i for i in node.childNodes]:
+ d+=str(_eval_xml(self,n,pool,cr,uid,idref))
+ if t == 'int':
+ d = d.strip()
+ if d=='None':
+ return None
+ else:
+ d=int(d.strip())
+ elif t=='float':
+ d=float(d.strip())
+ return d
+ elif t in ('list','tuple'):
+ res=[]
+ for n in [i for i in node.childNodes if (i.nodeType == i.ELEMENT_NODE and i.nodeName=='value')]:
+ res.append(_eval_xml(self,n,pool,cr,uid,idref))
+ if t=='tuple':
+ return tuple(res)
+ return res
+ elif node.nodeName=="getitem":
+ for n in [i for i in node.childNodes if (i.nodeType == i.ELEMENT_NODE)]:
+ res=_eval_xml(self,n,pool,cr,uid,idref)
+ if not res:
+ raise LookupError
+ elif node.getAttribute('type') in ("int", "list"):
+ return res[int(node.getAttribute('index'))]
+ else:
+ return res[node.getAttribute('index').encode("utf8")]
+ elif node.nodeName=="function":
+ args = []
+ a_eval = node.getAttribute('eval')
+ if len(a_eval):
+ idref['ref'] = lambda x: self.id_get(cr, False, x)
+ args = eval(a_eval, idref)
+ for n in [i for i in node.childNodes if (i.nodeType == i.ELEMENT_NODE)]:
+ args.append(_eval_xml(self,n, pool, cr, uid, idref, context))
+ model = pool.get(node.getAttribute('model'))
+ method = node.getAttribute('name')
+ res = getattr(model, method)(cr, uid, *args)
+ return res
+ elif node.nodeName=="test":
+ d = ""
+ for n in [i for i in node.childNodes]:
+ d+=str(_eval_xml(self,n,pool,cr,uid,idref, context=context))
+ return d
escape_re = re.compile(r'(?<!\\)/')
def escape(x):
- return x.replace('\\/', '/')
+ return x.replace('\\/', '/')
class assertion_report(object):
- def __init__(self):
- self._report = {}
-
- def record_assertion(self, success, severity):
- """
- Records the result of an assertion for the failed/success count
- retrurns success
- """
- if severity in self._report:
- self._report[severity][success] += 1
- else:
- self._report[severity] = {success:1, not success: 0}
- return success
-
- def get_report(self):
- return self._report
-
- def __str__(self):
- res = '\nAssertions report:\nLevel\tsuccess\tfailed\n'
- success = failed = 0
- for sev in self._report:
- res += sev + '\t' + str(self._report[sev][True]) + '\t' + str(self._report[sev][False]) + '\n'
- success += self._report[sev][True]
- failed += self._report[sev][False]
- res += 'total\t' + str(success) + '\t' + str(failed) + '\n'
- res += 'end of report (' + str(success + failed) + ' assertion(s) checked)'
- return res
+ def __init__(self):
+ self._report = {}
+
+ def record_assertion(self, success, severity):
+ """
+ Records the result of an assertion for the failed/success count
+ retrurns success
+ """
+ if severity in self._report:
+ self._report[severity][success] += 1
+ else:
+ self._report[severity] = {success:1, not success: 0}
+ return success
+
+ def get_report(self):
+ return self._report
+
+ def __str__(self):
+ res = '\nAssertions report:\nLevel\tsuccess\tfailed\n'
+ success = failed = 0
+ for sev in self._report:
+ res += sev + '\t' + str(self._report[sev][True]) + '\t' + str(self._report[sev][False]) + '\n'
+ success += self._report[sev][True]
+ failed += self._report[sev][False]
+ res += 'total\t' + str(success) + '\t' + str(failed) + '\n'
+ res += 'end of report (' + str(success + failed) + ' assertion(s) checked)'
+ return res
class xml_import(object):
- def isnoupdate(self, data_node = None):
- return self.noupdate or (data_node and data_node.getAttribute('noupdate'))
+ def isnoupdate(self, data_node = None):
+ return self.noupdate or (data_node and data_node.getAttribute('noupdate'))
- def get_context(self, data_node, node, eval_dict):
- data_node_context = (data_node and data_node.getAttribute('context').encode('utf8'))
- if data_node_context:
- context = eval(data_node_context, eval_dict)
- else:
- context = {}
+ def get_context(self, data_node, node, eval_dict):
+ data_node_context = (data_node and data_node.getAttribute('context').encode('utf8'))
+ if data_node_context:
+ context = eval(data_node_context, eval_dict)
+ else:
+ context = {}
- node_context = node.getAttribute("context").encode('utf8')
- if len(node_context):
- context.update(eval(node_context, eval_dict))
+ node_context = node.getAttribute("context").encode('utf8')
+ if len(node_context):
+ context.update(eval(node_context, eval_dict))
- return context
+ return context
- def get_uid(self, cr, uid, data_node, node):
- node_uid = node.getAttribute('uid') or (data_node and data_node.getAttribute('uid'))
- if len(node_uid):
- return self.id_get(cr, None, node_uid)
- return uid
+ def get_uid(self, cr, uid, data_node, node):
+ node_uid = node.getAttribute('uid') or (data_node and data_node.getAttribute('uid'))
+ if len(node_uid):
+ return self.id_get(cr, None, node_uid)
+ return uid
- def _test_xml_id(self, xml_id):
- id = xml_id
- if '.' in xml_id:
- assert len(id.split('.'))==2, """The ID reference '"%s" must contains
+ def _test_xml_id(self, xml_id):
+ id = xml_id
+ if '.' in xml_id:
+ assert len(id.split('.'))==2, """The ID reference '"%s" must contains
maximum one dot. They are used to refer to other modules ID, in the
form: module.record_id""" % (xml_id,)
- base, id = xml_id.split('.')
- if len(id) > 64:
- self.logger.notifyChannel('init', netsvc.LOG_ERROR, 'id: %s is to long (max: 64)'%xml_id)
-
- def _tag_delete(self, cr, rec, data_node=None):
- d_model = rec.getAttribute("model")
- d_search = rec.getAttribute("search")
- d_id = rec.getAttribute("id")
- ids = []
- if len(d_search):
- ids = self.pool.get(d_model).search(cr,self.uid,eval(d_search))
- if len(d_id):
- ids.append(self.id_get(cr, d_model, d_id))
- if len(ids):
- self.pool.get(d_model).unlink(cr, self.uid, ids)
- #self.pool.get('ir.model.data')._unlink(cr, self.uid, d_model, ids, direct=True)
- return False
-
- def _tag_report(self, cr, rec, data_node=None):
- res = {}
- for dest,f in (('name','string'),('model','model'),('report_name','name')):
- res[dest] = rec.getAttribute(f).encode('utf8')
- assert res[dest], "Attribute %s of report is empty !" % (f,)
- for field,dest in (('rml','report_rml'),('xml','report_xml'),('xsl','report_xsl')):
- if rec.hasAttribute(field):
- res[dest] = rec.getAttribute(field).encode('utf8')
- if rec.hasAttribute('auto'):
- res['auto'] = eval(rec.getAttribute('auto'))
- if rec.hasAttribute('sxw'):
- sxw_content = misc.file_open(rec.getAttribute('sxw')).read()
- res['report_sxw_content'] = sxw_content
- if rec.hasAttribute('header'):
- res['header'] = eval(rec.getAttribute('header'))
- res['multi'] = rec.hasAttribute('multi') and eval(rec.getAttribute('multi'))
- xml_id = rec.getAttribute('id').encode('utf8')
- self._test_xml_id(xml_id)
- id = self.pool.get('ir.model.data')._update(cr, self.uid, "ir.actions.report.xml", self.module, res, xml_id, mode=self.mode)
- self.idref[xml_id] = int(id)
- if not rec.hasAttribute('menu') or eval(rec.getAttribute('menu')):
- keyword = str(rec.getAttribute('keyword') or 'client_print_multi')
- keys = [('action',keyword),('res_model',res['model'])]
- value = 'ir.actions.report.xml,'+str(id)
- replace = rec.hasAttribute('replace') and rec.getAttribute("replace")
- self.pool.get('ir.model.data').ir_set(cr, self.uid, 'action', keyword, res['name'], [res['model']], value, replace=replace, isobject=True, xml_id=xml_id)
- return False
-
- def _tag_function(self, cr, rec, data_node=None):
- if self.isnoupdate(data_node) and self.mode != 'init':
- return
- context = self.get_context(data_node, rec, {'ref': _ref(self, cr)})
- uid = self.get_uid(cr, self.uid, data_node, rec)
- _eval_xml(self,rec, self.pool, cr, uid, self.idref, context=context)
- return False
-
- def _tag_wizard(self, cr, rec, data_node=None):
- string = rec.getAttribute("string").encode('utf8')
- model = rec.getAttribute("model").encode('utf8')
- name = rec.getAttribute("name").encode('utf8')
- xml_id = rec.getAttribute('id').encode('utf8')
- self._test_xml_id(xml_id)
- multi = rec.hasAttribute('multi') and eval(rec.getAttribute('multi'))
- res = {'name': string, 'wiz_name': name, 'multi':multi}
-
- id = self.pool.get('ir.model.data')._update(cr, self.uid, "ir.actions.wizard", self.module, res, xml_id, mode=self.mode)
- self.idref[xml_id] = int(id)
- # ir_set
- if (not rec.hasAttribute('menu') or eval(rec.getAttribute('menu'))) and id:
- keyword = str(rec.getAttribute('keyword') or 'client_action_multi')
- keys = [('action',keyword),('res_model',model)]
- value = 'ir.actions.wizard,'+str(id)
- replace = rec.hasAttribute('replace') and \
- rec.getAttribute("replace") or True
- self.pool.get('ir.model.data').ir_set(cr, self.uid, 'action', keyword, string, [model], value, replace=replace, isobject=True, xml_id=xml_id)
- return False
-
- def _tag_url(self, cr, rec, data_node=None):
- url = rec.getAttribute("string").encode('utf8')
- target = rec.getAttribute("target").encode('utf8')
- name = rec.getAttribute("name").encode('utf8')
- xml_id = rec.getAttribute('id').encode('utf8')
- self._test_xml_id(xml_id)
-
- res = {'name': name, 'url': url, 'target':target}
-
- id = self.pool.get('ir.model.data')._update(cr, self.uid, "ir.actions.url", self.module, res, xml_id, mode=self.mode)
- self.idref[xml_id] = int(id)
- # ir_set
- if (not rec.hasAttribute('menu') or eval(rec.getAttribute('menu'))) and id:
- keyword = str(rec.getAttribute('keyword') or 'client_action_multi')
- keys = [('action',keyword)]
- value = 'ir.actions.url,'+str(id)
- replace = rec.hasAttribute('replace') and \
- rec.getAttribute("replace") or True
- self.pool.get('ir.model.data').ir_set(cr, self.uid, 'action', keyword, url, ["ir.actions.url"], value, replace=replace, isobject=True, xml_id=xml_id)
- return False
-
- def _tag_act_window(self, cr, rec, data_node=None):
- name = rec.hasAttribute('name') and rec.getAttribute('name').encode('utf-8')
- xml_id = rec.getAttribute('id').encode('utf8')
- self._test_xml_id(xml_id)
- type = rec.hasAttribute('type') and rec.getAttribute('type').encode('utf-8') or 'ir.actions.act_window'
- view_id = False
- if rec.hasAttribute('view'):
- view_id = self.id_get(cr, 'ir.actions.act_window', rec.getAttribute('view').encode('utf-8'))
- domain = rec.hasAttribute('domain') and rec.getAttribute('domain').encode('utf-8')
- context = rec.hasAttribute('context') and rec.getAttribute('context').encode('utf-8') or '{}'
- res_model = rec.getAttribute('res_model').encode('utf-8')
- src_model = rec.hasAttribute('src_model') and rec.getAttribute('src_model').encode('utf-8')
- view_type = rec.hasAttribute('view_type') and rec.getAttribute('view_type').encode('utf-8') or 'form'
- view_mode = rec.hasAttribute('view_mode') and rec.getAttribute('view_mode').encode('utf-8') or 'tree,form'
- usage = rec.hasAttribute('usage') and rec.getAttribute('usage').encode('utf-8')
- limit = rec.hasAttribute('limit') and rec.getAttribute('limit').encode('utf-8')
- auto_refresh = rec.hasAttribute('auto_refresh') \
- and rec.getAttribute('auto_refresh').encode('utf-8')
-
- res = {
- 'name': name,
- 'type': type,
- 'view_id': view_id,
- 'domain': domain,
- 'context': context,
- 'res_model': res_model,
- 'src_model': src_model,
- 'view_type': view_type,
- 'view_mode': view_mode,
- 'usage': usage,
- 'limit': limit,
- 'auto_refresh': auto_refresh,
- }
- if rec.hasAttribute('target'):
- res['target'] = rec.getAttribute('target')
- id = self.pool.get('ir.model.data')._update(cr, self.uid, 'ir.actions.act_window', self.module, res, xml_id, mode=self.mode)
- self.idref[xml_id] = int(id)
-
- if src_model:
- keyword = 'client_action_relate'
- keys = [('action', keyword), ('res_model', res_model)]
- value = 'ir.actions.act_window,'+str(id)
- replace = rec.hasAttribute('replace') and rec.getAttribute('replace')
- self.pool.get('ir.model.data').ir_set(cr, self.uid, 'action', keyword, xml_id, [src_model], value, replace=replace, isobject=True, xml_id=xml_id)
- # TODO add remove ir.model.data
- return False
-
- def _tag_ir_set(self, cr, rec, data_node=None):
- if not self.mode=='init':
- return False
- res = {}
- for field in [i for i in rec.childNodes if (i.nodeType == i.ELEMENT_NODE and i.nodeName=="field")]:
- f_name = field.getAttribute("name").encode('utf-8')
- f_val = _eval_xml(self,field,self.pool, cr, self.uid, self.idref)
- res[f_name] = f_val
- self.pool.get('ir.model.data').ir_set(cr, self.uid, res['key'], res['key2'], res['name'], res['models'], res['value'], replace=res.get('replace',True), isobject=res.get('isobject', False), meta=res.get('meta',None))
- return False
-
- def _tag_workflow(self, cr, rec, data_node=None):
- if self.isnoupdate(data_node) and self.mode != 'init':
- return
- model = str(rec.getAttribute('model'))
- w_ref = rec.getAttribute('ref')
- if len(w_ref):
- id = self.id_get(cr, model, w_ref)
- else:
- assert rec.childNodes, 'You must define a child node if you dont give a ref'
- element_childs = [i for i in rec.childNodes if i.nodeType == i.ELEMENT_NODE]
- assert len(element_childs) == 1, 'Only one child node is accepted (%d given)' % len(rec.childNodes)
- id = _eval_xml(self, element_childs[0], self.pool, cr, self.uid, self.idref)
-
- uid = self.get_uid(cr, self.uid, data_node, rec)
- wf_service = netsvc.LocalService("workflow")
- wf_service.trg_validate(uid, model,
- id,
- str(rec.getAttribute('action')), cr)
- return False
-
- #
- # Support two types of notation:
- # name="Inventory Control/Sending Goods"
- # or
- # action="action_id"
- # parent="parent_id"
- #
- def _tag_menuitem(self, cr, rec, data_node=None):
- rec_id = rec.getAttribute("id").encode('ascii')
- self._test_xml_id(rec_id)
- m_l = map(escape, escape_re.split(rec.getAttribute("name").encode('utf8')))
-
- values = {'parent_id': False}
- if not rec.hasAttribute('parent'):
- 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))
- else:
- cr.execute('select id from ir_ui_menu where parent_id is null and name=%s', (menu_elem,))
- res = cr.fetchone()
- if idx==len(m_l)-1:
- values = {'parent_id': pid,'name':menu_elem}
- elif res:
- pid = res[0]
- xml_id = idx==len(m_l)-1 and rec.getAttribute('id').encode('utf8')
- 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
- else:
- # the menuitem does't exist but we are in branch (not a leaf)
- self.logger.notifyChannel("init", netsvc.LOG_INFO, 'Warning no ID for submenu %s of menu %s !' % (menu_elem, str(m_l)))
- pid = self.pool.get('ir.ui.menu').create(cr, self.uid, {'parent_id' : pid, 'name' : menu_elem})
- else:
- menu_parent_id = self.id_get(cr, 'ir.ui.menu', rec.getAttribute('parent'))
- values = {'parent_id': menu_parent_id}
- if rec.hasAttribute('name'):
- values['name'] = rec.getAttribute('name')
- try:
- res = [ self.id_get(cr, 'ir.ui.menu', rec.getAttribute('id')) ]
- except:
- res = None
-
- if rec.hasAttribute('action'):
- a_action = rec.getAttribute('action').encode('utf8')
- a_type = rec.getAttribute('type').encode('utf8') or 'act_window'
- icons = {
- "act_window": 'STOCK_NEW',
- "report.xml": 'STOCK_PASTE',
- "wizard": 'STOCK_EXECUTE',
- "url": 'STOCK_JUMP_TO'
- }
- 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),))
- action_type,action_mode,action_name,view_id,target = cr.fetchone()
- if view_id:
- cr.execute('SELECT type FROM ir_ui_view WHERE id=%d', (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),))
- if cr.rowcount:
- action_mode, = cr.fetchone()
- if action_type=='tree':
- values['icon'] = 'STOCK_INDENT'
- elif action_mode and action_mode.startswith('tree'):
- values['icon'] = 'STOCK_JUSTIFY_FILL'
- elif action_mode and action_mode.startswith('graph'):
- values['icon'] = 'terp-graph'
- elif action_mode and action_mode.startswith('calendar'):
- values['icon'] = 'terp-calendar'
- if target=='new':
- values['icon'] = 'STOCK_EXECUTE'
- if not values.get('name', False):
- 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),))
- resw = cr.fetchone()
- if (not values.get('name', False)) and resw:
- values['name'] = resw[0]
- if rec.hasAttribute('sequence'):
- values['sequence'] = int(rec.getAttribute('sequence'))
- if rec.hasAttribute('icon'):
- values['icon'] = str(rec.getAttribute('icon'))
- if rec.hasAttribute('groups'):
- g_names = rec.getAttribute('groups').split(',')
- groups_value = []
- groups_obj = self.pool.get('res.groups')
- for group in g_names:
- if group.startswith('-'):
- group_id = self.id_get(cr, 'res.groups', group[1:])
- groups_value.append((3, group_id))
- else:
- group_id = self.id_get(cr, 'res.groups', group)
- groups_value.append((4, group_id))
- values['groups_id'] = groups_value
-
- xml_id = rec.getAttribute('id').encode('utf8')
- self._test_xml_id(xml_id)
- pid = self.pool.get('ir.model.data')._update(cr, self.uid, 'ir.ui.menu', self.module, values, xml_id, True, mode=self.mode, res_id=res and res[0] or False)
-
- if rec_id and pid:
- self.idref[rec_id] = int(pid)
-
- if rec.hasAttribute('action') and pid:
- a_action = rec.getAttribute('action').encode('utf8')
- a_type = rec.getAttribute('type').encode('utf8') or 'act_window'
- a_id = self.id_get(cr, 'ir.actions.%s' % a_type, a_action)
- action = "ir.actions.%s,%d" % (a_type, a_id)
- self.pool.get('ir.model.data').ir_set(cr, self.uid, 'action', 'tree_but_open', 'Menuitem', [('ir.ui.menu', int(pid))], action, True, True, xml_id=rec_id)
- return ('ir.ui.menu', pid)
-
- def _assert_equals(self, f1, f2, prec = 4):
- return not round(f1 - f2, prec)
-
- def _tag_assert(self, cr, rec, data_node=None):
- if self.isnoupdate(data_node) and self.mode != 'init':
- return
-
- rec_model = rec.getAttribute("model").encode('ascii')
- model = self.pool.get(rec_model)
- assert model, "The model %s does not exist !" % (rec_model,)
- rec_id = rec.getAttribute("id").encode('ascii')
- self._test_xml_id(rec_id)
- rec_src = rec.getAttribute("search").encode('utf8')
- rec_src_count = rec.getAttribute("count")
-
- severity = rec.getAttribute("severity").encode('ascii') or 'info'
-
- rec_string = rec.getAttribute("string").encode('utf8') or 'unknown'
-
- ids = None
- eval_dict = {'ref': _ref(self, cr)}
- context = self.get_context(data_node, rec, eval_dict)
- uid = self.get_uid(cr, self.uid, data_node, rec)
- if len(rec_id):
- ids = [self.id_get(cr, rec_model, rec_id)]
- elif len(rec_src):
- q = eval(rec_src, eval_dict)
- ids = self.pool.get(rec_model).search(cr, uid, q, context=context)
- if len(rec_src_count):
- count = int(rec_src_count)
- if len(ids) != count:
- self.assert_report.record_assertion(False, severity)
- self.logger.notifyChannel('init', severity, 'assertion "' + rec_string + '" failed ! (search count is incorrect: ' + str(len(ids)) + ')' )
- sevval = getattr(logging, severity.upper())
- if sevval > config['assert_exit_level']:
- # TODO: define a dedicated exception
- raise Exception('Severe assertion failure')
- return
-
- assert ids != None, 'You must give either an id or a search criteria'
-
- ref = _ref(self, cr)
- for id in ids:
- brrec = model.browse(cr, uid, id, context)
- class d(dict):
- def __getitem__(self2, key):
- if key in brrec:
- return brrec[key]
- return dict.__getitem__(self2, key)
- globals = d()
- globals['floatEqual'] = self._assert_equals
- globals['ref'] = ref
- globals['_ref'] = ref
- for test in [i for i in rec.childNodes if (i.nodeType == i.ELEMENT_NODE and i.nodeName=="test")]:
- f_expr = test.getAttribute("expr").encode('utf-8')
- f_val = _eval_xml(self, test, self.pool, cr, uid, self.idref, context=context) or True
- if eval(f_expr, globals) != f_val: # assertion failed
- self.assert_report.record_assertion(False, severity)
- self.logger.notifyChannel('init', severity, 'assertion "' + rec_string + '" failed ! (tag ' + test.toxml() + ')' )
- sevval = getattr(logging, severity.upper())
- if sevval > config['assert_exit_level']:
- # TODO: define a dedicated exception
- raise Exception('Severe assertion failure')
- return
- else: # all tests were successful for this assertion tag (no break)
- self.assert_report.record_assertion(True, severity)
-
- def _tag_record(self, cr, rec, data_node=None):
- rec_model = rec.getAttribute("model").encode('ascii')
- model = self.pool.get(rec_model)
- assert model, "The model %s does not exist !" % (rec_model,)
- rec_id = rec.getAttribute("id").encode('ascii')
- self._test_xml_id(rec_id)
-
-# if not rec_id and not self.isnoupdate(data_node):
-# print "Warning", rec_model
-
- if self.isnoupdate(data_node) and not self.mode == 'init':
- # check if the xml record has an id string
- if rec_id:
- id = self.pool.get('ir.model.data')._update_dummy(cr, self.uid, rec_model, self.module, rec_id)
- # check if the resource already existed at the last update
- if id:
- # if it existed, we don't update the data, but we need to
- # know the id of the existing record anyway
- self.idref[rec_id] = int(id)
- return None
- else:
- # if the resource didn't exist
- if rec.getAttribute("forcecreate"):
- # we want to create it, so we let the normal "update" behavior happen
- pass
- else:
- # otherwise do nothing
- return None
- else:
- # otherwise it is skipped
- return None
-
- res = {}
- for field in [i for i in rec.childNodes if (i.nodeType == i.ELEMENT_NODE and i.nodeName=="field")]:
+ base, id = xml_id.split('.')
+ if len(id) > 64:
+ self.logger.notifyChannel('init', netsvc.LOG_ERROR, 'id: %s is to long (max: 64)'%xml_id)
+
+ def _tag_delete(self, cr, rec, data_node=None):
+ d_model = rec.getAttribute("model")
+ d_search = rec.getAttribute("search")
+ d_id = rec.getAttribute("id")
+ ids = []
+ if len(d_search):
+ ids = self.pool.get(d_model).search(cr,self.uid,eval(d_search))
+ if len(d_id):
+ ids.append(self.id_get(cr, d_model, d_id))
+ if len(ids):
+ self.pool.get(d_model).unlink(cr, self.uid, ids)
+ #self.pool.get('ir.model.data')._unlink(cr, self.uid, d_model, ids, direct=True)
+ return False
+
+ def _tag_report(self, cr, rec, data_node=None):
+ res = {}
+ for dest,f in (('name','string'),('model','model'),('report_name','name')):
+ res[dest] = rec.getAttribute(f).encode('utf8')
+ assert res[dest], "Attribute %s of report is empty !" % (f,)
+ for field,dest in (('rml','report_rml'),('xml','report_xml'),('xsl','report_xsl')):
+ if rec.hasAttribute(field):
+ res[dest] = rec.getAttribute(field).encode('utf8')
+ if rec.hasAttribute('auto'):
+ res['auto'] = eval(rec.getAttribute('auto'))
+ if rec.hasAttribute('sxw'):
+ sxw_content = misc.file_open(rec.getAttribute('sxw')).read()
+ res['report_sxw_content'] = sxw_content
+ if rec.hasAttribute('header'):
+ res['header'] = eval(rec.getAttribute('header'))
+ res['multi'] = rec.hasAttribute('multi') and eval(rec.getAttribute('multi'))
+ xml_id = rec.getAttribute('id').encode('utf8')
+ self._test_xml_id(xml_id)
+ id = self.pool.get('ir.model.data')._update(cr, self.uid, "ir.actions.report.xml", self.module, res, xml_id, mode=self.mode)
+ self.idref[xml_id] = int(id)
+ if not rec.hasAttribute('menu') or eval(rec.getAttribute('menu')):
+ keyword = str(rec.getAttribute('keyword') or 'client_print_multi')
+ keys = [('action',keyword),('res_model',res['model'])]
+ value = 'ir.actions.report.xml,'+str(id)
+ replace = rec.hasAttribute('replace') and rec.getAttribute("replace")
+ self.pool.get('ir.model.data').ir_set(cr, self.uid, 'action', keyword, res['name'], [res['model']], value, replace=replace, isobject=True, xml_id=xml_id)
+ return False
+
+ def _tag_function(self, cr, rec, data_node=None):
+ if self.isnoupdate(data_node) and self.mode != 'init':
+ return
+ context = self.get_context(data_node, rec, {'ref': _ref(self, cr)})
+ uid = self.get_uid(cr, self.uid, data_node, rec)
+ _eval_xml(self,rec, self.pool, cr, uid, self.idref, context=context)
+ return False
+
+ def _tag_wizard(self, cr, rec, data_node=None):
+ string = rec.getAttribute("string").encode('utf8')
+ model = rec.getAttribute("model").encode('utf8')
+ name = rec.getAttribute("name").encode('utf8')
+ xml_id = rec.getAttribute('id').encode('utf8')
+ self._test_xml_id(xml_id)
+ multi = rec.hasAttribute('multi') and eval(rec.getAttribute('multi'))
+ res = {'name': string, 'wiz_name': name, 'multi':multi}
+
+ id = self.pool.get('ir.model.data')._update(cr, self.uid, "ir.actions.wizard", self.module, res, xml_id, mode=self.mode)
+ self.idref[xml_id] = int(id)
+ # ir_set
+ if (not rec.hasAttribute('menu') or eval(rec.getAttribute('menu'))) and id:
+ keyword = str(rec.getAttribute('keyword') or 'client_action_multi')
+ keys = [('action',keyword),('res_model',model)]
+ value = 'ir.actions.wizard,'+str(id)
+ replace = rec.hasAttribute('replace') and \
+ rec.getAttribute("replace") or True
+ self.pool.get('ir.model.data').ir_set(cr, self.uid, 'action', keyword, string, [model], value, replace=replace, isobject=True, xml_id=xml_id)
+ return False
+
+ def _tag_url(self, cr, rec, data_node=None):
+ url = rec.getAttribute("string").encode('utf8')
+ target = rec.getAttribute("target").encode('utf8')
+ name = rec.getAttribute("name").encode('utf8')
+ xml_id = rec.getAttribute('id').encode('utf8')
+ self._test_xml_id(xml_id)
+
+ res = {'name': name, 'url': url, 'target':target}
+
+ id = self.pool.get('ir.model.data')._update(cr, self.uid, "ir.actions.url", self.module, res, xml_id, mode=self.mode)
+ self.idref[xml_id] = int(id)
+ # ir_set
+ if (not rec.hasAttribute('menu') or eval(rec.getAttribute('menu'))) and id:
+ keyword = str(rec.getAttribute('keyword') or 'client_action_multi')
+ keys = [('action',keyword)]
+ value = 'ir.actions.url,'+str(id)
+ replace = rec.hasAttribute('replace') and \
+ rec.getAttribute("replace") or True
+ self.pool.get('ir.model.data').ir_set(cr, self.uid, 'action', keyword, url, ["ir.actions.url"], value, replace=replace, isobject=True, xml_id=xml_id)
+ return False
+
+ def _tag_act_window(self, cr, rec, data_node=None):
+ name = rec.hasAttribute('name') and rec.getAttribute('name').encode('utf-8')
+ xml_id = rec.getAttribute('id').encode('utf8')
+ self._test_xml_id(xml_id)
+ type = rec.hasAttribute('type') and rec.getAttribute('type').encode('utf-8') or 'ir.actions.act_window'
+ view_id = False
+ if rec.hasAttribute('view'):
+ view_id = self.id_get(cr, 'ir.actions.act_window', rec.getAttribute('view').encode('utf-8'))
+ domain = rec.hasAttribute('domain') and rec.getAttribute('domain').encode('utf-8')
+ context = rec.hasAttribute('context') and rec.getAttribute('context').encode('utf-8') or '{}'
+ res_model = rec.getAttribute('res_model').encode('utf-8')
+ src_model = rec.hasAttribute('src_model') and rec.getAttribute('src_model').encode('utf-8')
+ view_type = rec.hasAttribute('view_type') and rec.getAttribute('view_type').encode('utf-8') or 'form'
+ view_mode = rec.hasAttribute('view_mode') and rec.getAttribute('view_mode').encode('utf-8') or 'tree,form'
+ usage = rec.hasAttribute('usage') and rec.getAttribute('usage').encode('utf-8')
+ limit = rec.hasAttribute('limit') and rec.getAttribute('limit').encode('utf-8')
+ auto_refresh = rec.hasAttribute('auto_refresh') \
+ and rec.getAttribute('auto_refresh').encode('utf-8')
+
+ res = {
+ 'name': name,
+ 'type': type,
+ 'view_id': view_id,
+ 'domain': domain,
+ 'context': context,
+ 'res_model': res_model,
+ 'src_model': src_model,
+ 'view_type': view_type,
+ 'view_mode': view_mode,
+ 'usage': usage,
+ 'limit': limit,
+ 'auto_refresh': auto_refresh,
+ }
+ if rec.hasAttribute('target'):
+ res['target'] = rec.getAttribute('target')
+ id = self.pool.get('ir.model.data')._update(cr, self.uid, 'ir.actions.act_window', self.module, res, xml_id, mode=self.mode)
+ self.idref[xml_id] = int(id)
+
+ if src_model:
+ keyword = 'client_action_relate'
+ keys = [('action', keyword), ('res_model', res_model)]
+ value = 'ir.actions.act_window,'+str(id)
+ replace = rec.hasAttribute('replace') and rec.getAttribute('replace')
+ self.pool.get('ir.model.data').ir_set(cr, self.uid, 'action', keyword, xml_id, [src_model], value, replace=replace, isobject=True, xml_id=xml_id)
+ # TODO add remove ir.model.data
+ return False
+
+ def _tag_ir_set(self, cr, rec, data_node=None):
+ if not self.mode=='init':
+ return False
+ res = {}
+ for field in [i for i in rec.childNodes if (i.nodeType == i.ELEMENT_NODE and i.nodeName=="field")]:
+ f_name = field.getAttribute("name").encode('utf-8')
+ f_val = _eval_xml(self,field,self.pool, cr, self.uid, self.idref)
+ res[f_name] = f_val
+ self.pool.get('ir.model.data').ir_set(cr, self.uid, res['key'], res['key2'], res['name'], res['models'], res['value'], replace=res.get('replace',True), isobject=res.get('isobject', False), meta=res.get('meta',None))
+ return False
+
+ def _tag_workflow(self, cr, rec, data_node=None):
+ if self.isnoupdate(data_node) and self.mode != 'init':
+ return
+ model = str(rec.getAttribute('model'))
+ w_ref = rec.getAttribute('ref')
+ if len(w_ref):
+ id = self.id_get(cr, model, w_ref)
+ else:
+ assert rec.childNodes, 'You must define a child node if you dont give a ref'
+ element_childs = [i for i in rec.childNodes if i.nodeType == i.ELEMENT_NODE]
+ assert len(element_childs) == 1, 'Only one child node is accepted (%d given)' % len(rec.childNodes)
+ id = _eval_xml(self, element_childs[0], self.pool, cr, self.uid, self.idref)
+
+ uid = self.get_uid(cr, self.uid, data_node, rec)
+ wf_service = netsvc.LocalService("workflow")
+ wf_service.trg_validate(uid, model,
+ id,
+ str(rec.getAttribute('action')), cr)
+ return False
+
+ #
+ # Support two types of notation:
+ # name="Inventory Control/Sending Goods"
+ # or
+ # action="action_id"
+ # parent="parent_id"
+ #
+ def _tag_menuitem(self, cr, rec, data_node=None):
+ rec_id = rec.getAttribute("id").encode('ascii')
+ self._test_xml_id(rec_id)
+ m_l = map(escape, escape_re.split(rec.getAttribute("name").encode('utf8')))
+
+ values = {'parent_id': False}
+ if not rec.hasAttribute('parent'):
+ 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))
+ else:
+ cr.execute('select id from ir_ui_menu where parent_id is null and name=%s', (menu_elem,))
+ res = cr.fetchone()
+ if idx==len(m_l)-1:
+ values = {'parent_id': pid,'name':menu_elem}
+ elif res:
+ pid = res[0]
+ xml_id = idx==len(m_l)-1 and rec.getAttribute('id').encode('utf8')
+ 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
+ else:
+ # the menuitem does't exist but we are in branch (not a leaf)
+ self.logger.notifyChannel("init", netsvc.LOG_INFO, 'Warning no ID for submenu %s of menu %s !' % (menu_elem, str(m_l)))
+ pid = self.pool.get('ir.ui.menu').create(cr, self.uid, {'parent_id' : pid, 'name' : menu_elem})
+ else:
+ menu_parent_id = self.id_get(cr, 'ir.ui.menu', rec.getAttribute('parent'))
+ values = {'parent_id': menu_parent_id}
+ if rec.hasAttribute('name'):
+ values['name'] = rec.getAttribute('name')
+ try:
+ res = [ self.id_get(cr, 'ir.ui.menu', rec.getAttribute('id')) ]
+ except:
+ res = None
+
+ if rec.hasAttribute('action'):
+ a_action = rec.getAttribute('action').encode('utf8')
+ a_type = rec.getAttribute('type').encode('utf8') or 'act_window'
+ icons = {
+ "act_window": 'STOCK_NEW',
+ "report.xml": 'STOCK_PASTE',
+ "wizard": 'STOCK_EXECUTE',
+ "url": 'STOCK_JUMP_TO'
+ }
+ 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),))
+ action_type,action_mode,action_name,view_id,target = cr.fetchone()
+ if view_id:
+ cr.execute('SELECT type FROM ir_ui_view WHERE id=%d', (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),))
+ if cr.rowcount:
+ action_mode, = cr.fetchone()
+ if action_type=='tree':
+ values['icon'] = 'STOCK_INDENT'
+ elif action_mode and action_mode.startswith('tree'):
+ values['icon'] = 'STOCK_JUSTIFY_FILL'
+ elif action_mode and action_mode.startswith('graph'):
+ values['icon'] = 'terp-graph'
+ elif action_mode and action_mode.startswith('calendar'):
+ values['icon'] = 'terp-calendar'
+ if target=='new':
+ values['icon'] = 'STOCK_EXECUTE'
+ if not values.get('name', False):
+ 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),))
+ resw = cr.fetchone()
+ if (not values.get('name', False)) and resw:
+ values['name'] = resw[0]
+ if rec.hasAttribute('sequence'):
+ values['sequence'] = int(rec.getAttribute('sequence'))
+ if rec.hasAttribute('icon'):
+ values['icon'] = str(rec.getAttribute('icon'))
+ if rec.hasAttribute('groups'):
+ g_names = rec.getAttribute('groups').split(',')
+ groups_value = []
+ groups_obj = self.pool.get('res.groups')
+ for group in g_names:
+ if group.startswith('-'):
+ group_id = self.id_get(cr, 'res.groups', group[1:])
+ groups_value.append((3, group_id))
+ else:
+ group_id = self.id_get(cr, 'res.groups', group)
+ groups_value.append((4, group_id))
+ values['groups_id'] = groups_value
+
+ xml_id = rec.getAttribute('id').encode('utf8')
+ self._test_xml_id(xml_id)
+ pid = self.pool.get('ir.model.data')._update(cr, self.uid, 'ir.ui.menu', self.module, values, xml_id, True, mode=self.mode, res_id=res and res[0] or False)
+
+ if rec_id and pid:
+ self.idref[rec_id] = int(pid)
+
+ if rec.hasAttribute('action') and pid:
+ a_action = rec.getAttribute('action').encode('utf8')
+ a_type = rec.getAttribute('type').encode('utf8') or 'act_window'
+ a_id = self.id_get(cr, 'ir.actions.%s' % a_type, a_action)
+ action = "ir.actions.%s,%d" % (a_type, a_id)
+ self.pool.get('ir.model.data').ir_set(cr, self.uid, 'action', 'tree_but_open', 'Menuitem', [('ir.ui.menu', int(pid))], action, True, True, xml_id=rec_id)
+ return ('ir.ui.menu', pid)
+
+ def _assert_equals(self, f1, f2, prec = 4):
+ return not round(f1 - f2, prec)
+
+ def _tag_assert(self, cr, rec, data_node=None):
+ if self.isnoupdate(data_node) and self.mode != 'init':
+ return
+
+ rec_model = rec.getAttribute("model").encode('ascii')
+ model = self.pool.get(rec_model)
+ assert model, "The model %s does not exist !" % (rec_model,)
+ rec_id = rec.getAttribute("id").encode('ascii')
+ self._test_xml_id(rec_id)
+ rec_src = rec.getAttribute("search").encode('utf8')
+ rec_src_count = rec.getAttribute("count")
+
+ severity = rec.getAttribute("severity").encode('ascii') or 'info'
+
+ rec_string = rec.getAttribute("string").encode('utf8') or 'unknown'
+
+ ids = None
+ eval_dict = {'ref': _ref(self, cr)}
+ context = self.get_context(data_node, rec, eval_dict)
+ uid = self.get_uid(cr, self.uid, data_node, rec)
+ if len(rec_id):
+ ids = [self.id_get(cr, rec_model, rec_id)]
+ elif len(rec_src):
+ q = eval(rec_src, eval_dict)
+ ids = self.pool.get(rec_model).search(cr, uid, q, context=context)
+ if len(rec_src_count):
+ count = int(rec_src_count)
+ if len(ids) != count:
+ self.assert_report.record_assertion(False, severity)
+ self.logger.notifyChannel('init', severity, 'assertion "' + rec_string + '" failed ! (search count is incorrect: ' + str(len(ids)) + ')' )
+ sevval = getattr(logging, severity.upper())
+ if sevval > config['assert_exit_level']:
+ # TODO: define a dedicated exception
+ raise Exception('Severe assertion failure')
+ return
+
+ assert ids != None, 'You must give either an id or a search criteria'
+
+ ref = _ref(self, cr)
+ for id in ids:
+ brrec = model.browse(cr, uid, id, context)
+ class d(dict):
+ def __getitem__(self2, key):
+ if key in brrec:
+ return brrec[key]
+ return dict.__getitem__(self2, key)
+ globals = d()
+ globals['floatEqual'] = self._assert_equals
+ globals['ref'] = ref
+ globals['_ref'] = ref
+ for test in [i for i in rec.childNodes if (i.nodeType == i.ELEMENT_NODE and i.nodeName=="test")]:
+ f_expr = test.getAttribute("expr").encode('utf-8')
+ f_val = _eval_xml(self, test, self.pool, cr, uid, self.idref, context=context) or True
+ if eval(f_expr, globals) != f_val: # assertion failed
+ self.assert_report.record_assertion(False, severity)
+ self.logger.notifyChannel('init', severity, 'assertion "' + rec_string + '" failed ! (tag ' + test.toxml() + ')' )
+ sevval = getattr(logging, severity.upper())
+ if sevval > config['assert_exit_level']:
+ # TODO: define a dedicated exception
+ raise Exception('Severe assertion failure')
+ return
+ else: # all tests were successful for this assertion tag (no break)
+ self.assert_report.record_assertion(True, severity)
+
+ def _tag_record(self, cr, rec, data_node=None):
+ rec_model = rec.getAttribute("model").encode('ascii')
+ model = self.pool.get(rec_model)
+ assert model, "The model %s does not exist !" % (rec_model,)
+ rec_id = rec.getAttribute("id").encode('ascii')
+ self._test_xml_id(rec_id)
+
+# if not rec_id and not self.isnoupdate(data_node):
+# print "Warning", rec_model
+
+ if self.isnoupdate(data_node) and not self.mode == 'init':
+ # check if the xml record has an id string
+ if rec_id:
+ id = self.pool.get('ir.model.data')._update_dummy(cr, self.uid, rec_model, self.module, rec_id)
+ # check if the resource already existed at the last update
+ if id:
+ # if it existed, we don't update the data, but we need to
+ # know the id of the existing record anyway
+ self.idref[rec_id] = int(id)
+ return None
+ else:
+ # if the resource didn't exist
+ if rec.getAttribute("forcecreate"):
+ # we want to create it, so we let the normal "update" behavior happen
+ pass
+ else:
+ # otherwise do nothing
+ return None
+ else:
+ # otherwise it is skipped
+ return None
+
+ res = {}
+ for field in [i for i in rec.childNodes if (i.nodeType == i.ELEMENT_NODE and i.nodeName=="field")]:
#TODO: most of this code is duplicated above (in _eval_xml)...
- f_name = field.getAttribute("name").encode('utf-8')
- f_ref = field.getAttribute("ref").encode('ascii')
- f_search = field.getAttribute("search").encode('utf-8')
- f_model = field.getAttribute("model").encode('ascii')
- if not f_model and model._columns.get(f_name,False):
- f_model = model._columns[f_name]._obj
- f_use = field.getAttribute("use").encode('ascii') or 'id'
- f_val = False
-
- if len(f_search):
- q = eval(f_search, self.idref)
- field = []
- assert f_model, 'Define an attribute model="..." in your .XML file !'
- f_obj = self.pool.get(f_model)
- # browse the objects searched
- s = f_obj.browse(cr, self.uid, f_obj.search(cr, self.uid, q))
- # column definitions of the "local" object
- _cols = self.pool.get(rec_model)._columns
- # if the current field is many2many
- if (f_name in _cols) and _cols[f_name]._type=='many2many':
- f_val = [(6, 0, map(lambda x: x[f_use], s))]
- elif len(s):
- # otherwise (we are probably in a many2one field),
- # take the first element of the search
- f_val = s[0][f_use]
- elif len(f_ref):
- if f_ref=="null":
- f_val = False
- else:
- f_val = self.id_get(cr, f_model, f_ref)
- else:
- f_val = _eval_xml(self,field, self.pool, cr, self.uid, self.idref)
- if model._columns.has_key(f_name):
- if isinstance(model._columns[f_name], osv.fields.integer):
- f_val = int(f_val)
- res[f_name] = f_val
- id = self.pool.get('ir.model.data')._update(cr, self.uid, rec_model, self.module, res, rec_id or False, not self.isnoupdate(data_node), noupdate=self.isnoupdate(data_node), mode=self.mode )
- if rec_id:
- self.idref[rec_id] = int(id)
- if config.get('commit_mode', False):
- cr.commit()
- return rec_model, id
-
- def id_get(self, cr, model, id_str):
- if id_str in self.idref:
- return self.idref[id_str]
- mod = self.module
- if '.' in id_str:
- mod,id_str = id_str.split('.')
- result = self.pool.get('ir.model.data')._get_id(cr, self.uid, mod, id_str)
- return int(self.pool.get('ir.model.data').read(cr, self.uid, [result], ['res_id'])[0]['res_id'])
-
- def parse(self, xmlstr):
- d = xml.dom.minidom.parseString(xmlstr)
- de = d.documentElement
- for n in [i for i in de.childNodes if (i.nodeType == i.ELEMENT_NODE and i.nodeName=="data")]:
- for rec in n.childNodes:
- if rec.nodeType == rec.ELEMENT_NODE:
- if rec.nodeName in self._tags:
- try:
- self._tags[rec.nodeName](self.cr, rec, n)
- except:
- self.logger.notifyChannel("init", netsvc.LOG_INFO, '\n'+rec.toxml())
- self.cr.rollback()
- raise
- return True
-
- def __init__(self, cr, module, idref, mode, report=assertion_report(), noupdate = False):
- self.logger = netsvc.Logger()
- self.mode = mode
- self.module = module
- self.cr = cr
- self.idref = idref
- self.pool = pooler.get_pool(cr.dbname)
-# self.pool = osv.osv.FakePool(module)
- self.uid = 1
- self.assert_report = report
- self.noupdate = noupdate
- self._tags = {
- 'menuitem': self._tag_menuitem,
- 'record': self._tag_record,
- 'assert': self._tag_assert,
- 'report': self._tag_report,
- 'wizard': self._tag_wizard,
- 'delete': self._tag_delete,
- 'ir_set': self._tag_ir_set,
- 'function': self._tag_function,
- 'workflow': self._tag_workflow,
- 'act_window': self._tag_act_window,
- 'url': self._tag_url
- }
+ f_name = field.getAttribute("name").encode('utf-8')
+ f_ref = field.getAttribute("ref").encode('ascii')
+ f_search = field.getAttribute("search").encode('utf-8')
+ f_model = field.getAttribute("model").encode('ascii')
+ if not f_model and model._columns.get(f_name,False):
+ f_model = model._columns[f_name]._obj
+ f_use = field.getAttribute("use").encode('ascii') or 'id'
+ f_val = False
+
+ if len(f_search):
+ q = eval(f_search, self.idref)
+ field = []
+ assert f_model, 'Define an attribute model="..." in your .XML file !'
+ f_obj = self.pool.get(f_model)
+ # browse the objects searched
+ s = f_obj.browse(cr, self.uid, f_obj.search(cr, self.uid, q))
+ # column definitions of the "local" object
+ _cols = self.pool.get(rec_model)._columns
+ # if the current field is many2many
+ if (f_name in _cols) and _cols[f_name]._type=='many2many':
+ f_val = [(6, 0, map(lambda x: x[f_use], s))]
+ elif len(s):
+ # otherwise (we are probably in a many2one field),
+ # take the first element of the search
+ f_val = s[0][f_use]
+ elif len(f_ref):
+ if f_ref=="null":
+ f_val = False
+ else:
+ f_val = self.id_get(cr, f_model, f_ref)
+ else:
+ f_val = _eval_xml(self,field, self.pool, cr, self.uid, self.idref)
+ if model._columns.has_key(f_name):
+ if isinstance(model._columns[f_name], osv.fields.integer):
+ f_val = int(f_val)
+ res[f_name] = f_val
+ id = self.pool.get('ir.model.data')._update(cr, self.uid, rec_model, self.module, res, rec_id or False, not self.isnoupdate(data_node), noupdate=self.isnoupdate(data_node), mode=self.mode )
+ if rec_id:
+ self.idref[rec_id] = int(id)
+ if config.get('commit_mode', False):
+ cr.commit()
+ return rec_model, id
+
+ def id_get(self, cr, model, id_str):
+ if id_str in self.idref:
+ return self.idref[id_str]
+ mod = self.module
+ if '.' in id_str:
+ mod,id_str = id_str.split('.')
+ result = self.pool.get('ir.model.data')._get_id(cr, self.uid, mod, id_str)
+ return int(self.pool.get('ir.model.data').read(cr, self.uid, [result], ['res_id'])[0]['res_id'])
+
+ def parse(self, xmlstr):
+ d = xml.dom.minidom.parseString(xmlstr)
+ de = d.documentElement
+ for n in [i for i in de.childNodes if (i.nodeType == i.ELEMENT_NODE and i.nodeName=="data")]:
+ for rec in n.childNodes:
+ if rec.nodeType == rec.ELEMENT_NODE:
+ if rec.nodeName in self._tags:
+ try:
+ self._tags[rec.nodeName](self.cr, rec, n)
+ except:
+ self.logger.notifyChannel("init", netsvc.LOG_INFO, '\n'+rec.toxml())
+ self.cr.rollback()
+ raise
+ return True
+
+ def __init__(self, cr, module, idref, mode, report=assertion_report(), noupdate = False):
+ self.logger = netsvc.Logger()
+ self.mode = mode
+ self.module = module
+ self.cr = cr
+ self.idref = idref
+ self.pool = pooler.get_pool(cr.dbname)
+# self.pool = osv.osv.FakePool(module)
+ self.uid = 1
+ self.assert_report = report
+ self.noupdate = noupdate
+ self._tags = {
+ 'menuitem': self._tag_menuitem,
+ 'record': self._tag_record,
+ 'assert': self._tag_assert,
+ 'report': self._tag_report,
+ 'wizard': self._tag_wizard,
+ 'delete': self._tag_delete,
+ 'ir_set': self._tag_ir_set,
+ 'function': self._tag_function,
+ 'workflow': self._tag_workflow,
+ 'act_window': self._tag_act_window,
+ 'url': self._tag_url
+ }
def convert_csv_import(cr, module, fname, csvcontent, idref=None, mode='init',
- noupdate=False):
- '''Import csv file :
- quote: "
- delimiter: ,
- encoding: utf-8'''
- if not idref:
- idref={}
- model = ('.'.join(fname.split('.')[:-1]).split('-'))[0]
- #remove folder path from model
- head, model = os.path.split(model)
-
- pool = pooler.get_pool(cr.dbname)
-
- input = StringIO.StringIO(csvcontent)
- reader = csv.reader(input, quotechar='"', delimiter=',')
- fields = reader.next()
-
- if not (mode == 'init' or 'id' in fields):
- return
-
- uid = 1
- datas = []
- for line in reader:
- if (not line) or not reduce(lambda x,y: x or y, line) :
- continue
- datas.append( map(lambda x:x.decode('utf8').encode('utf8'), line))
- pool.get(model).import_data(cr, uid, fields, datas,mode, module,noupdate)
+ noupdate=False):
+ '''Import csv file :
+ quote: "
+ delimiter: ,
+ encoding: utf-8'''
+ if not idref:
+ idref={}
+ model = ('.'.join(fname.split('.')[:-1]).split('-'))[0]
+ #remove folder path from model
+ head, model = os.path.split(model)
+
+ pool = pooler.get_pool(cr.dbname)
+
+ input = StringIO.StringIO(csvcontent)
+ reader = csv.reader(input, quotechar='"', delimiter=',')
+ fields = reader.next()
+
+ if not (mode == 'init' or 'id' in fields):
+ return
+
+ uid = 1
+ datas = []
+ for line in reader:
+ if (not line) or not reduce(lambda x,y: x or y, line) :
+ continue
+ datas.append( map(lambda x:x.decode('utf8').encode('utf8'), line))
+ pool.get(model).import_data(cr, uid, fields, datas,mode, module,noupdate)
#
# xml import/export
#
def convert_xml_import(cr, module, xmlfile, idref=None, mode='init', noupdate = False, report=None):
- xmlstr = xmlfile.read()
- xmlfile.seek(0)
- relaxng_doc = etree.parse(file(os.path.join( config['root_path'], 'import_xml.rng' )))
- relaxng = etree.RelaxNG(relaxng_doc)
-
- doc = etree.parse(xmlfile)
- try:
- relaxng.assert_(doc)
- except Exception, e:
- logger = netsvc.Logger()
- logger.notifyChannel('init', netsvc.LOG_ERROR, 'The XML file do not fit the required schema !')
- logger.notifyChannel('init', netsvc.LOG_ERROR, relaxng.error_log.last_error)
- raise
-
- if not idref:
- idref={}
- if report is None:
- report=assertion_report()
- obj = xml_import(cr, module, idref, mode, report=report, noupdate = noupdate)
- obj.parse(xmlstr)
- del obj
- return True
+ xmlstr = xmlfile.read()
+ xmlfile.seek(0)
+ relaxng_doc = etree.parse(file(os.path.join( config['root_path'], 'import_xml.rng' )))
+ relaxng = etree.RelaxNG(relaxng_doc)
+
+ doc = etree.parse(xmlfile)
+ try:
+ relaxng.assert_(doc)
+ except Exception, e:
+ logger = netsvc.Logger()
+ logger.notifyChannel('init', netsvc.LOG_ERROR, 'The XML file do not fit the required schema !')
+ logger.notifyChannel('init', netsvc.LOG_ERROR, relaxng.error_log.last_error)
+ raise
+
+ if not idref:
+ idref={}
+ if report is None:
+ report=assertion_report()
+ obj = xml_import(cr, module, idref, mode, report=report, noupdate = noupdate)
+ obj.parse(xmlstr)
+ del obj
+ return True
def convert_xml_export(res):
- uid=1
- pool=pooler.get_pool(cr.dbname)
- cr=pooler.db.cursor()
- idref = {}
- d = xml.dom.minidom.getDOMImplementation().createDocument(None, "terp", None)
- de = d.documentElement
- data=d.createElement("data")
- de.appendChild(data)
- de.appendChild(d.createTextNode('Some textual content.'))
- cr.commit()
- cr.close()
+ uid=1
+ pool=pooler.get_pool(cr.dbname)
+ cr=pooler.db.cursor()
+ idref = {}
+ d = xml.dom.minidom.getDOMImplementation().createDocument(None, "terp", None)
+ de = d.documentElement
+ data=d.createElement("data")
+ de.appendChild(data)
+ de.appendChild(d.createTextNode('Some textual content.'))
+ cr.commit()
+ cr.close()
diff --git a/bin/tools/graph.py b/bin/tools/graph.py
index c271726b79c..697bbd936d8 100644
--- a/bin/tools/graph.py
+++ b/bin/tools/graph.py
@@ -28,306 +28,306 @@
###############################################################################
class graph(object):
- def __init__(self, nodes, transitions):
- self.nodes = nodes
- self.links = transitions
- trans = {}
- for t in transitions:
- trans.setdefault(t[0], [])
- trans[t[0]].append(t[1])
- self.transitions = trans
- self.result = {}
- self.levels = {}
-
- def get_parent(self,node):
- count = 0
- for item in self.transitions:
- if self.transitions[item].__contains__(node):
- count +=1
- return count
-
- def init_rank(self):
- self.temp = {}
- for link in self.links:
- self.temp[link] = self.result[link[1]]['y'] - self.result[link[0]]['y']
-
- cnt = 0
- list_node = []
- list_edge = []
-
- while self.tight_tree()<self.result.__len__():
- cnt+=1
- list_node = []
-
- for node in self.nodes:
- if node not in self.reachable_nodes:
- list_node.append(node)
- list_edge = []
-
- for link in self.temp:
- if link not in self.tree_edges:
- list_edge.append(link)
-
- slack = 100
-
- for edge in list_edge:
- if (self.reachable_nodes.__contains__(edge[0]) and edge[1] not in self.reachable_nodes) or ( self.reachable_nodes.__contains__(edge[1]) and edge[0] not in self.reachable_nodes):
- if(slack>self.temp[edge]-1):
- slack = self.temp[edge]-1
- new_edge = edge
-
- if new_edge[0] not in self.reachable_nodes:
- delta = -(self.temp[new_edge]-1)
- else:
- delta = self.temp[new_edge]-1
-
- for node in self.result:
- if node in self.reachable_nodes:
- self.result[node]['y'] += delta
-
- for link in self.temp:
- self.temp[link] = self.result[link[1]]['y'] - self.result[link[0]]['y']
-
- self.init_cutvalues()
-
-
-
-
- def tight_tree(self,):
- self.reachable_nodes = []
- self.tree_edges = []
- self.reachable_node(self.start)
- return self.reachable_nodes.__len__()
-
- def reachable_node(self,node):
- if node not in self.reachable_nodes:
- self.reachable_nodes.append(node)
- for link in self.temp:
- if link[0]==node:
-# print link[0]
- if self.temp[link]==1:
- self.tree_edges.append(link)
- if link[1] not in self.reachable_nodes:
- self.reachable_nodes.append(link[1])
- self.reachable_node(link[1])
-
-
- def init_cutvalues(self):
- self.cut_edges = {}
- self.head_nodes = []
- i=0;
- for edge in self.tree_edges:
- self.head_nodes = []
- rest_edges = []
- rest_edges += self.tree_edges
- rest_edges.__delitem__(i)
- self.head_component(self.start,rest_edges)
- i+=1
- positive = 0
- negative = 0
- for source_node in self.transitions:
- if source_node in self.head_nodes:
- for dest_node in self.transitions[source_node]:
- if dest_node not in self.head_nodes:
- negative+=1
- else:
- for dest_node in self.transitions[source_node]:
- if dest_node in self.head_nodes:
- positive+=1
+ def __init__(self, nodes, transitions):
+ self.nodes = nodes
+ self.links = transitions
+ trans = {}
+ for t in transitions:
+ trans.setdefault(t[0], [])
+ trans[t[0]].append(t[1])
+ self.transitions = trans
+ self.result = {}
+ self.levels = {}
+
+ def get_parent(self,node):
+ count = 0
+ for item in self.transitions:
+ if self.transitions[item].__contains__(node):
+ count +=1
+ return count
+
+ def init_rank(self):
+ self.temp = {}
+ for link in self.links:
+ self.temp[link] = self.result[link[1]]['y'] - self.result[link[0]]['y']
+
+ cnt = 0
+ list_node = []
+ list_edge = []
+
+ while self.tight_tree()<self.result.__len__():
+ cnt+=1
+ list_node = []
+
+ for node in self.nodes:
+ if node not in self.reachable_nodes:
+ list_node.append(node)
+ list_edge = []
+
+ for link in self.temp:
+ if link not in self.tree_edges:
+ list_edge.append(link)
+
+ slack = 100
+
+ for edge in list_edge:
+ if (self.reachable_nodes.__contains__(edge[0]) and edge[1] not in self.reachable_nodes) or ( self.reachable_nodes.__contains__(edge[1]) and edge[0] not in self.reachable_nodes):
+ if(slack>self.temp[edge]-1):
+ slack = self.temp[edge]-1
+ new_edge = edge
+
+ if new_edge[0] not in self.reachable_nodes:
+ delta = -(self.temp[new_edge]-1)
+ else:
+ delta = self.temp[new_edge]-1
+
+ for node in self.result:
+ if node in self.reachable_nodes:
+ self.result[node]['y'] += delta
+
+ for link in self.temp:
+ self.temp[link] = self.result[link[1]]['y'] - self.result[link[0]]['y']
+
+ self.init_cutvalues()
+
+
+
+
+ def tight_tree(self,):
+ self.reachable_nodes = []
+ self.tree_edges = []
+ self.reachable_node(self.start)
+ return self.reachable_nodes.__len__()
+
+ def reachable_node(self,node):
+ if node not in self.reachable_nodes:
+ self.reachable_nodes.append(node)
+ for link in self.temp:
+ if link[0]==node:
+# print link[0]
+ if self.temp[link]==1:
+ self.tree_edges.append(link)
+ if link[1] not in self.reachable_nodes:
+ self.reachable_nodes.append(link[1])
+ self.reachable_node(link[1])
+
+
+ def init_cutvalues(self):
+ self.cut_edges = {}
+ self.head_nodes = []
+ i=0;
+ for edge in self.tree_edges:
+ self.head_nodes = []
+ rest_edges = []
+ rest_edges += self.tree_edges
+ rest_edges.__delitem__(i)
+ self.head_component(self.start,rest_edges)
+ i+=1
+ positive = 0
+ negative = 0
+ for source_node in self.transitions:
+ if source_node in self.head_nodes:
+ for dest_node in self.transitions[source_node]:
+ if dest_node not in self.head_nodes:
+ negative+=1
+ else:
+ for dest_node in self.transitions[source_node]:
+ if dest_node in self.head_nodes:
+ positive+=1
- self.cut_edges[edge] = positive - negative
-
-
+ self.cut_edges[edge] = positive - negative
+
+
-
- def head_component(self, node, rest_edges):
- if node not in self.head_nodes:
- self.head_nodes.append(node)
- for link in rest_edges:
- if link[0]==node:
- self.head_component(link[1],rest_edges)
-
+
+ def head_component(self, node, rest_edges):
+ if node not in self.head_nodes:
+ self.head_nodes.append(node)
+ for link in rest_edges:
+ if link[0]==node:
+ self.head_component(link[1],rest_edges)
+
- def process_ranking(self, node, level=0):
- if node not in self.result:
- self.result[node] = {'x': None, 'y':level, 'mark':0}
- else:
- if level > self.result[node]['y']:
- self.result[node]['y'] = level
- if self.result[node]['mark']==0:
- self.result[node]['mark'] = 1
- for t in self.transitions.get(node, []):
- self.process_ranking(t, level+1)
-
+ def process_ranking(self, node, level=0):
+ if node not in self.result:
+ self.result[node] = {'x': None, 'y':level, 'mark':0}
+ else:
+ if level > self.result[node]['y']:
+ self.result[node]['y'] = level
+ if self.result[node]['mark']==0:
+ self.result[node]['mark'] = 1
+ for t in self.transitions.get(node, []):
+ self.process_ranking(t, level+1)
+
- def preprocess_order(self):
- levels = {}
- for r in self.result:
- l = self.result[r]['y']
- levels.setdefault(l,[])
- levels[l].append(r)
- self.levels = levels
+ def preprocess_order(self):
+ levels = {}
+ for r in self.result:
+ l = self.result[r]['y']
+ levels.setdefault(l,[])
+ levels[l].append(r)
+ self.levels = levels
- def process_order(self, level):
- self.levels[level].sort(lambda x,y: cmp(self.result[x]['x'], self.result[y]['x']))
- for nodepos in range(len(self.levels[level])):
- node = self.levels[level][nodepos]
- if nodepos == 0:
- left = self.result[node]['x']- 0.5
- else:
- left = (self.result[node]['x'] + self.result[self.levels[level][nodepos-1]]['x']) / 2.0
+ def process_order(self, level):
+ self.levels[level].sort(lambda x,y: cmp(self.result[x]['x'], self.result[y]['x']))
+ for nodepos in range(len(self.levels[level])):
+ node = self.levels[level][nodepos]
+ if nodepos == 0:
+ left = self.result[node]['x']- 0.5
+ else:
+ left = (self.result[node]['x'] + self.result[self.levels[level][nodepos-1]]['x']) / 2.0
- if nodepos == (len(self.levels[level])-1):
- right = self.result[node]['x'] + 0.5
- else:
- right = (self.result[node]['x'] + self.result[self.levels[level][nodepos+1]]['x']) / 2.0
+ if nodepos == (len(self.levels[level])-1):
+ right = self.result[node]['x'] + 0.5
+ else:
+ right = (self.result[node]['x'] + self.result[self.levels[level][nodepos+1]]['x']) / 2.0
- if self.transitions.get(node, False):
- if len(self.transitions[node])==1:
- pos = (left+right)/2.0
- step = 0
- else:
- pos = left
- step = (-left+right) / (len(self.transitions[node])-1)
+ if self.transitions.get(node, False):
+ if len(self.transitions[node])==1:
+ pos = (left+right)/2.0
+ step = 0
+ else:
+ pos = left
+ step = (-left+right) / (len(self.transitions[node])-1)
- for n2 in self.transitions[node]:
- self.result[n2]['x'] = pos
- pos += step
-
- def exchange(self,e,f):
- self.tree_edges.__delitem__(self.tree_edges.index(e))
- self.tree_edges.append(f)
- self.init_cutvalues()
-
-
- def enter_edge(self,edge):
- self.head_nodes = []
- rest_edges = []
- rest_edges += self.tree_edges
- rest_edges.__delitem__(rest_edges.index(edge))
- self.head_component(self.start,rest_edges)
- slack = 100
- for source_node in self.transitions:
- if source_node in self.head_nodes:
- for dest_node in self.transitions[source_node]:
- if dest_node not in self.head_nodes:
- if(slack>(self.temp[edge]-1)):
- slack = self.temp[edge]-1
- new_edge = (source_node,dest_node)
- return new_edge
-
+ for n2 in self.transitions[node]:
+ self.result[n2]['x'] = pos
+ pos += step
+
+ def exchange(self,e,f):
+ self.tree_edges.__delitem__(self.tree_edges.index(e))
+ self.tree_edges.append(f)
+ self.init_cutvalues()
+
+
+ def enter_edge(self,edge):
+ self.head_nodes = []
+ rest_edges = []
+ rest_edges += self.tree_edges
+ rest_edges.__delitem__(rest_edges.index(edge))
+ self.head_component(self.start,rest_edges)
+ slack = 100
+ for source_node in self.transitions:
+ if source_node in self.head_nodes:
+ for dest_node in self.transitions[source_node]:
+ if dest_node not in self.head_nodes:
+ if(slack>(self.temp[edge]-1)):
+ slack = self.temp[edge]-1
+ new_edge = (source_node,dest_node)
+ return new_edge
+
- def leave_edge(self):
- for edge in self.cut_edges:
- if self.cut_edges[edge]<0:
- return edge
- return ()
+ def leave_edge(self):
+ for edge in self.cut_edges:
+ if self.cut_edges[edge]<0:
+ return edge
+ return ()
- def process(self, starting_node):
- pos = (len(starting_node) - 1.0)/2.0
- self.start = starting_node[0]
- for s in starting_node:
- self.process_ranking(s)
- self.result[s]['x'] = pos
- pos += 1.0
- self.init_rank()
- #normalize
- least_rank=100
-
- #normalization
- for node in self.result:
- if least_rank>self.result[node]['y']:
- least_rank = self.result[node]['y']
-
- if(least_rank!=0):
- diff = least_rank
- for node in self.result:
- self.result[node]['y']-=least_rank
-
- e = self.leave_edge()
- #while e:
- f = self.enter_edge(e)
- self.exchange(e,f)
- e = self.leave_edge()
-
-
-
- self.preprocess_order()
- for n in self.levels:
- self.process_order(n)
-
-
-
+ def process(self, starting_node):
+ pos = (len(starting_node) - 1.0)/2.0
+ self.start = starting_node[0]
+ for s in starting_node:
+ self.process_ranking(s)
+ self.result[s]['x'] = pos
+ pos += 1.0
+ self.init_rank()
+ #normalize
+ least_rank=100
+
+ #normalization
+ for node in self.result:
+ if least_rank>self.result[node]['y']:
+ least_rank = self.result[node]['y']
+
+ if(least_rank!=0):
+ diff = least_rank
+ for node in self.result:
+ self.result[node]['y']-=least_rank
+
+ e = self.leave_edge()
+ #while e:
+ f = self.enter_edge(e)
+ self.exchange(e,f)
+ e = self.leave_edge()
+
+
+
+ self.preprocess_order()
+ for n in self.levels:
+ self.process_order(n)
+
+
+
- def __str__(self):
- result = ''
- for l in self.levels:
- result += 'PosY: ' + str(l) + '\n'
- for node in self.levels[l]:
- result += '\tPosX: '+ str(self.result[node]['x']) + ' - Node:' + node + "\n"
- return result
+ def __str__(self):
+ result = ''
+ for l in self.levels:
+ result += 'PosY: ' + str(l) + '\n'
+ for node in self.levels[l]:
+ result += '\tPosX: '+ str(self.result[node]['x']) + ' - Node:' + node + "\n"
+ return result
- def scale(self, maxx, maxy, plusx2=0, plusy2=0):
- plusx = - min(map(lambda x: x['x'],self.result.values()))
- plusy = - min(map(lambda x: x['y'],self.result.values()))
+ def scale(self, maxx, maxy, plusx2=0, plusy2=0):
+ plusx = - min(map(lambda x: x['x'],self.result.values()))
+ plusy = - min(map(lambda x: x['y'],self.result.values()))
- maxcurrent = 1.0
- diff = 1.0
- for l in self.levels:
- for n in range(1, len(self.levels[l])):
- n1 = self.levels[l][n]
- n2 = self.levels[l][n-1]
- diff = abs(self.result[n2]['x']-self.result[n1]['x'])
- if diff<maxcurrent:
- maxcurrent=diff
- factor = maxx / diff
- for r in self.result:
- self.result[r]['x'] = (self.result[r]['x']+plusx) * factor + plusx2
- self.result[r]['y'] = (self.result[r]['y']+plusy) * maxy + plusy2
+ maxcurrent = 1.0
+ diff = 1.0
+ for l in self.levels:
+ for n in range(1, len(self.levels[l])):
+ n1 = self.levels[l][n]
+ n2 = self.levels[l][n-1]
+ diff = abs(self.result[n2]['x']-self.result[n1]['x'])
+ if diff<maxcurrent:
+ maxcurrent=diff
+ factor = maxx / diff
+ for r in self.result:
+ self.result[r]['x'] = (self.result[r]['x']+plusx) * factor + plusx2
+ self.result[r]['y'] = (self.result[r]['y']+plusy) * maxy + plusy2
- def result_get(self):
- return self.result
+ def result_get(self):
+ return self.result
if __name__=='__main__':
- starting_node = ['profile'] # put here nodes with flow_start=True
- nodes = ['project','account','hr','base','product','mrp','test','profile']
- transitions = [
- ('profile','mrp'),
- ('mrp','project'),
- ('project','product'),
- ('mrp','hr'),
- ('mrp','test'),
- ('project','account'),
- ('project','hr'),
- ('product','base'),
- ('account','product'),
- ('account','test'),
- ('account','base'),
- ('hr','base'),
- ('test','base')
- ]
+ starting_node = ['profile'] # put here nodes with flow_start=True
+ nodes = ['project','account','hr','base','product','mrp','test','profile']
+ transitions = [
+ ('profile','mrp'),
+ ('mrp','project'),
+ ('project','product'),
+ ('mrp','hr'),
+ ('mrp','test'),
+ ('project','account'),
+ ('project','hr'),
+ ('product','base'),
+ ('account','product'),
+ ('account','test'),
+ ('account','base'),
+ ('hr','base'),
+ ('test','base')
+ ]
- radius = 20
- g = graph(nodes, transitions)
- g.process(starting_node)
- g.scale(radius*3,radius*3, radius, radius)
+ radius = 20
+ g = graph(nodes, transitions)
+ g.process(starting_node)
+ g.scale(radius*3,radius*3, radius, radius)
- print g
+ print g
- import Image
- import ImageDraw
- img = Image.new("RGB", (800, 600), "#ffffff")
- draw = ImageDraw.Draw(img)
+ import Image
+ import ImageDraw
+ img = Image.new("RGB", (800, 600), "#ffffff")
+ draw = ImageDraw.Draw(img)
- for name,node in g.result.items():
- draw.arc( (int(node['x']-radius), int(node['y']-radius),int(node['x']+radius), int(node['y']+radius) ), 0, 360, (128,128,128))
- draw.text( (int(node['x']), int(node['y'])), name, (128,128,128))
+ for name,node in g.result.items():
+ draw.arc( (int(node['x']-radius), int(node['y']-radius),int(node['x']+radius), int(node['y']+radius) ), 0, 360, (128,128,128))
+ draw.text( (int(node['x']), int(node['y'])), name, (128,128,128))
- for nodefrom in g.transitions:
- for nodeto in g.transitions[nodefrom]:
- draw.line( (int(g.result[nodefrom]['x']), int(g.result[nodefrom]['y']),int(g.result[nodeto]['x']),int(g.result[nodeto]['y'])),(128,128,128) )
+ for nodefrom in g.transitions:
+ for nodeto in g.transitions[nodefrom]:
+ draw.line( (int(g.result[nodefrom]['x']), int(g.result[nodefrom]['y']),int(g.result[nodeto]['x']),int(g.result[nodeto]['y'])),(128,128,128) )
- img.save("graph.png", "PNG")
+ img.save("graph.png", "PNG")
diff --git a/bin/tools/import_email.py b/bin/tools/import_email.py
index d09a3090e8d..e31d8e13800 100644
--- a/bin/tools/import_email.py
+++ b/bin/tools/import_email.py
@@ -43,131 +43,131 @@ Le message avec le sujet "%s" n'a pu être archivé dans l'ERP.
class EmailParser(object):
- def __init__(self, headers, dispatcher):
- self.headers = headers
- self.dispatcher = dispatcher
-
- def parse(self, msg):
- dispatcher((self.headers, msg))
+ def __init__(self, headers, dispatcher):
+ self.headers = headers
+ self.dispatcher = dispatcher
+
+ def parse(self, msg):
+ dispatcher((self.headers, msg))
class CommandDispatcher(object):
- def __init__(self, receiver):
- self.receiver = receiver
-
- def __call__(self, request):
- return self.receiver(request)
+ def __init__(self, receiver):
+ self.receiver = receiver
+
+ def __call__(self, request):
+ return self.receiver(request)
class RPCProxy(object):
- def __init__(self, uid, passwd, host='localhost', port=8069, path='object'):
- self.rpc = xmlrpclib.ServerProxy('http://%s:%s/%s' % (host, port, path))
- self.user_id = uid
- self.passwd = passwd
-
- def __call__(self, request):
- return self.rpc.execute(self.user_id, self.passwd, *request)
+ def __init__(self, uid, passwd, host='localhost', port=8069, path='object'):
+ self.rpc = xmlrpclib.ServerProxy('http://%s:%s/%s' % (host, port, path))
+ self.user_id = uid
+ self.passwd = passwd
+
+ def __call__(self, request):
+ return self.rpc.execute(self.user_id, self.passwd, *request)
class ReceiverEmail2Event(object):
- email_re = re.compile(r"""
- ([a-zA-Z][\w\.-]*[a-zA-Z0-9] # username part
- @ # mandatory @ sign
- [a-zA-Z0-9][\w\.-]* # domain must start with a letter
- \.
- [a-z]{2,3} # TLD
- )
- """, re.VERBOSE)
-
- project_re = re.compile(r"^ *\[?(\d{4}\.?\d{0,3})\]?", re.UNICODE)
-
-
- def __init__(self, rpc):
- self.rpc = rpc
-
- def get_addresses(self, headers, msg):
- hcontent = ''
- for header in [h for h in headers if msg.has_key(h)]:
- hcontent += msg[header]
- return self.email_re.findall(hcontent)
-
- def get_partners(self, headers, msg):
- alladdresses = self.get_addresses(headers, msg)
- address_ids = self.rpc(('res.partner.address', 'search', [('email', 'in', alladdresses)]))
- addresses = self.rpc(('res.partner.address', 'read', address_ids))
- return [x['partner_id'][0] for x in addresses]
-
- def __call__(self, request):
- headers, msg = request
- partners = self.get_partners(headers, msg)
- subject = u''
- for string, charset in decode_header(msg['Subject']):
- if charset:
- subject += string.decode(charset)
- else:
- subject += unicode(string)
- if partners:
- self.save_mail(msg, subject, partners)
- else:
- warning = MIMEText((warn_msg % (subject,)).encode('utf-8'), 'plain', 'utf-8')
- warning['Subject'] = 'Message de TinyERP'
- warning['From'] = 'erp@steel-sa.com'
- warning['To'] = msg['From']
- s = smtplib.SMTP()
- s.connect()
- s.sendmail('erp@steel-sa.com', self.email_re.findall(msg['From']), warning.as_string())
- s.close()
-
- if msg.is_multipart():
- for message in [m for m in msg.get_payload() if m.get_content_type() == 'message/rfc822']:
- self((headers, message.get_payload()[0]))
-
- def save_mail(self, msg, subject, partners):
- counter, description = 1, u''
- if msg.is_multipart():
- for part in msg.get_payload():
- stockdir = os.path.join('emails', msg['Message-Id'][1:-1])
- newdir = os.path.join('/tmp', stockdir)
- filename = part.get_filename()
- if not filename:
- ext = mimetypes.guess_extension(part.get_type())
- if not ext:
- ext = '.bin'
- filename = 'part-%03d%s' % (counter, ext)
-
- if part.get_content_maintype() == 'multipart':
- continue
- elif part.get_content_maintype() == 'text':
- if part.get_content_subtype() == 'plain':
- description += part.get_payload(decode=1).decode(part.get_charsets()[0])
- description += u'\n\nVous trouverez les éventuels fichiers dans le répertoire: %s' % stockdir
- continue
- else:
- description += u'\n\nCe message est en "%s", vous trouverez ce texte dans le répertoire: %s' % (part.get_content_type(), stockdir)
- elif part.get_content_type() == 'message/rfc822':
- continue
- if not os.path.isdir(newdir):
- os.mkdir(newdir)
-
- counter += 1
- fd = file(os.path.join(newdir, filename), 'w')
- fd.write(part.get_payload(decode=1))
- fd.close()
- else:
- description = msg.get_payload(decode=1).decode(msg.get_charsets()[0])
-
- project = self.project_re.search(subject)
- if project:
- project = project.groups()[0]
- else:
- project = ''
-
- for partner in partners:
- self.rpc(('res.partner.event', 'create', {'name' : subject, 'partner_id' : partner, 'description' : description, 'project' : project}))
+ email_re = re.compile(r"""
+ ([a-zA-Z][\w\.-]*[a-zA-Z0-9] # username part
+ @ # mandatory @ sign
+ [a-zA-Z0-9][\w\.-]* # domain must start with a letter
+ \.
+ [a-z]{2,3} # TLD
+ )
+ """, re.VERBOSE)
+
+ project_re = re.compile(r"^ *\[?(\d{4}\.?\d{0,3})\]?", re.UNICODE)
+
+
+ def __init__(self, rpc):
+ self.rpc = rpc
+
+ def get_addresses(self, headers, msg):
+ hcontent = ''
+ for header in [h for h in headers if msg.has_key(h)]:
+ hcontent += msg[header]
+ return self.email_re.findall(hcontent)
+
+ def get_partners(self, headers, msg):
+ alladdresses = self.get_addresses(headers, msg)
+ address_ids = self.rpc(('res.partner.address', 'search', [('email', 'in', alladdresses)]))
+ addresses = self.rpc(('res.partner.address', 'read', address_ids))
+ return [x['partner_id'][0] for x in addresses]
+
+ def __call__(self, request):
+ headers, msg = request
+ partners = self.get_partners(headers, msg)
+ subject = u''
+ for string, charset in decode_header(msg['Subject']):
+ if charset:
+ subject += string.decode(charset)
+ else:
+ subject += unicode(string)
+ if partners:
+ self.save_mail(msg, subject, partners)
+ else:
+ warning = MIMEText((warn_msg % (subject,)).encode('utf-8'), 'plain', 'utf-8')
+ warning['Subject'] = 'Message de TinyERP'
+ warning['From'] = 'erp@steel-sa.com'
+ warning['To'] = msg['From']
+ s = smtplib.SMTP()
+ s.connect()
+ s.sendmail('erp@steel-sa.com', self.email_re.findall(msg['From']), warning.as_string())
+ s.close()
+
+ if msg.is_multipart():
+ for message in [m for m in msg.get_payload() if m.get_content_type() == 'message/rfc822']:
+ self((headers, message.get_payload()[0]))
+
+ def save_mail(self, msg, subject, partners):
+ counter, description = 1, u''
+ if msg.is_multipart():
+ for part in msg.get_payload():
+ stockdir = os.path.join('emails', msg['Message-Id'][1:-1])
+ newdir = os.path.join('/tmp', stockdir)
+ filename = part.get_filename()
+ if not filename:
+ ext = mimetypes.guess_extension(part.get_type())
+ if not ext:
+ ext = '.bin'
+ filename = 'part-%03d%s' % (counter, ext)
+
+ if part.get_content_maintype() == 'multipart':
+ continue
+ elif part.get_content_maintype() == 'text':
+ if part.get_content_subtype() == 'plain':
+ description += part.get_payload(decode=1).decode(part.get_charsets()[0])
+ description += u'\n\nVous trouverez les éventuels fichiers dans le répertoire: %s' % stockdir
+ continue
+ else:
+ description += u'\n\nCe message est en "%s", vous trouverez ce texte dans le répertoire: %s' % (part.get_content_type(), stockdir)
+ elif part.get_content_type() == 'message/rfc822':
+ continue
+ if not os.path.isdir(newdir):
+ os.mkdir(newdir)
+
+ counter += 1
+ fd = file(os.path.join(newdir, filename), 'w')
+ fd.write(part.get_payload(decode=1))
+ fd.close()
+ else:
+ description = msg.get_payload(decode=1).decode(msg.get_charsets()[0])
+
+ project = self.project_re.search(subject)
+ if project:
+ project = project.groups()[0]
+ else:
+ project = ''
+
+ for partner in partners:
+ self.rpc(('res.partner.event', 'create', {'name' : subject, 'partner_id' : partner, 'description' : description, 'project' : project}))
if __name__ == '__main__':
- rpc_dispatcher = CommandDispatcher(RPCProxy(4, 'admin'))
- dispatcher = CommandDispatcher(ReceiverEmail2Event(rpc_dispatcher))
- parser = EmailParser(['To', 'Cc', 'From'], dispatcher)
- parser.parse(email.message_from_file(sys.stdin))
+ rpc_dispatcher = CommandDispatcher(RPCProxy(4, 'admin'))
+ dispatcher = CommandDispatcher(ReceiverEmail2Event(rpc_dispatcher))
+ parser = EmailParser(['To', 'Cc', 'From'], dispatcher)
+ parser.parse(email.message_from_file(sys.stdin))
diff --git a/bin/tools/misc.py b/bin/tools/misc.py
index 4523c762c0a..457d22596d9 100644
--- a/bin/tools/misc.py
+++ b/bin/tools/misc.py
@@ -44,123 +44,123 @@ import release
import socket
if sys.version_info[:2] < (2, 4):
- from threadinglocal import local
+ from threadinglocal import local
else:
- from threading import local
+ from threading import local
# initialize a database with base/base.sql
def init_db(cr):
- import addons
- f = addons.get_module_resource('base', 'base.sql')
- for line in file(f).read().split(';'):
- if (len(line)>0) and (not line.isspace()):
- cr.execute(line)
- cr.commit()
-
- for i in addons.get_modules():
- terp_file = addons.get_module_resource(i, '__terp__.py')
- mod_path = addons.get_module_path(i)
- info = False
- if os.path.isfile(terp_file) and not os.path.isfile(mod_path+'.zip'):
- info = eval(file(terp_file).read())
- elif zipfile.is_zipfile(mod_path+'.zip'):
- zfile = zipfile.ZipFile(mod_path+'.zip')
- i = os.path.splitext(i)[0]
- info = eval(zfile.read(os.path.join(i, '__terp__.py')))
- if info:
- categs = info.get('category', 'Uncategorized').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))
- 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))
- else:
- c_id = c_id[0]
- p_id = c_id
- categs = categs[1:]
-
- active = info.get('active', False)
- installable = info.get('installable', True)
- if installable:
- if active:
- state = 'to install'
- else:
- state = 'uninstalled'
- else:
- state = 'uninstallable'
- 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, \
- 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', ''),
- info.get('website', ''), i, info.get('name', False),
- info.get('description', ''), p_id, state))
- dependencies = info.get('depends', [])
- for d in dependencies:
- cr.execute('insert into ir_module_module_dependency \
- (module_id,name) values (%s, %s)', (id, d))
- cr.commit()
+ import addons
+ f = addons.get_module_resource('base', 'base.sql')
+ for line in file(f).read().split(';'):
+ if (len(line)>0) and (not line.isspace()):
+ cr.execute(line)
+ cr.commit()
+
+ for i in addons.get_modules():
+ terp_file = addons.get_module_resource(i, '__terp__.py')
+ mod_path = addons.get_module_path(i)
+ info = False
+ if os.path.isfile(terp_file) and not os.path.isfile(mod_path+'.zip'):
+ info = eval(file(terp_file).read())
+ elif zipfile.is_zipfile(mod_path+'.zip'):
+ zfile = zipfile.ZipFile(mod_path+'.zip')
+ i = os.path.splitext(i)[0]
+ info = eval(zfile.read(os.path.join(i, '__terp__.py')))
+ if info:
+ categs = info.get('category', 'Uncategorized').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))
+ 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))
+ else:
+ c_id = c_id[0]
+ p_id = c_id
+ categs = categs[1:]
+
+ active = info.get('active', False)
+ installable = info.get('installable', True)
+ if installable:
+ if active:
+ state = 'to install'
+ else:
+ state = 'uninstalled'
+ else:
+ state = 'uninstallable'
+ 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, \
+ 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', ''),
+ info.get('website', ''), i, info.get('name', False),
+ info.get('description', ''), p_id, state))
+ dependencies = info.get('depends', [])
+ for d in dependencies:
+ cr.execute('insert into ir_module_module_dependency \
+ (module_id,name) values (%s, %s)', (id, d))
+ cr.commit()
def find_in_path(name):
- if os.name == "nt":
- sep = ';'
- else:
- sep = ':'
- path = [dir for dir in os.environ['PATH'].split(sep)
- if os.path.isdir(dir)]
- for dir in path:
- val = os.path.join(dir, name)
- if os.path.isfile(val) or os.path.islink(val):
- return val
- return None
+ if os.name == "nt":
+ sep = ';'
+ else:
+ sep = ':'
+ path = [dir for dir in os.environ['PATH'].split(sep)
+ if os.path.isdir(dir)]
+ for dir in path:
+ val = os.path.join(dir, name)
+ if os.path.isfile(val) or os.path.islink(val):
+ return val
+ return None
def find_pg_tool(name):
- if config['pg_path'] and config['pg_path'] != 'None':
- return os.path.join(config['pg_path'], name)
- else:
- return find_in_path(name)
+ if config['pg_path'] and config['pg_path'] != 'None':
+ return os.path.join(config['pg_path'], name)
+ else:
+ return find_in_path(name)
def exec_pg_command(name, *args):
- prog = find_pg_tool(name)
- if not prog:
- raise Exception('Couldn\'t find %s' % name)
- args2 = (os.path.basename(prog),) + args
- return os.spawnv(os.P_WAIT, prog, args2)
+ prog = find_pg_tool(name)
+ if not prog:
+ raise Exception('Couldn\'t find %s' % name)
+ args2 = (os.path.basename(prog),) + args
+ return os.spawnv(os.P_WAIT, prog, args2)
def exec_pg_command_pipe(name, *args):
- prog = find_pg_tool(name)
- if not prog:
- raise Exception('Couldn\'t find %s' % name)
- if os.name == "nt":
- cmd = '"' + prog + '" ' + ' '.join(args)
- else:
- cmd = prog + ' ' + ' '.join(args)
- return os.popen2(cmd, 'b')
+ prog = find_pg_tool(name)
+ if not prog:
+ raise Exception('Couldn\'t find %s' % name)
+ if os.name == "nt":
+ cmd = '"' + prog + '" ' + ' '.join(args)
+ else:
+ cmd = prog + ' ' + ' '.join(args)
+ return os.popen2(cmd, 'b')
def exec_command_pipe(name, *args):
- prog = find_in_path(name)
- if not prog:
- raise Exception('Couldn\'t find %s' % name)
- if os.name == "nt":
- cmd = '"'+prog+'" '+' '.join(args)
- else:
- cmd = prog+' '+' '.join(args)
- return os.popen2(cmd, 'b')
+ prog = find_in_path(name)
+ if not prog:
+ raise Exception('Couldn\'t find %s' % name)
+ if os.name == "nt":
+ cmd = '"'+prog+'" '+' '.join(args)
+ else:
+ cmd = prog+' '+' '.join(args)
+ return os.popen2(cmd, 'b')
#----------------------------------------------------------
# File paths
@@ -169,89 +169,89 @@ def exec_command_pipe(name, *args):
#file_path_addons = os.path.join(file_path_root, 'addons')
def file_open(name, mode="r", subdir='addons', pathinfo=False):
- """Open a file from the Tiny ERP root, using a subdir folder.
-
- >>> file_open('hr/report/timesheer.xsl')
- >>> file_open('addons/hr/report/timesheet.xsl')
- >>> file_open('../../base/report/rml_template.xsl', subdir='addons/hr/report', pathinfo=True)
-
- @param name: name of the file
- @param mode: file open mode
- @param subdir: subdirectory
- @param pathinfo: if True returns tupple (fileobject, filepath)
-
- @return: fileobject if pathinfo is False else (fileobject, filepath)
- """
-
- adp = os.path.normcase(os.path.abspath(config['addons_path']))
- rtp = os.path.normcase(os.path.abspath(config['root_path']))
-
- if name.replace(os.path.sep, '/').startswith('addons/'):
- subdir = 'addons'
- name = name[7:]
-
- # First try to locate in addons_path
- if subdir:
- subdir2 = subdir
- if subdir2.replace(os.path.sep, '/').startswith('addons/'):
- subdir2 = subdir2[7:]
-
- subdir2 = (subdir2 != 'addons' or None) and subdir2
-
- try:
- if subdir2:
- fn = os.path.join(adp, subdir2, name)
- else:
- fn = os.path.join(adp, name)
- fn = os.path.normpath(fn)
- fo = file_open(fn, mode=mode, subdir=None, pathinfo=pathinfo)
- if pathinfo:
- return fo, fn
- return fo
- except IOError, e:
- pass
-
- if subdir:
- name = os.path.join(rtp, subdir, name)
- else:
- name = os.path.join(rtp, name)
-
- name = os.path.normpath(name)
-
- # Check for a zipfile in the path
- head = name
- zipname = False
- name2 = False
- while True:
- head, tail = os.path.split(head)
- if not tail:
- break
- if zipname:
- zipname = os.path.join(tail, zipname)
- else:
- zipname = tail
- if zipfile.is_zipfile(head+'.zip'):
- import StringIO
- zfile = zipfile.ZipFile(head+'.zip')
- try:
- fo = StringIO.StringIO(zfile.read(os.path.join(
- os.path.basename(head), zipname).replace(
- os.sep, '/')))
-
- if pathinfo:
- return fo, name
- return fo
- except:
- name2 = os.path.normpath(os.path.join(head + '.zip', zipname))
- pass
- for i in (name2, name):
- if i and os.path.isfile(i):
- fo = file(i, mode)
- if pathinfo:
- return fo, i
- return fo
-
- raise IOError, 'File not found : '+str(name)
+ """Open a file from the Tiny ERP root, using a subdir folder.
+
+ >>> file_open('hr/report/timesheer.xsl')
+ >>> file_open('addons/hr/report/timesheet.xsl')
+ >>> file_open('../../base/report/rml_template.xsl', subdir='addons/hr/report', pathinfo=True)
+
+ @param name: name of the file
+ @param mode: file open mode
+ @param subdir: subdirectory
+ @param pathinfo: if True returns tupple (fileobject, filepath)
+
+ @return: fileobject if pathinfo is False else (fileobject, filepath)
+ """
+
+ adp = os.path.normcase(os.path.abspath(config['addons_path']))
+ rtp = os.path.normcase(os.path.abspath(config['root_path']))
+
+ if name.replace(os.path.sep, '/').startswith('addons/'):
+ subdir = 'addons'
+ name = name[7:]
+
+ # First try to locate in addons_path
+ if subdir:
+ subdir2 = subdir
+ if subdir2.replace(os.path.sep, '/').startswith('addons/'):
+ subdir2 = subdir2[7:]
+
+ subdir2 = (subdir2 != 'addons' or None) and subdir2
+
+ try:
+ if subdir2:
+ fn = os.path.join(adp, subdir2, name)
+ else:
+ fn = os.path.join(adp, name)
+ fn = os.path.normpath(fn)
+ fo = file_open(fn, mode=mode, subdir=None, pathinfo=pathinfo)
+ if pathinfo:
+ return fo, fn
+ return fo
+ except IOError, e:
+ pass
+
+ if subdir:
+ name = os.path.join(rtp, subdir, name)
+ else:
+ name = os.path.join(rtp, name)
+
+ name = os.path.normpath(name)
+
+ # Check for a zipfile in the path
+ head = name
+ zipname = False
+ name2 = False
+ while True:
+ head, tail = os.path.split(head)
+ if not tail:
+ break
+ if zipname:
+ zipname = os.path.join(tail, zipname)
+ else:
+ zipname = tail
+ if zipfile.is_zipfile(head+'.zip'):
+ import StringIO
+ zfile = zipfile.ZipFile(head+'.zip')
+ try:
+ fo = StringIO.StringIO(zfile.read(os.path.join(
+ os.path.basename(head), zipname).replace(
+ os.sep, '/')))
+
+ if pathinfo:
+ return fo, name
+ return fo
+ except:
+ name2 = os.path.normpath(os.path.join(head + '.zip', zipname))
+ pass
+ for i in (name2, name):
+ if i and os.path.isfile(i):
+ fo = file(i, mode)
+ if pathinfo:
+ return fo, i
+ return fo
+
+ raise IOError, 'File not found : '+str(name)
#----------------------------------------------------------
@@ -294,244 +294,244 @@ def flatten(list):
# Emails
#----------------------------------------------------------
def email_send(email_from, email_to, subject, body, email_cc=None, email_bcc=None, on_error=False, reply_to=False, tinycrm=False):
- """Send an email."""
- if not email_cc:
- email_cc=[]
- if not email_bcc:
- email_bcc=[]
- import smtplib
- from email.MIMEText import MIMEText
- from email.MIMEMultipart import MIMEMultipart
- from email.Header import Header
- from email.Utils import formatdate, COMMASPACE
-
- msg = MIMEText(body or '', _charset='utf-8')
- msg['Subject'] = Header(subject.decode('utf8'), 'utf-8')
- msg['From'] = email_from
- del msg['Reply-To']
- if reply_to:
- msg['Reply-To'] = msg['From']+', '+reply_to
- msg['To'] = COMMASPACE.join(email_to)
- if email_cc:
- msg['Cc'] = COMMASPACE.join(email_cc)
- if email_bcc:
- msg['Bcc'] = COMMASPACE.join(email_bcc)
- msg['Date'] = formatdate(localtime=True)
- if tinycrm:
- msg['Message-Id'] = '<'+str(time.time())+'-tinycrm-'+str(tinycrm)+'@'+socket.gethostname()+'>'
- try:
- s = smtplib.SMTP()
- s.connect(config['smtp_server'])
- if config['smtp_user'] or config['smtp_password']:
- s.login(config['smtp_user'], config['smtp_password'])
- s.sendmail(email_from, flatten([email_to, email_cc, email_bcc]), msg.as_string())
- s.quit()
- except Exception, e:
- import logging
- logging.getLogger().error(str(e))
- return True
+ """Send an email."""
+ if not email_cc:
+ email_cc=[]
+ if not email_bcc:
+ email_bcc=[]
+ import smtplib
+ from email.MIMEText import MIMEText
+ from email.MIMEMultipart import MIMEMultipart
+ from email.Header import Header
+ from email.Utils import formatdate, COMMASPACE
+
+ msg = MIMEText(body or '', _charset='utf-8')
+ msg['Subject'] = Header(subject.decode('utf8'), 'utf-8')
+ msg['From'] = email_from
+ del msg['Reply-To']
+ if reply_to:
+ msg['Reply-To'] = msg['From']+', '+reply_to
+ msg['To'] = COMMASPACE.join(email_to)
+ if email_cc:
+ msg['Cc'] = COMMASPACE.join(email_cc)
+ if email_bcc:
+ msg['Bcc'] = COMMASPACE.join(email_bcc)
+ msg['Date'] = formatdate(localtime=True)
+ if tinycrm:
+ msg['Message-Id'] = '<'+str(time.time())+'-tinycrm-'+str(tinycrm)+'@'+socket.gethostname()+'>'
+ try:
+ s = smtplib.SMTP()
+ s.connect(config['smtp_server'])
+ if config['smtp_user'] or config['smtp_password']:
+ s.login(config['smtp_user'], config['smtp_password'])
+ s.sendmail(email_from, flatten([email_to, email_cc, email_bcc]), msg.as_string())
+ s.quit()
+ except Exception, e:
+ import logging
+ logging.getLogger().error(str(e))
+ return True
#----------------------------------------------------------
# Emails
#----------------------------------------------------------
def email_send_attach(email_from, email_to, subject, body, email_cc=None, email_bcc=None, on_error=False, reply_to=False, attach=None, tinycrm=False):
- """Send an email."""
- if not email_cc:
- email_cc=[]
- if not email_bcc:
- email_bcc=[]
- if not attach:
- attach=[]
- import smtplib
- from email.MIMEText import MIMEText
- from email.MIMEBase import MIMEBase
- from email.MIMEMultipart import MIMEMultipart
- from email.Header import Header
- from email.Utils import formatdate, COMMASPACE
- from email import Encoders
-
- msg = MIMEMultipart()
-
- msg['Subject'] = Header(subject.decode('utf8'), 'utf-8')
- msg['From'] = email_from
- del msg['Reply-To']
- if reply_to:
- msg['Reply-To'] = reply_to
- msg['To'] = COMMASPACE.join(email_to)
- if email_cc:
- msg['Cc'] = COMMASPACE.join(email_cc)
- if email_bcc:
- msg['Bcc'] = COMMASPACE.join(email_bcc)
- if tinycrm:
- msg['Message-Id'] = '<'+str(time.time())+'-tinycrm-'+str(tinycrm)+'@'+socket.gethostname()+'>'
- msg['Date'] = formatdate(localtime=True)
- msg.attach( MIMEText(body or '', _charset='utf-8') )
- for (fname,fcontent) in attach:
- part = MIMEBase('application', "octet-stream")
- part.set_payload( fcontent )
- Encoders.encode_base64(part)
- part.add_header('Content-Disposition', 'attachment; filename="%s"' % (fname,))
- msg.attach(part)
- try:
- s = smtplib.SMTP()
- s.connect(config['smtp_server'])
- if config['smtp_user'] or config['smtp_password']:
- s.login(config['smtp_user'], config['smtp_password'])
- s.sendmail(email_from, flatten([email_to, email_cc, email_bcc]), msg.as_string())
- s.quit()
- except Exception, e:
- import logging
- logging.getLogger().error(str(e))
- return True
+ """Send an email."""
+ if not email_cc:
+ email_cc=[]
+ if not email_bcc:
+ email_bcc=[]
+ if not attach:
+ attach=[]
+ import smtplib
+ from email.MIMEText import MIMEText
+ from email.MIMEBase import MIMEBase
+ from email.MIMEMultipart import MIMEMultipart
+ from email.Header import Header
+ from email.Utils import formatdate, COMMASPACE
+ from email import Encoders
+
+ msg = MIMEMultipart()
+
+ msg['Subject'] = Header(subject.decode('utf8'), 'utf-8')
+ msg['From'] = email_from
+ del msg['Reply-To']
+ if reply_to:
+ msg['Reply-To'] = reply_to
+ msg['To'] = COMMASPACE.join(email_to)
+ if email_cc:
+ msg['Cc'] = COMMASPACE.join(email_cc)
+ if email_bcc:
+ msg['Bcc'] = COMMASPACE.join(email_bcc)
+ if tinycrm:
+ msg['Message-Id'] = '<'+str(time.time())+'-tinycrm-'+str(tinycrm)+'@'+socket.gethostname()+'>'
+ msg['Date'] = formatdate(localtime=True)
+ msg.attach( MIMEText(body or '', _charset='utf-8') )
+ for (fname,fcontent) in attach:
+ part = MIMEBase('application', "octet-stream")
+ part.set_payload( fcontent )
+ Encoders.encode_base64(part)
+ part.add_header('Content-Disposition', 'attachment; filename="%s"' % (fname,))
+ msg.attach(part)
+ try:
+ s = smtplib.SMTP()
+ s.connect(config['smtp_server'])
+ if config['smtp_user'] or config['smtp_password']:
+ s.login(config['smtp_user'], config['smtp_password'])
+ s.sendmail(email_from, flatten([email_to, email_cc, email_bcc]), msg.as_string())
+ s.quit()
+ except Exception, e:
+ import logging
+ logging.getLogger().error(str(e))
+ return True
#----------------------------------------------------------
# SMS
#----------------------------------------------------------
# text must be latin-1 encoded
def sms_send(user, password, api_id, text, to):
- import urllib
- 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)
- print f.read()
- return True
+ import urllib
+ 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)
+ print f.read()
+ return True
#---------------------------------------------------------
# Class that stores an updateable string (used in wizards)
#---------------------------------------------------------
class UpdateableStr(local):
- def __init__(self, string=''):
- self.string = string
-
- def __str__(self):
- return str(self.string)
+ def __init__(self, string=''):
+ self.string = string
+
+ def __str__(self):
+ return str(self.string)
- def __repr__(self):
- return str(self.string)
+ def __repr__(self):
+ return str(self.string)
- def __nonzero__(self):
- return bool(self.string)
+ def __nonzero__(self):
+ return bool(self.string)
class UpdateableDict(local):
- '''Stores an updateable dict to use in wizards'''
+ '''Stores an updateable dict to use in wizards'''
- def __init__(self, dict=None):
- if dict is None:
- dict = {}
- self.dict = dict
+ def __init__(self, dict=None):
+ if dict is None:
+ dict = {}
+ self.dict = dict
- def __str__(self):
- return str(self.dict)
+ def __str__(self):
+ return str(self.dict)
- def __repr__(self):
- return str(self.dict)
+ def __repr__(self):
+ return str(self.dict)
- def clear(self):
- return self.dict.clear()
+ def clear(self):
+ return self.dict.clear()
- def keys(self):
- return self.dict.keys()
+ def keys(self):
+ return self.dict.keys()
- def __setitem__(self, i, y):
- self.dict.__setitem__(i, y)
+ def __setitem__(self, i, y):
+ self.dict.__setitem__(i, y)
- def __getitem__(self, i):
- return self.dict.__getitem__(i)
+ def __getitem__(self, i):
+ return self.dict.__getitem__(i)
- def copy(self):
- return self.dict.copy()
+ def copy(self):
+ return self.dict.copy()
- def iteritems(self):
- return self.dict.iteritems()
+ def iteritems(self):
+ return self.dict.iteritems()
- def iterkeys(self):
- return self.dict.iterkeys()
+ def iterkeys(self):
+ return self.dict.iterkeys()
- def itervalues(self):
- return self.dict.itervalues()
+ def itervalues(self):
+ return self.dict.itervalues()
- def pop(self, k, d=None):
- return self.dict.pop(k, d)
+ def pop(self, k, d=None):
+ return self.dict.pop(k, d)
- def popitem(self):
- return self.dict.popitem()
+ def popitem(self):
+ return self.dict.popitem()
- def setdefault(self, k, d=None):
- return self.dict.setdefault(k, d)
+ def setdefault(self, k, d=None):
+ return self.dict.setdefault(k, d)
- def update(self, E, **F):
- return self.dict.update(E, F)
+ def update(self, E, **F):
+ return self.dict.update(E, F)
- def values(self):
- return self.dict.values()
+ def values(self):
+ return self.dict.values()
- def get(self, k, d=None):
- return self.dict.get(k, d)
+ def get(self, k, d=None):
+ return self.dict.get(k, d)
- def has_key(self, k):
- return self.dict.has_key(k)
+ def has_key(self, k):
+ return self.dict.has_key(k)
- def items(self):
- return self.dict.items()
+ def items(self):
+ return self.dict.items()
- def __cmp__(self, y):
- return self.dict.__cmp__(y)
+ def __cmp__(self, y):
+ return self.dict.__cmp__(y)
- def __contains__(self, k):
- return self.dict.__contains__(k)
+ def __contains__(self, k):
+ return self.dict.__contains__(k)
- def __delitem__(self, y):
- return self.dict.__delitem__(y)
+ def __delitem__(self, y):
+ return self.dict.__delitem__(y)
- def __eq__(self, y):
- return self.dict.__eq__(y)
+ def __eq__(self, y):
+ return self.dict.__eq__(y)
- def __ge__(self, y):
- return self.dict.__ge__(y)
+ def __ge__(self, y):
+ return self.dict.__ge__(y)
- def __getitem__(self, y):
- return self.dict.__getitem__(y)
+ def __getitem__(self, y):
+ return self.dict.__getitem__(y)
- def __gt__(self, y):
- return self.dict.__gt__(y)
+ def __gt__(self, y):
+ return self.dict.__gt__(y)
- def __hash__(self):
- return self.dict.__hash__()
+ def __hash__(self):
+ return self.dict.__hash__()
- def __iter__(self):
- return self.dict.__iter__()
+ def __iter__(self):
+ return self.dict.__iter__()
- def __le__(self, y):
- return self.dict.__le__(y)
+ def __le__(self, y):
+ return self.dict.__le__(y)
- def __len__(self):
- return self.dict.__len__()
+ def __len__(self):
+ return self.dict.__len__()
- def __lt__(self, y):
- return self.dict.__lt__(y)
+ def __lt__(self, y):
+ return self.dict.__lt__(y)
- def __ne__(self, y):
- return self.dict.__ne__(y)
+ def __ne__(self, y):
+ return self.dict.__ne__(y)
# Don't use ! Use res.currency.round()
class currency(float):
- def __init__(self, value, accuracy=2, rounding=None):
- if rounding is None:
- rounding=10**-accuracy
- self.rounding=rounding
- self.accuracy=accuracy
+ def __init__(self, value, accuracy=2, rounding=None):
+ if rounding is None:
+ rounding=10**-accuracy
+ self.rounding=rounding
+ self.accuracy=accuracy
- def __new__(cls, value, accuracy=2, rounding=None):
- return float.__new__(cls, round(value, accuracy))
+ def __new__(cls, value, accuracy=2, rounding=None):
+ return float.__new__(cls, round(value, accuracy))
- #def __str__(self):
- # display_value = int(self*(10**(-self.accuracy))/self.rounding)*self.rounding/(10**(-self.accuracy))
- # return str(display_value)
+ #def __str__(self):
+ # display_value = int(self*(10**(-self.accuracy))/self.rounding)*self.rounding/(10**(-self.accuracy))
+ # return str(display_value)
#
@@ -539,99 +539,99 @@ class currency(float):
# Timeout: 0 = no timeout, otherwise in seconds
#
class cache(object):
- def __init__(self, timeout=10000, skiparg=2):
- self.timeout = timeout
- self.cache = {}
-
- def __call__(self, fn):
- arg_names = inspect.getargspec(fn)[0][2:]
- def cached_result(self2, cr=None, *args, **kwargs):
- if cr is None:
- self.cache = {}
- return True
-
- # Update named arguments with positional argument values
- kwargs.update(dict(zip(arg_names, args)))
- kwargs = kwargs.items()
- kwargs.sort()
-
- # Work out key as a tuple of ('argname', value) pairs
- key = (('dbname', cr.dbname),) + tuple(kwargs)
-
- # Check cache and return cached value if possible
- if key in self.cache:
- (value, last_time) = self.cache[key]
- mintime = time.time() - self.timeout
- if self.timeout <= 0 or mintime <= last_time:
- return value
-
- # Work out new value, cache it and return it
- # Should copy() this value to avoid futur modf of the cacle ?
- result = fn(self2,cr,**dict(kwargs))
-
- self.cache[key] = (result, time.time())
- return result
- return cached_result
+ def __init__(self, timeout=10000, skiparg=2):
+ self.timeout = timeout
+ self.cache = {}
+
+ def __call__(self, fn):
+ arg_names = inspect.getargspec(fn)[0][2:]
+ def cached_result(self2, cr=None, *args, **kwargs):
+ if cr is None:
+ self.cache = {}
+ return True
+
+ # Update named arguments with positional argument values
+ kwargs.update(dict(zip(arg_names, args)))
+ kwargs = kwargs.items()
+ kwargs.sort()
+
+ # Work out key as a tuple of ('argname', value) pairs
+ key = (('dbname', cr.dbname),) + tuple(kwargs)
+
+ # Check cache and return cached value if possible
+ if key in self.cache:
+ (value, last_time) = self.cache[key]
+ mintime = time.time() - self.timeout
+ if self.timeout <= 0 or mintime <= last_time:
+ return value
+
+ # Work out new value, cache it and return it
+ # Should copy() this value to avoid futur modf of the cacle ?
+ result = fn(self2,cr,**dict(kwargs))
+
+ self.cache[key] = (result, time.time())
+ return result
+ return cached_result
def to_xml(s):
- return s.replace('&','&amp;').replace('<','&lt;').replace('>','&gt;')
+ return s.replace('&','&amp;').replace('<','&lt;').replace('>','&gt;')
def get_languages():
- languages={
- 'zh_CN': 'Chinese (CN)',
- 'zh_TW': 'Chinese (TW)',
- 'cs_CZ': 'Czech',
- 'de_DE': 'Deutsch',
- 'es_AR': 'Español (Argentina)',
- 'es_ES': 'Español (España)',
- 'fr_FR': 'Français',
- 'fr_CH': 'Français (Suisse)',
- 'en_EN': 'English (default)',
- 'hu_HU': 'Hungarian',
- 'it_IT': 'Italiano',
- 'pt_BR': 'Portugese (Brasil)',
- 'pt_PT': 'Portugese (Portugal)',
- 'nl_NL': 'Nederlands',
- 'ro_RO': 'Romanian',
- 'ru_RU': 'Russian',
- 'sv_SE': 'Swedish',
- }
- return languages
+ languages={
+ 'zh_CN': 'Chinese (CN)',
+ 'zh_TW': 'Chinese (TW)',
+ 'cs_CZ': 'Czech',
+ 'de_DE': 'Deutsch',
+ 'es_AR': 'Español (Argentina)',
+ 'es_ES': 'Español (España)',
+ 'fr_FR': 'Français',
+ 'fr_CH': 'Français (Suisse)',
+ 'en_EN': 'English (default)',
+ 'hu_HU': 'Hungarian',
+ 'it_IT': 'Italiano',
+ 'pt_BR': 'Portugese (Brasil)',
+ 'pt_PT': 'Portugese (Portugal)',
+ 'nl_NL': 'Nederlands',
+ 'ro_RO': 'Romanian',
+ 'ru_RU': 'Russian',
+ 'sv_SE': 'Swedish',
+ }
+ return languages
def scan_languages():
- import glob
- file_list = [os.path.splitext(os.path.basename(f))[0] for f in glob.glob(os.path.join(config['root_path'], 'i18n', '*.csv'))]
- lang_dict = get_languages()
- return [(lang, lang_dict.get(lang, lang)) for lang in file_list]
+ import glob
+ file_list = [os.path.splitext(os.path.basename(f))[0] for f in glob.glob(os.path.join(config['root_path'], 'i18n', '*.csv'))]
+ lang_dict = get_languages()
+ return [(lang, lang_dict.get(lang, lang)) for lang in file_list]
def get_user_companies(cr, user):
- def _get_company_children(cr, ids):
- if not ids:
- return []
- cr.execute('SELECT id FROM res_company WHERE parent_id = any(array[%s])' %(','.join([str(x) for x in ids]),))
- res=[x[0] for x in cr.fetchall()]
- res.extend(_get_company_children(cr, res))
- return res
- cr.execute('SELECT comp.id FROM res_company AS comp, res_users AS u WHERE u.id = %d AND comp.id = u.company_id' % (user,))
- compids=[cr.fetchone()[0]]
- compids.extend(_get_company_children(cr, compids))
- return compids
+ def _get_company_children(cr, ids):
+ if not ids:
+ return []
+ cr.execute('SELECT id FROM res_company WHERE parent_id = any(array[%s])' %(','.join([str(x) for x in ids]),))
+ res=[x[0] for x in cr.fetchall()]
+ res.extend(_get_company_children(cr, res))
+ return res
+ cr.execute('SELECT comp.id FROM res_company AS comp, res_users AS u WHERE u.id = %d AND comp.id = u.company_id' % (user,))
+ compids=[cr.fetchone()[0]]
+ compids.extend(_get_company_children(cr, compids))
+ return compids
def mod10r(number):
- """
- Input number : account or invoice number
- Output return: the same number completed with the recursive mod10
- key
- """
- codec=[0,9,4,6,8,2,7,1,3,5]
- report = 0
- result=""
- for digit in number:
- result += digit
- if digit.isdigit():
- report = codec[ (int(digit) + report) % 10 ]
- return result + str((10 - report) % 10)
+ """
+ Input number : account or invoice number
+ Output return: the same number completed with the recursive mod10
+ key
+ """
+ codec=[0,9,4,6,8,2,7,1,3,5]
+ report = 0
+ result=""
+ for digit in number:
+ result += digit
+ if digit.isdigit():
+ report = codec[ (int(digit) + report) % 10 ]
+ return result + str((10 - report) % 10)
diff --git a/bin/tools/translate.py b/bin/tools/translate.py
index 123d673d238..8b9409dad1a 100644
--- a/bin/tools/translate.py
+++ b/bin/tools/translate.py
@@ -38,7 +38,7 @@ import inspect
import mx.DateTime as mxdt
class UNIX_LINE_TERMINATOR(csv.excel):
- lineterminator = '\n'
+ lineterminator = '\n'
csv.register_dialect("UNIX", UNIX_LINE_TERMINATOR)
@@ -46,15 +46,15 @@ csv.register_dialect("UNIX", UNIX_LINE_TERMINATOR)
# TODO: a caching method
#
def translate(cr, name, source_type, lang, source=None):
- if source and name:
- cr.execute('select value from ir_translation where lang=%s and type=%s and name=%s and src=%s', (lang, source_type, str(name), source))
- elif name:
- cr.execute('select value from ir_translation where lang=%s and type=%s and name=%s', (lang, source_type, str(name)))
- elif source:
- cr.execute('select value from ir_translation where lang=%s and type=%s and src=%s', (lang, source_type, source))
- res_trans = cr.fetchone()
- res = res_trans and res_trans[0] or False
- return res
+ if source and name:
+ cr.execute('select value from ir_translation where lang=%s and type=%s and name=%s and src=%s', (lang, source_type, str(name), source))
+ elif name:
+ cr.execute('select value from ir_translation where lang=%s and type=%s and name=%s', (lang, source_type, str(name)))
+ elif source:
+ cr.execute('select value from ir_translation where lang=%s and type=%s and src=%s', (lang, source_type, source))
+ res_trans = cr.fetchone()
+ res = res_trans and res_trans[0] or False
+ return res
class GettextAlias(object):
def __call__(self, source):
@@ -71,469 +71,469 @@ _ = GettextAlias()
# class to handle po files
class TinyPoFile(object):
- def __init__(self, buffer):
- self.buffer = buffer
-
- def __iter__(self):
- self.buffer.seek(0)
- self.lines = self.buffer.readlines()
- self.first = True
- return self
-
- def next(self):
- def unquote(str):
- return str[1:-1].replace("\\n", "\n") \
- .replace('\\"', "\"")
-
- type = name = res_id = source = trad = None
-
- line = None
- while not line:
- if 0 == len(self.lines):
- raise StopIteration()
- line = self.lines.pop(0).strip()
-
- while line.startswith('#'):
- if line.startswith('#:'):
- type, name, res_id = line[2:].strip().split(':')
- line = self.lines.pop(0).strip()
- if not line.startswith('msgid'):
- raise Exception("malformed file")
- source = line[7:-1]
- line = self.lines.pop(0).strip()
- if not source and self.first:
- # if the source is "" and it's the first msgid, it's the special
- # msgstr with the informations about the traduction and the
- # traductor; we skip it
- while line:
- line = self.lines.pop(0).strip()
- return next()
-
- while not line.startswith('msgstr'):
- if not line:
- raise Exception('malformed file')
- source += unquote(line)
- line = self.lines.pop(0).strip()
-
- trad = line[8:-1]
- line = self.lines.pop(0).strip()
- while line:
- trad += unquote(line)
- line = self.lines.pop(0).strip()
-
- self.first = False
- return type, name, res_id, source, trad
-
- def write_infos(self, modules):
- import release
- self.buffer.write("# Translation of %(project)s.\n" \
- "# This file containt the translation of the following modules:\n" \
- "%(modules)s" \
- "#\n" \
- "msgid \"\"\n" \
- "msgstr \"\"\n" \
- "\"Project-Id-Version: %(project)s %(version)s\"\n" \
- "\"Report-Msgid-Bugs-To: %(bugmail)s\"\n" \
- "\"POT-Creation-Date: %(now)s\"\n" \
- "\"PO-Revision-Date: %(now)s\"\n" \
- "\"Last-Translator: <>\"\n" \
- "\"Language-Team: \"\n" \
- "\"MIME-Version: 1.0\"\n" \
- "\"Content-Type: text/plain; charset=UTF-8\"\n" \
- "\"Content-Transfer-Encoding: \"\n" \
- "\"Plural-Forms: \"\n" \
- "\n"
-
- % { 'project': release.description,
- 'version': release.version,
- 'modules': reduce(lambda s, m: s + "#\t* %s\n" % m, modules, ""),
- 'bugmail': 'support@tinyerp.com', #TODO: use variable from release
- 'now': mxdt.ISO.strUTC(mxdt.ISO.DateTime.utc()),
- }
- )
-
- def write(self, module, type, name, res_id, source, trad):
- def quote(str):
- return '"%s"' % str.replace('"','\\"') \
- .replace('\n', '\\n"\n"')
-
- self.buffer.write("#. module: %s\n" \
- "#, python-format\n" \
- "#: %s:%s:%s\n" \
- "msgid %s\n" \
- "msgstr %s\n\n" \
- % (module, type, name, str(res_id), quote(source), quote(trad))
- )
-
+ def __init__(self, buffer):
+ self.buffer = buffer
+
+ def __iter__(self):
+ self.buffer.seek(0)
+ self.lines = self.buffer.readlines()
+ self.first = True
+ return self
+
+ def next(self):
+ def unquote(str):
+ return str[1:-1].replace("\\n", "\n") \
+ .replace('\\"', "\"")
+
+ type = name = res_id = source = trad = None
+
+ line = None
+ while not line:
+ if 0 == len(self.lines):
+ raise StopIteration()
+ line = self.lines.pop(0).strip()
+
+ while line.startswith('#'):
+ if line.startswith('#:'):
+ type, name, res_id = line[2:].strip().split(':')
+ line = self.lines.pop(0).strip()
+ if not line.startswith('msgid'):
+ raise Exception("malformed file")
+ source = line[7:-1]
+ line = self.lines.pop(0).strip()
+ if not source and self.first:
+ # if the source is "" and it's the first msgid, it's the special
+ # msgstr with the informations about the traduction and the
+ # traductor; we skip it
+ while line:
+ line = self.lines.pop(0).strip()
+ return next()
+
+ while not line.startswith('msgstr'):
+ if not line:
+ raise Exception('malformed file')
+ source += unquote(line)
+ line = self.lines.pop(0).strip()
+
+ trad = line[8:-1]
+ line = self.lines.pop(0).strip()
+ while line:
+ trad += unquote(line)
+ line = self.lines.pop(0).strip()
+
+ self.first = False
+ return type, name, res_id, source, trad
+
+ def write_infos(self, modules):
+ import release
+ self.buffer.write("# Translation of %(project)s.\n" \
+ "# This file containt the translation of the following modules:\n" \
+ "%(modules)s" \
+ "#\n" \
+ "msgid \"\"\n" \
+ "msgstr \"\"\n" \
+ "\"Project-Id-Version: %(project)s %(version)s\"\n" \
+ "\"Report-Msgid-Bugs-To: %(bugmail)s\"\n" \
+ "\"POT-Creation-Date: %(now)s\"\n" \
+ "\"PO-Revision-Date: %(now)s\"\n" \
+ "\"Last-Translator: <>\"\n" \
+ "\"Language-Team: \"\n" \
+ "\"MIME-Version: 1.0\"\n" \
+ "\"Content-Type: text/plain; charset=UTF-8\"\n" \
+ "\"Content-Transfer-Encoding: \"\n" \
+ "\"Plural-Forms: \"\n" \
+ "\n"
+
+ % { 'project': release.description,
+ 'version': release.version,
+ 'modules': reduce(lambda s, m: s + "#\t* %s\n" % m, modules, ""),
+ 'bugmail': 'support@tinyerp.com', #TODO: use variable from release
+ 'now': mxdt.ISO.strUTC(mxdt.ISO.DateTime.utc()),
+ }
+ )
+
+ def write(self, module, type, name, res_id, source, trad):
+ def quote(str):
+ return '"%s"' % str.replace('"','\\"') \
+ .replace('\n', '\\n"\n"')
+
+ self.buffer.write("#. module: %s\n" \
+ "#, python-format\n" \
+ "#: %s:%s:%s\n" \
+ "msgid %s\n" \
+ "msgstr %s\n\n" \
+ % (module, type, name, str(res_id), quote(source), quote(trad))
+ )
+
# Methods to export the translation file
def trans_export(lang, modules, buffer, format, dbname=None):
- trans = trans_generate(lang, modules, dbname)
- if format == 'csv':
- writer=csv.writer(buffer, 'UNIX')
- for row in trans:
- writer.writerow(row)
- elif format == 'po':
- trans.pop(0)
- writer = tools.TinyPoFile(buffer)
- writer.write_infos(modules)
- for module, type, name, res_id, src, trad in trans:
- writer.write(module, type, name, res_id, src, trad)
- else:
- raise Exception(_('Bad file format'))
- del trans
-
+ trans = trans_generate(lang, modules, dbname)
+ if format == 'csv':
+ writer=csv.writer(buffer, 'UNIX')
+ for row in trans:
+ writer.writerow(row)
+ elif format == 'po':
+ trans.pop(0)
+ writer = tools.TinyPoFile(buffer)
+ writer.write_infos(modules)
+ for module, type, name, res_id, src, trad in trans:
+ writer.write(module, type, name, res_id, src, trad)
+ else:
+ raise Exception(_('Bad file format'))
+ del trans
+
def trans_parse_xsl(de):
- res = []
- for n in [i for i in de.childNodes if (i.nodeType == i.ELEMENT_NODE)]:
- if n.hasAttribute("t"):
- for m in [j for j in n.childNodes if (j.nodeType == j.TEXT_NODE)]:
- l = m.data.strip().replace('\n',' ')
- if len(l):
- res.append(l.encode("utf8"))
- res.extend(trans_parse_xsl(n))
- return res
+ res = []
+ for n in [i for i in de.childNodes if (i.nodeType == i.ELEMENT_NODE)]:
+ if n.hasAttribute("t"):
+ for m in [j for j in n.childNodes if (j.nodeType == j.TEXT_NODE)]:
+ l = m.data.strip().replace('\n',' ')
+ if len(l):
+ res.append(l.encode("utf8"))
+ res.extend(trans_parse_xsl(n))
+ return res
def trans_parse_rml(de):
- res = []
- for n in [i for i in de.childNodes if (i.nodeType == i.ELEMENT_NODE)]:
- for m in [j for j in n.childNodes if (j.nodeType == j.TEXT_NODE)]:
- string_list = [s.replace('\n', ' ').strip() for s in re.split('\[\[.+?\]\]', m.data)]
- for s in string_list:
- if s:
- res.append(s.encode("utf8"))
- res.extend(trans_parse_rml(n))
- return res
+ res = []
+ for n in [i for i in de.childNodes if (i.nodeType == i.ELEMENT_NODE)]:
+ for m in [j for j in n.childNodes if (j.nodeType == j.TEXT_NODE)]:
+ string_list = [s.replace('\n', ' ').strip() for s in re.split('\[\[.+?\]\]', m.data)]
+ for s in string_list:
+ if s:
+ res.append(s.encode("utf8"))
+ res.extend(trans_parse_rml(n))
+ return res
def trans_parse_view(de):
- res = []
- if de.hasAttribute("string"):
- s = de.getAttribute('string')
- if s:
- res.append(s.encode("utf8"))
- if de.hasAttribute("sum"):
- s = de.getAttribute('sum')
- if s:
- res.append(s.encode("utf8"))
- for n in [i for i in de.childNodes if (i.nodeType == i.ELEMENT_NODE)]:
- res.extend(trans_parse_view(n))
- return res
+ res = []
+ if de.hasAttribute("string"):
+ s = de.getAttribute('string')
+ if s:
+ res.append(s.encode("utf8"))
+ if de.hasAttribute("sum"):
+ s = de.getAttribute('sum')
+ if s:
+ res.append(s.encode("utf8"))
+ for n in [i for i in de.childNodes if (i.nodeType == i.ELEMENT_NODE)]:
+ res.extend(trans_parse_view(n))
+ return res
# tests whether an object is in a list of modules
def in_modules(object_name, modules):
- if 'all' in modules:
- return True
-
- module_dict = {
- 'ir': 'base',
- 'res': 'base',
- 'workflow': 'base',
- }
- module = object_name.split('.')[0]
- module = module_dict.get(module, module)
- return module in modules
+ if 'all' in modules:
+ return True
+
+ module_dict = {
+ 'ir': 'base',
+ 'res': 'base',
+ 'workflow': 'base',
+ }
+ module = object_name.split('.')[0]
+ module = module_dict.get(module, module)
+ return module in modules
def trans_generate(lang, modules, dbname=None):
- logger = netsvc.Logger()
- if not dbname:
- dbname=tools.config['db_name']
- pool = pooler.get_pool(dbname)
- trans_obj = pool.get('ir.translation')
- model_data_obj = pool.get('ir.model.data')
- cr = pooler.get_db(dbname).cursor()
- uid = 1
- l = pool.obj_pool.items()
- l.sort()
-
- query = 'SELECT name, model, res_id, module' \
- ' FROM ir_model_data'
- if not 'all' in modules:
- query += ' WHERE module IN (%s)' % ','.join(['%s']*len(modules))
- query += ' ORDER BY module, model, name'
-
- query_param = not 'all' in modules and modules or None
- cr.execute(query, query_param)
-
- #if 'all' in modules:
- # cr.execute('select name,model,res_id,module from ir_model_data')
- #else:
- # cr.execute('select name,model,res_id,module from ir_model_data where module in ('+','.join(['%s']*len(modules))+')', modules)
-
-
- _to_translate = []
- def push_translation(module, type, name, id, source):
- tuple = (module, type, name, id, source)
- if not tuple in _to_translate:
- _to_translate.append(tuple)
-
-
- for (xml_name,model,res_id,module) in cr.fetchall():
- xml_name = module+'.'+xml_name
- obj = pool.get(model).browse(cr, uid, res_id)
- if model=='ir.ui.view':
- d = xml.dom.minidom.parseString(obj.arch)
- for t in trans_parse_view(d.documentElement):
- push_translation(module, 'view', obj.model, 0, t)
- elif model=='ir.actions.wizard':
- service_name = 'wizard.'+obj.wiz_name
- obj2 = netsvc._service[service_name]
- for state_name, state_def in obj2.states.iteritems():
- if 'result' in state_def:
- result = state_def['result']
- if result['type'] != 'form':
- continue
- name = obj.wiz_name + ',' + state_name
-
- # export fields
- for field_name, field_def in result['fields'].iteritems():
- if 'string' in field_def:
- source = field_def['string']
- res_name = name + ',' + field_name
- push_translation(module, 'wizard_field', res_name, 0, source)
-
- # export arch
- arch = result['arch']
- if not isinstance(arch, UpdateableStr):
- d = xml.dom.minidom.parseString(arch)
- for t in trans_parse_view(d.documentElement):
- push_translation(module, 'wizard_view', name, 0, t)
-
- # export button labels
- for but_args in result['state']:
- button_name = but_args[0]
- button_label = but_args[1]
- res_name = name + ',' + button_name
- push_translation(module, 'wizard_button', res_name, 0, button_label)
-
- elif model=='ir.model.fields':
- field_name = obj.name
- field_def = pool.get(obj.model)._columns[field_name]
-
- name = obj.model + "," + field_name
- push_translation(module, 'field', name, 0, field_def.string.encode('utf8'))
-
- if field_def.help:
- push_translation(module, 'help', name, 0, field_def.help.encode('utf8'))
-
- if field_def.translate:
- ids = pool.get(obj.model).search(cr, uid, [])
- obj_values = pool.get(obj.model).read(cr, uid, ids, [field_name])
- for obj_value in obj_values:
- res_id = obj_value['id']
- if obj.name in ('ir.model', 'ir.ui.menu'):
- res_id = 0
- model_data_ids = model_data_obj.search(cr, uid, [
- ('model', '=', model),
- ('res_id', '=', res_id),
- ])
- if not model_data_ids:
- push_translation(module, 'model', name, 0, obj_value[field_name])
-
- if hasattr(field_def, 'selection') and isinstance(field_def.selection, (list, tuple)):
- for key, val in field_def.selection:
- push_translation(module, 'selection', name, 0, val.encode('utf8'))
-
- elif model=='ir.actions.report.xml':
- name = obj.report_name
- fname = ""
- if obj.report_rml:
- fname = obj.report_rml
- parse_func = trans_parse_rml
- report_type = "rml"
- elif obj.report_xsl:
- fname = obj.report_xsl
- parse_func = trans_parse_xsl
- report_type = "xsl"
- try:
- xmlstr = tools.file_open(fname).read()
- d = xml.dom.minidom.parseString(xmlstr)
- for t in parse_func(d.documentElement):
- push_translation(module, report_type, name, 0, t)
- except IOError:
- if fname:
- logger.notifyChannel("init", netsvc.LOG_WARNING, "couldn't export translation for report %s %s %s" % (name, report_type, fname))
-
- for constraint in pool.get(model)._constraints:
- msg = constraint[1]
- push_translation(module, 'constraint', model, 0, msg.encode('utf8'))
-
- for field_name,field_def in pool.get(model)._columns.items():
- if field_def.translate:
- name = model + "," + field_name
- trad = getattr(obj, field_name) or ''
- push_translation(module, 'model', name, xml_name, trad)
-
- # parse source code for _() calls
- def get_module_from_path(path):
- relative_addons_path = tools.config['addons_path'][len(tools.config['root_path'])+1:]
- if path.startswith(relative_addons_path):
- path = path[len(relative_addons_path)+1:]
- return path.split(os.path.sep)[0]
- return 'base' # files that are not in a module are considered as being in 'base' module
-
- modobj = pool.get('ir.module.module')
- for root, dirs, files in os.walk(tools.config['root_path']):
- for fname in fnmatch.filter(files, '*.py'):
- fabsolutepath = join(root, fname)
- frelativepath = fabsolutepath[len(tools.config['root_path'])+1:]
- module = get_module_from_path(frelativepath)
- is_mod_installed = modobj.search(cr, uid, [('state', '=', 'installed'), ('name', '=', module)]) <> []
- if (('all' in modules) or (module in modules)) and is_mod_installed:
- code_string = tools.file_open(fabsolutepath, subdir='').read()
- iter = re.finditer(
- '[^a-zA-Z0-9_]_\([\s]*["\'](.+?)["\'][\s]*\)',
- code_string)
- for i in iter:
- push_translation(module, 'code', frelativepath, 0, i.group(1).encode('utf8'))
-
-
- out = [["module","type","name","res_id","src","value"]] # header
- # translate strings marked as to be translated
- for module, type, name, id, source in _to_translate:
- trans = trans_obj._get_source(cr, uid, name, type, lang, source)
- out.append([module, type, name, id, source, trans or ''])
-
- cr.close()
- return out
+ logger = netsvc.Logger()
+ if not dbname:
+ dbname=tools.config['db_name']
+ pool = pooler.get_pool(dbname)
+ trans_obj = pool.get('ir.translation')
+ model_data_obj = pool.get('ir.model.data')
+ cr = pooler.get_db(dbname).cursor()
+ uid = 1
+ l = pool.obj_pool.items()
+ l.sort()
+
+ query = 'SELECT name, model, res_id, module' \
+ ' FROM ir_model_data'
+ if not 'all' in modules:
+ query += ' WHERE module IN (%s)' % ','.join(['%s']*len(modules))
+ query += ' ORDER BY module, model, name'
+
+ query_param = not 'all' in modules and modules or None
+ cr.execute(query, query_param)
+
+ #if 'all' in modules:
+ # cr.execute('select name,model,res_id,module from ir_model_data')
+ #else:
+ # cr.execute('select name,model,res_id,module from ir_model_data where module in ('+','.join(['%s']*len(modules))+')', modules)
+
+
+ _to_translate = []
+ def push_translation(module, type, name, id, source):
+ tuple = (module, type, name, id, source)
+ if not tuple in _to_translate:
+ _to_translate.append(tuple)
+
+
+ for (xml_name,model,res_id,module) in cr.fetchall():
+ xml_name = module+'.'+xml_name
+ obj = pool.get(model).browse(cr, uid, res_id)
+ if model=='ir.ui.view':
+ d = xml.dom.minidom.parseString(obj.arch)
+ for t in trans_parse_view(d.documentElement):
+ push_translation(module, 'view', obj.model, 0, t)
+ elif model=='ir.actions.wizard':
+ service_name = 'wizard.'+obj.wiz_name
+ obj2 = netsvc._service[service_name]
+ for state_name, state_def in obj2.states.iteritems():
+ if 'result' in state_def:
+ result = state_def['result']
+ if result['type'] != 'form':
+ continue
+ name = obj.wiz_name + ',' + state_name
+
+ # export fields
+ for field_name, field_def in result['fields'].iteritems():
+ if 'string' in field_def:
+ source = field_def['string']
+ res_name = name + ',' + field_name
+ push_translation(module, 'wizard_field', res_name, 0, source)
+
+ # export arch
+ arch = result['arch']
+ if not isinstance(arch, UpdateableStr):
+ d = xml.dom.minidom.parseString(arch)
+ for t in trans_parse_view(d.documentElement):
+ push_translation(module, 'wizard_view', name, 0, t)
+
+ # export button labels
+ for but_args in result['state']:
+ button_name = but_args[0]
+ button_label = but_args[1]
+ res_name = name + ',' + button_name
+ push_translation(module, 'wizard_button', res_name, 0, button_label)
+
+ elif model=='ir.model.fields':
+ field_name = obj.name
+ field_def = pool.get(obj.model)._columns[field_name]
+
+ name = obj.model + "," + field_name
+ push_translation(module, 'field', name, 0, field_def.string.encode('utf8'))
+
+ if field_def.help:
+ push_translation(module, 'help', name, 0, field_def.help.encode('utf8'))
+
+ if field_def.translate:
+ ids = pool.get(obj.model).search(cr, uid, [])
+ obj_values = pool.get(obj.model).read(cr, uid, ids, [field_name])
+ for obj_value in obj_values:
+ res_id = obj_value['id']
+ if obj.name in ('ir.model', 'ir.ui.menu'):
+ res_id = 0
+ model_data_ids = model_data_obj.search(cr, uid, [
+ ('model', '=', model),
+ ('res_id', '=', res_id),
+ ])
+ if not model_data_ids:
+ push_translation(module, 'model', name, 0, obj_value[field_name])
+
+ if hasattr(field_def, 'selection') and isinstance(field_def.selection, (list, tuple)):
+ for key, val in field_def.selection:
+ push_translation(module, 'selection', name, 0, val.encode('utf8'))
+
+ elif model=='ir.actions.report.xml':
+ name = obj.report_name
+ fname = ""
+ if obj.report_rml:
+ fname = obj.report_rml
+ parse_func = trans_parse_rml
+ report_type = "rml"
+ elif obj.report_xsl:
+ fname = obj.report_xsl
+ parse_func = trans_parse_xsl
+ report_type = "xsl"
+ try:
+ xmlstr = tools.file_open(fname).read()
+ d = xml.dom.minidom.parseString(xmlstr)
+ for t in parse_func(d.documentElement):
+ push_translation(module, report_type, name, 0, t)
+ except IOError:
+ if fname:
+ logger.notifyChannel("init", netsvc.LOG_WARNING, "couldn't export translation for report %s %s %s" % (name, report_type, fname))
+
+ for constraint in pool.get(model)._constraints:
+ msg = constraint[1]
+ push_translation(module, 'constraint', model, 0, msg.encode('utf8'))
+
+ for field_name,field_def in pool.get(model)._columns.items():
+ if field_def.translate:
+ name = model + "," + field_name
+ trad = getattr(obj, field_name) or ''
+ push_translation(module, 'model', name, xml_name, trad)
+
+ # parse source code for _() calls
+ def get_module_from_path(path):
+ relative_addons_path = tools.config['addons_path'][len(tools.config['root_path'])+1:]
+ if path.startswith(relative_addons_path):
+ path = path[len(relative_addons_path)+1:]
+ return path.split(os.path.sep)[0]
+ return 'base' # files that are not in a module are considered as being in 'base' module
+
+ modobj = pool.get('ir.module.module')
+ for root, dirs, files in os.walk(tools.config['root_path']):
+ for fname in fnmatch.filter(files, '*.py'):
+ fabsolutepath = join(root, fname)
+ frelativepath = fabsolutepath[len(tools.config['root_path'])+1:]
+ module = get_module_from_path(frelativepath)
+ is_mod_installed = modobj.search(cr, uid, [('state', '=', 'installed'), ('name', '=', module)]) <> []
+ if (('all' in modules) or (module in modules)) and is_mod_installed:
+ code_string = tools.file_open(fabsolutepath, subdir='').read()
+ iter = re.finditer(
+ '[^a-zA-Z0-9_]_\([\s]*["\'](.+?)["\'][\s]*\)',
+ code_string)
+ for i in iter:
+ push_translation(module, 'code', frelativepath, 0, i.group(1).encode('utf8'))
+
+
+ out = [["module","type","name","res_id","src","value"]] # header
+ # translate strings marked as to be translated
+ for module, type, name, id, source in _to_translate:
+ trans = trans_obj._get_source(cr, uid, name, type, lang, source)
+ out.append([module, type, name, id, source, trans or ''])
+
+ cr.close()
+ return out
def trans_load(db_name, filename, lang, strict=False):
- logger = netsvc.Logger()
- try:
- fileobj = open(filename,'r')
- fileformat = os.path.splitext(filename)[-1][1:].lower()
- r = trans_load_data(db_name, fileobj, fileformat, lang, strict=False)
- fileobj.close()
- return r
- except IOError:
- logger.notifyChannel("init", netsvc.LOG_ERROR, "couldn't read file")
- return None
+ logger = netsvc.Logger()
+ try:
+ fileobj = open(filename,'r')
+ fileformat = os.path.splitext(filename)[-1][1:].lower()
+ r = trans_load_data(db_name, fileobj, fileformat, lang, strict=False)
+ fileobj.close()
+ return r
+ except IOError:
+ logger.notifyChannel("init", netsvc.LOG_ERROR, "couldn't read file")
+ return None
def trans_load_data(db_name, fileobj, fileformat, lang, strict=False, lang_name=None):
- logger = netsvc.Logger()
- logger.notifyChannel("init", netsvc.LOG_INFO,
- 'loading translation file for language %s' % (lang))
- pool = pooler.get_pool(db_name)
- lang_obj = pool.get('res.lang')
- trans_obj = pool.get('ir.translation')
- model_data_obj = pool.get('ir.model.data')
- try:
- uid = 1
- cr = pooler.get_db(db_name).cursor()
-
- ids = lang_obj.search(cr, uid, [('code','=',lang)])
- if not ids:
- if not lang_name:
- lang_name=lang
- languages=tools.get_languages()
- if lang in languages:
- lang_name=languages[lang]
- ids = lang_obj.create(cr, uid, {
- 'code': lang,
- 'name': lang_name,
- 'translatable': 1,
- })
- else:
- lang_obj.write(cr, uid, ids, {'translatable':1})
- lang_ids = lang_obj.search(cr, uid, [])
- langs = lang_obj.read(cr, uid, lang_ids)
- ls = map(lambda x: (x['code'],x['name']), langs)
-
- fileobj.seek(0)
-
- if fileformat == 'csv':
- reader = csv.reader(fileobj, quotechar='"', delimiter=',')
- # read the first line of the file (it contains columns titles)
- for row in reader:
- f = row
- break
- elif fileformat == 'po':
- reader = TinyPoFile(fileobj)
- f = ['type', 'name', 'res_id', 'src', 'value']
- else:
- raise Exception(_('Bad file format'))
-
- # read the rest of the file
- line = 1
- for row in reader:
- line += 1
- #try:
- # 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
- # {'lang': ..., 'type': ..., 'name': ..., 'res_id': ...,
- # 'src': ..., 'value': ...}
- dic = {'lang': lang}
- for i in range(len(f)):
- if f[i] in ('module',):
- continue
- dic[f[i]] = row[i]
-
- try:
- dic['res_id'] = int(dic['res_id'])
- except:
- model_data_ids = model_data_obj.search(cr, uid, [
- ('model', '=', dic['name'].split(',')[0]),
- ('module', '=', dic['res_id'].split('.', 1)[0]),
- ('name', '=', dic['res_id'].split('.', 1)[1]),
- ])
- if model_data_ids:
- dic['res_id'] = model_data_obj.browse(cr, uid,
- model_data_ids[0]).res_id
- else:
- dic['res_id'] = False
-
- if dic['type'] == 'model' and not strict:
- (model, field) = dic['name'].split(',')
-
- # get the ids of the resources of this model which share
- # the same source
- obj = pool.get(model)
- if obj:
- ids = obj.search(cr, uid, [(field, '=', dic['src'])])
-
- # if the resource id (res_id) is in that list, use it,
- # otherwise use the whole list
- ids = (dic['res_id'] in ids) and [dic['res_id']] or ids
- for id in ids:
- dic['res_id'] = id
- ids = trans_obj.search(cr, uid, [
- ('lang', '=', lang),
- ('type', '=', dic['type']),
- ('name', '=', dic['name']),
- ('src', '=', dic['src']),
- ('res_id', '=', dic['res_id'])
- ])
- if ids:
- trans_obj.write(cr, uid, ids, {'value': dic['value']})
- else:
- trans_obj.create(cr, uid, dic)
- else:
- ids = trans_obj.search(cr, uid, [
- ('lang', '=', lang),
- ('type', '=', dic['type']),
- ('name', '=', dic['name']),
- ('src', '=', dic['src'])
- ])
- if ids:
- trans_obj.write(cr, uid, ids, {'value': dic['value']})
- else:
- trans_obj.create(cr, uid, dic)
- cr.commit()
- #except Exception, e:
- # logger.notifyChannel('init', netsvc.LOG_ERROR,
- # 'Import error: %s on line %d: %s!' % (str(e), line, row))
- # cr.rollback()
- # cr.close()
- # cr = pooler.get_db(db_name).cursor()
- cr.close()
- logger.notifyChannel("init", netsvc.LOG_INFO,
- "translation file loaded succesfully")
- except IOError:
- logger.notifyChannel("init", netsvc.LOG_ERROR, "couldn't read file")
+ logger = netsvc.Logger()
+ logger.notifyChannel("init", netsvc.LOG_INFO,
+ 'loading translation file for language %s' % (lang))
+ pool = pooler.get_pool(db_name)
+ lang_obj = pool.get('res.lang')
+ trans_obj = pool.get('ir.translation')
+ model_data_obj = pool.get('ir.model.data')
+ try:
+ uid = 1
+ cr = pooler.get_db(db_name).cursor()
+
+ ids = lang_obj.search(cr, uid, [('code','=',lang)])
+ if not ids:
+ if not lang_name:
+ lang_name=lang
+ languages=tools.get_languages()
+ if lang in languages:
+ lang_name=languages[lang]
+ ids = lang_obj.create(cr, uid, {
+ 'code': lang,
+ 'name': lang_name,
+ 'translatable': 1,
+ })
+ else:
+ lang_obj.write(cr, uid, ids, {'translatable':1})
+ lang_ids = lang_obj.search(cr, uid, [])
+ langs = lang_obj.read(cr, uid, lang_ids)
+ ls = map(lambda x: (x['code'],x['name']), langs)
+
+ fileobj.seek(0)
+
+ if fileformat == 'csv':
+ reader = csv.reader(fileobj, quotechar='"', delimiter=',')
+ # read the first line of the file (it contains columns titles)
+ for row in reader:
+ f = row
+ break
+ elif fileformat == 'po':
+ reader = TinyPoFile(fileobj)
+ f = ['type', 'name', 'res_id', 'src', 'value']
+ else:
+ raise Exception(_('Bad file format'))
+
+ # read the rest of the file
+ line = 1
+ for row in reader:
+ line += 1
+ #try:
+ # 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
+ # {'lang': ..., 'type': ..., 'name': ..., 'res_id': ...,
+ # 'src': ..., 'value': ...}
+ dic = {'lang': lang}
+ for i in range(len(f)):
+ if f[i] in ('module',):
+ continue
+ dic[f[i]] = row[i]
+
+ try:
+ dic['res_id'] = int(dic['res_id'])
+ except:
+ model_data_ids = model_data_obj.search(cr, uid, [
+ ('model', '=', dic['name'].split(',')[0]),
+ ('module', '=', dic['res_id'].split('.', 1)[0]),
+ ('name', '=', dic['res_id'].split('.', 1)[1]),
+ ])
+ if model_data_ids:
+ dic['res_id'] = model_data_obj.browse(cr, uid,
+ model_data_ids[0]).res_id
+ else:
+ dic['res_id'] = False
+
+ if dic['type'] == 'model' and not strict:
+ (model, field) = dic['name'].split(',')
+
+ # get the ids of the resources of this model which share
+ # the same source
+ obj = pool.get(model)
+ if obj:
+ ids = obj.search(cr, uid, [(field, '=', dic['src'])])
+
+ # if the resource id (res_id) is in that list, use it,
+ # otherwise use the whole list
+ ids = (dic['res_id'] in ids) and [dic['res_id']] or ids
+ for id in ids:
+ dic['res_id'] = id
+ ids = trans_obj.search(cr, uid, [
+ ('lang', '=', lang),
+ ('type', '=', dic['type']),
+ ('name', '=', dic['name']),
+ ('src', '=', dic['src']),
+ ('res_id', '=', dic['res_id'])
+ ])
+ if ids:
+ trans_obj.write(cr, uid, ids, {'value': dic['value']})
+ else:
+ trans_obj.create(cr, uid, dic)
+ else:
+ ids = trans_obj.search(cr, uid, [
+ ('lang', '=', lang),
+ ('type', '=', dic['type']),
+ ('name', '=', dic['name']),
+ ('src', '=', dic['src'])
+ ])
+ if ids:
+ trans_obj.write(cr, uid, ids, {'value': dic['value']})
+ else:
+ trans_obj.create(cr, uid, dic)
+ cr.commit()
+ #except Exception, e:
+ # logger.notifyChannel('init', netsvc.LOG_ERROR,
+ # 'Import error: %s on line %d: %s!' % (str(e), line, row))
+ # cr.rollback()
+ # cr.close()
+ # cr = pooler.get_db(db_name).cursor()
+ cr.close()
+ logger.notifyChannel("init", netsvc.LOG_INFO,
+ "translation file loaded succesfully")
+ except IOError:
+ logger.notifyChannel("init", netsvc.LOG_ERROR, "couldn't read file")
diff --git a/bin/tools/upgrade.py b/bin/tools/upgrade.py
index 167ee7eaa6d..2d9c39ece2c 100644
--- a/bin/tools/upgrade.py
+++ b/bin/tools/upgrade.py
@@ -36,60 +36,60 @@ import tools
# remove an existing version of modules if it exist
def remove(name):
- adp = tools.config['addons_path']
- addons = os.listdir(adp)
- if name in addons:
- try:
- shutil.rmtree(os.path.join(adp, name))
- except:
- print "Unable to remove module %s !" % name
+ adp = tools.config['addons_path']
+ addons = os.listdir(adp)
+ if name in addons:
+ try:
+ shutil.rmtree(os.path.join(adp, name))
+ except:
+ print "Unable to remove module %s !" % name
def install(name, url):
- tar = tarfile.open(mode="r|gz", fileobj=urllib2.urlopen(url))
- for tarinfo in tar:
- tar.extract(tarinfo, tools.config['addons_path'])
+ tar = tarfile.open(mode="r|gz", fileobj=urllib2.urlopen(url))
+ for tarinfo in tar:
+ tar.extract(tarinfo, tools.config['addons_path'])
def upgrade():
- import pooler
- cr = pooler.db.cursor()
+ import pooler
+ cr = pooler.db.cursor()
- toinit = []
- toupdate = []
+ toinit = []
+ toupdate = []
-# print 'Check for correct rights (create and unlink on addons)...'
- # todo: touch addons/test.txt
- # todo: rm addons/test.txt
+# print 'Check for correct rights (create and unlink on addons)...'
+ # todo: touch addons/test.txt
+ # todo: rm addons/test.txt
- print 'Check for modules to remove...'
- cr.execute('select id,name,url from ir_module_module where state=%s', ('to remove',))
- 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.commit()
+ print 'Check for modules to remove...'
+ cr.execute('select id,name,url from ir_module_module where state=%s', ('to remove',))
+ 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.commit()
- print 'Check for modules to upgrade...'
- cr.execute('select id,name,url from ir_module_module where state=%s', ('to upgrade',))
- for module_id,name,url in cr.fetchall():
- 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.commit()
- toupdate.append(name)
+ print 'Check for modules to upgrade...'
+ cr.execute('select id,name,url from ir_module_module where state=%s', ('to upgrade',))
+ for module_id,name,url in cr.fetchall():
+ 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.commit()
+ toupdate.append(name)
- print 'Check for modules to install...'
- cr.execute('select id,name,url from ir_module_module where state=%s', ('to install',))
- 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.commit()
- toinit.append(name)
+ print 'Check for modules to install...'
+ cr.execute('select id,name,url from ir_module_module where state=%s', ('to install',))
+ 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.commit()
+ toinit.append(name)
- print 'Initializing all datas...'
+ print 'Initializing all datas...'
- cr.commit()
- cr.close()
- return (toinit, toupdate)
+ cr.commit()
+ cr.close()
+ return (toinit, toupdate)
diff --git a/bin/wizard/__init__.py b/bin/wizard/__init__.py
index 10e57e93585..adeaee803d0 100644
--- a/bin/wizard/__init__.py
+++ b/bin/wizard/__init__.py
@@ -41,138 +41,138 @@ from netsvc import Logger, LOG_ERROR
import sys
class except_wizard(Exception):
- def __init__(self, name, value):
- self.name = name
- self.value = value
- self.args = (name, value)
+ def __init__(self, name, value):
+ self.name = name
+ self.value = value
+ self.args = (name, value)
class interface(netsvc.Service):
- states = {}
-
- def __init__(self, name):
- assert not netsvc.service_exist('wizard.'+name), 'The wizard "%s" already exists!'%name
- super(interface, self).__init__('wizard.'+name)
- self.exportMethod(self.execute)
- self.wiz_name = name
-
- def translate_view(self, cr, node, state, lang):
- if node.nodeType == node.ELEMENT_NODE:
- 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'))
- for n in node.childNodes:
- self.translate_view(cr, n, state, lang)
+ states = {}
+
+ def __init__(self, name):
+ assert not netsvc.service_exist('wizard.'+name), 'The wizard "%s" already exists!'%name
+ super(interface, self).__init__('wizard.'+name)
+ self.exportMethod(self.execute)
+ self.wiz_name = name
+
+ def translate_view(self, cr, node, state, lang):
+ if node.nodeType == node.ELEMENT_NODE:
+ 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'))
+ for n in node.childNodes:
+ self.translate_view(cr, n, state, lang)
- def execute_cr(self, cr, uid, data, state='init', context=None):
- if not context:
- context={}
- res = {}
- try:
- state_def = self.states[state]
- result_def = state_def.get('result', {})
-
- actions_res = {}
- # iterate through the list of actions defined for this state
- for action in state_def.get('actions', []):
- # execute them
- action_res = action(self, cr, uid, data, context)
- assert isinstance(action_res, dict), 'The return value of wizard actions should be a dictionary'
- actions_res.update(action_res)
-
- res = copy.copy(result_def)
- res['datas'] = actions_res
-
- lang = context.get('lang', False)
- if result_def['type'] == 'action':
- res['action'] = result_def['action'](self, cr, uid, data, context)
- elif result_def['type'] == 'form':
- fields = copy.copy(result_def['fields'])
- arch = copy.copy(result_def['arch'])
- button_list = copy.copy(result_def['state'])
+ def execute_cr(self, cr, uid, data, state='init', context=None):
+ if not context:
+ context={}
+ res = {}
+ try:
+ state_def = self.states[state]
+ result_def = state_def.get('result', {})
+
+ actions_res = {}
+ # iterate through the list of actions defined for this state
+ for action in state_def.get('actions', []):
+ # execute them
+ action_res = action(self, cr, uid, data, context)
+ assert isinstance(action_res, dict), 'The return value of wizard actions should be a dictionary'
+ actions_res.update(action_res)
+
+ res = copy.copy(result_def)
+ res['datas'] = actions_res
+
+ lang = context.get('lang', False)
+ if result_def['type'] == 'action':
+ res['action'] = result_def['action'](self, cr, uid, data, context)
+ elif result_def['type'] == 'form':
+ fields = copy.copy(result_def['fields'])
+ arch = copy.copy(result_def['arch'])
+ button_list = copy.copy(result_def['state'])
- if isinstance(fields, UpdateableDict):
- fields = fields.dict
- if isinstance(arch, UpdateableStr):
- arch = arch.string
+ if isinstance(fields, UpdateableDict):
+ fields = fields.dict
+ if isinstance(arch, UpdateableStr):
+ arch = arch.string
- # fetch user-set defaut values for the field... shouldn't we pass it the uid?
- defaults = ir.ir_get(cr, uid, 'default', False, [('wizard.'+self.wiz_name, False)])
- default_values = dict([(x[1], x[2]) for x in defaults])
- for val in fields.keys():
- if 'default' in fields[val]:
- # execute default method for this field
- if callable(fields[val]['default']):
- fields[val]['value'] = fields[val]['default'](uid, data, state)
- else:
- fields[val]['value'] = fields[val]['default']
- del fields[val]['default']
- else:
- # if user has set a default value for the field, use it
- if val in default_values:
- fields[val]['value'] = default_values[val]
- if 'selection' in fields[val]:
- if not isinstance(fields[val]['selection'], (tuple, list)):
- fields[val] = copy.copy(fields[val])
- fields[val]['selection'] = fields[val]['selection'](self, cr, uid, context)
+ # fetch user-set defaut values for the field... shouldn't we pass it the uid?
+ defaults = ir.ir_get(cr, uid, 'default', False, [('wizard.'+self.wiz_name, False)])
+ default_values = dict([(x[1], x[2]) for x in defaults])
+ for val in fields.keys():
+ if 'default' in fields[val]:
+ # execute default method for this field
+ if callable(fields[val]['default']):
+ fields[val]['value'] = fields[val]['default'](uid, data, state)
+ else:
+ fields[val]['value'] = fields[val]['default']
+ del fields[val]['default']
+ else:
+ # if user has set a default value for the field, use it
+ if val in default_values:
+ fields[val]['value'] = default_values[val]
+ if 'selection' in fields[val]:
+ if not isinstance(fields[val]['selection'], (tuple, list)):
+ fields[val] = copy.copy(fields[val])
+ fields[val]['selection'] = fields[val]['selection'](self, cr, uid, context)
- if lang:
- # translate fields
- for field in fields:
- trans = translate(cr, self.wiz_name+','+state+','+field, 'wizard_field', lang)
- if trans:
- fields[field]['string'] = trans
+ if lang:
+ # translate fields
+ for field in fields:
+ trans = translate(cr, self.wiz_name+','+state+','+field, 'wizard_field', lang)
+ if trans:
+ fields[field]['string'] = trans
- # translate arch
- if not isinstance(arch, UpdateableStr):
- doc = dom.minidom.parseString(arch)
- self.translate_view(cr, doc, state, lang)
- arch = doc.toxml()
+ # translate arch
+ if not isinstance(arch, UpdateableStr):
+ doc = dom.minidom.parseString(arch)
+ self.translate_view(cr, doc, state, lang)
+ arch = doc.toxml()
- # translate buttons
- button_list = list(button_list)
- for i, aa in enumerate(button_list):
- button_name = aa[0]
- trans = translate(cr, self.wiz_name+','+state+','+button_name, 'wizard_button', lang)
- if trans:
- aa = list(aa)
- aa[1] = trans
- button_list[i] = aa
-
- res['fields'] = fields
- res['arch'] = arch
- res['state'] = button_list
+ # translate buttons
+ button_list = list(button_list)
+ for i, aa in enumerate(button_list):
+ button_name = aa[0]
+ trans = translate(cr, self.wiz_name+','+state+','+button_name, 'wizard_button', lang)
+ if trans:
+ aa = list(aa)
+ aa[1] = trans
+ button_list[i] = aa
+
+ res['fields'] = fields
+ res['arch'] = arch
+ res['state'] = button_list
- except Exception, e:
- if isinstance(e, except_wizard) \
- or isinstance(e, except_osv) \
- or isinstance(e, except_orm):
- self.abortResponse(2, e.name, 'warning', e.value)
- else:
- import traceback
- tb_s = reduce(lambda x, y: x+y, traceback.format_exception(
- sys.exc_type, sys.exc_value, sys.exc_traceback))
- logger = Logger()
- logger.notifyChannel("web-services", LOG_ERROR,
- 'Exception in call: ' + tb_s)
- raise
+ except Exception, e:
+ if isinstance(e, except_wizard) \
+ or isinstance(e, except_osv) \
+ or isinstance(e, except_orm):
+ self.abortResponse(2, e.name, 'warning', e.value)
+ else:
+ import traceback
+ tb_s = reduce(lambda x, y: x+y, traceback.format_exception(
+ sys.exc_type, sys.exc_value, sys.exc_traceback))
+ logger = Logger()
+ logger.notifyChannel("web-services", LOG_ERROR,
+ 'Exception in call: ' + tb_s)
+ raise
- if result_def['type'] == 'choice':
- next_state = result_def['next_state'](self, cr, uid, data, context)
- return self.execute_cr(cr, uid, data, next_state, context)
- return res
+ if result_def['type'] == 'choice':
+ next_state = result_def['next_state'](self, cr, uid, data, context)
+ return self.execute_cr(cr, uid, data, next_state, context)
+ return res
- def execute(self, db, uid, data, state='init', context=None):
- if not context:
- context={}
- cr = pooler.get_db(db).cursor()
- try:
- try:
- res = self.execute_cr(cr, uid, data, state, context)
- cr.commit()
- except Exception:
- cr.rollback()
- raise
- finally:
- cr.close()
- return res
+ def execute(self, db, uid, data, state='init', context=None):
+ if not context:
+ context={}
+ cr = pooler.get_db(db).cursor()
+ try:
+ try:
+ res = self.execute_cr(cr, uid, data, state, context)
+ cr.commit()
+ except Exception:
+ cr.rollback()
+ raise
+ finally:
+ cr.close()
+ return res
diff --git a/bin/workflow/common.py b/bin/workflow/common.py
index 51d902996b0..9eba6b62926 100644
--- a/bin/workflow/common.py
+++ b/bin/workflow/common.py
@@ -26,6 +26,6 @@
##############################################################################
class except_wkf(Exception):
- def __init__(self, name, value):
- self.name = name
- self.value = value
+ def __init__(self, name, value):
+ self.name = name
+ self.value = value
diff --git a/bin/workflow/instance.py b/bin/workflow/instance.py
index d25bc367f4c..82071e462f7 100644
--- a/bin/workflow/instance.py
+++ b/bin/workflow/instance.py
@@ -33,54 +33,54 @@ import netsvc
import pooler
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,))
- res = cr.dictfetchall()
- stack = []
- workitem.create(cr, res, id_new, ident, stack=stack)
- update(cr, id_new, ident)
- return id_new
+ (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,))
+ res = cr.dictfetchall()
+ stack = []
+ workitem.create(cr, res, id_new, ident, stack=stack)
+ update(cr, id_new, ident)
+ return id_new
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))
+ (uid,res_type,res_id) = ident
+ cr.execute('delete from wkf_instance where res_id=%d 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,))
- for witem in cr.dictfetchall():
- stack = []
- workitem.process(cr, witem, ident, signal, force_running, stack=stack)
- # An action is returned
- _update_end(cr, inst_id, ident)
- return stack and stack[0] or False
+ cr.execute("select * from wkf_workitem where inst_id=%d", (inst_id,))
+ for witem in cr.dictfetchall():
+ stack = []
+ workitem.process(cr, witem, ident, signal, force_running, stack=stack)
+ # An action is returned
+ _update_end(cr, inst_id, ident)
+ 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,))
- for witem in cr.dictfetchall():
- stack = []
- workitem.process(cr, witem, ident, stack=stack)
- return _update_end(cr, inst_id, ident)
+ cr.execute("select * from wkf_workitem where inst_id=%d", (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,))
- 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,))
- 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,))
- 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,))
- 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])
- return ok
+ cr.execute('select wkf_id from wkf_instance where id=%d', (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,))
+ 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,))
+ 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,))
+ 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])
+ return ok
diff --git a/bin/workflow/wkf_expr.py b/bin/workflow/wkf_expr.py
index f1476cc8188..dca3e666efe 100644
--- a/bin/workflow/wkf_expr.py
+++ b/bin/workflow/wkf_expr.py
@@ -34,77 +34,77 @@ import pooler
class EnvCall(object):
- def __init__(self,wf_service,d_arg):
- self.wf_service=wf_service
- self.d_arg=d_arg
+ def __init__(self,wf_service,d_arg):
+ self.wf_service=wf_service
+ self.d_arg=d_arg
- def __call__(self,*args):
- arg=self.d_arg+args
- return self.wf_service.execute_cr(*arg)
+ def __call__(self,*args):
+ arg=self.d_arg+args
+ return self.wf_service.execute_cr(*arg)
class Env(dict):
- def __init__(self, wf_service, cr, uid, model, ids):
- self.wf_service = wf_service
- self.cr = cr
- self.uid = uid
- self.model = model
- self.ids = ids
- self.obj = pooler.get_pool(cr.dbname).get(model)
- self.columns = self.obj._columns.keys() + self.obj._inherit_fields.keys()
+ def __init__(self, wf_service, cr, uid, model, ids):
+ self.wf_service = wf_service
+ self.cr = cr
+ self.uid = uid
+ self.model = model
+ self.ids = ids
+ self.obj = pooler.get_pool(cr.dbname).get(model)
+ self.columns = self.obj._columns.keys() + self.obj._inherit_fields.keys()
- def __getitem__(self, key):
- if (key in self.columns) or (key in dir(self.obj)):
- res = self.obj.browse(self.cr, self.uid, self.ids[0])
- return res[key]
- #res=self.wf_service.execute_cr(self.cr, self.uid, self.model, 'read',\
- # self.ids, [key])[0][key]
- #super(Env, self).__setitem__(key, res)
- #return res
- #elif key in dir(self.obj):
- # return EnvCall(self.wf_service, (self.cr, self.uid, self.model, key,\
- # self.ids))
- else:
- return super(Env, self).__getitem__(key)
+ def __getitem__(self, key):
+ if (key in self.columns) or (key in dir(self.obj)):
+ res = self.obj.browse(self.cr, self.uid, self.ids[0])
+ return res[key]
+ #res=self.wf_service.execute_cr(self.cr, self.uid, self.model, 'read',\
+ # self.ids, [key])[0][key]
+ #super(Env, self).__setitem__(key, res)
+ #return res
+ #elif key in dir(self.obj):
+ # return EnvCall(self.wf_service, (self.cr, self.uid, self.model, key,\
+ # self.ids))
+ else:
+ return super(Env, self).__getitem__(key)
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'):
- uid=ident[0]
- model=ident[1]
- ids=[ident[2]]
- if line =='True':
- ret=True
- elif line =='False':
- ret=False
- else:
- wf_service = netsvc.LocalService("object_proxy")
- env = Env(wf_service, cr, uid, model, ids)
- ret = eval(line, env)
- return ret
+ ret=False
+ assert action, 'You used a NULL action in a workflow, use dummy node instead.'
+ for line in action.split('\n'):
+ uid=ident[0]
+ model=ident[1]
+ ids=[ident[2]]
+ if line =='True':
+ ret=True
+ elif line =='False':
+ ret=False
+ else:
+ wf_service = netsvc.LocalService("object_proxy")
+ env = Env(wf_service, cr, uid, model, ids)
+ ret = eval(line, env)
+ return ret
def execute_action(cr, ident, workitem, activity):
- wf_service = netsvc.LocalService("object_proxy")
- obj = pooler.get_pool(cr.dbname).get('ir.actions.server')
- ctx = {'active_id':ident[2], 'active_ids':[ident[2]]}
- result = obj.run(cr, ident[0], [activity['action_id']], ctx)
- return result
+ wf_service = netsvc.LocalService("object_proxy")
+ obj = pooler.get_pool(cr.dbname).get('ir.actions.server')
+ ctx = {'active_id':ident[2], 'active_ids':[ident[2]]}
+ result = obj.run(cr, ident[0], [activity['action_id']], ctx)
+ return result
def execute(cr, ident, workitem, activity):
- return _eval_expr(cr, ident, workitem, activity['action'])
+ return _eval_expr(cr, ident, workitem, activity['action'])
def check(cr, workitem, ident, transition, signal):
- ok = True
- if transition['signal']:
- ok = (signal==transition['signal'])
+ ok = True
+ if transition['signal']:
+ ok = (signal==transition['signal'])
- if transition['role_id']:
- uid = ident[0]
- serv = netsvc.LocalService('object_proxy')
- user_roles = serv.execute_cr(cr, uid, 'res.users', 'read', [uid], ['roles_id'])[0]['roles_id']
- ok = ok and serv.execute_cr(cr, uid, 'res.roles', 'check', user_roles, transition['role_id'])
- ok = ok and _eval_expr(cr, ident, workitem, transition['condition'])
- return ok
+ if transition['role_id']:
+ uid = ident[0]
+ serv = netsvc.LocalService('object_proxy')
+ user_roles = serv.execute_cr(cr, uid, 'res.users', 'read', [uid], ['roles_id'])[0]['roles_id']
+ ok = ok and serv.execute_cr(cr, uid, 'res.roles', 'check', user_roles, transition['role_id'])
+ ok = ok and _eval_expr(cr, ident, workitem, transition['condition'])
+ return ok
diff --git a/bin/workflow/wkf_logs.py b/bin/workflow/wkf_logs.py
index 0ec3ded3e2d..f8d68c1f37a 100644
--- a/bin/workflow/wkf_logs.py
+++ b/bin/workflow/wkf_logs.py
@@ -31,5 +31,5 @@
#
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))
+ 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))
diff --git a/bin/workflow/wkf_service.py b/bin/workflow/wkf_service.py
index f1c103ccfe0..e980c47af90 100644
--- a/bin/workflow/wkf_service.py
+++ b/bin/workflow/wkf_service.py
@@ -34,79 +34,79 @@ import netsvc
import pooler
class workflow_service(netsvc.Service):
- def __init__(self, name='workflow', audience='*'):
- netsvc.Service.__init__(self, name, audience)
- self.exportMethod(self.trg_write)
- self.exportMethod(self.trg_delete)
- self.exportMethod(self.trg_create)
- self.exportMethod(self.trg_validate)
- self.exportMethod(self.trg_redirect)
- self.exportMethod(self.trg_trigger)
- self.exportMethod(self.clear_cache)
- self.wkf_on_create_cache={}
+ def __init__(self, name='workflow', audience='*'):
+ netsvc.Service.__init__(self, name, audience)
+ self.exportMethod(self.trg_write)
+ self.exportMethod(self.trg_delete)
+ self.exportMethod(self.trg_create)
+ self.exportMethod(self.trg_validate)
+ self.exportMethod(self.trg_redirect)
+ self.exportMethod(self.trg_trigger)
+ self.exportMethod(self.clear_cache)
+ self.wkf_on_create_cache={}
- def clear_cache(self, cr, uid):
- self.wkf_on_create_cache[cr.dbname]={}
+ def clear_cache(self, cr, uid):
+ self.wkf_on_create_cache[cr.dbname]={}
- 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'))
- for (id,) in cr.fetchall():
- instance.update(cr, id, ident)
+ 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'))
+ 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))
- res = cr.fetchall()
- for (instance_id,) in res:
- cr.execute('select uid,res_type,res_id from wkf_instance where id=%d', (instance_id,))
- ident = cr.fetchone()
- instance.update(cr, instance_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))
+ res = cr.fetchall()
+ for (instance_id,) in res:
+ cr.execute('select uid,res_type,res_id from wkf_instance where id=%d', (instance_id,))
+ ident = cr.fetchone()
+ instance.update(cr, instance_id, ident)
- def trg_delete(self, uid, res_type, res_id, cr):
- ident = (uid,res_type,res_id)
- instance.delete(cr, ident)
+ def trg_delete(self, uid, res_type, res_id, cr):
+ ident = (uid,res_type,res_id)
+ instance.delete(cr, ident)
- def trg_create(self, uid, res_type, res_id, cr):
- ident = (uid,res_type,res_id)
- self.wkf_on_create_cache.setdefault(cr.dbname, {})
- if res_type in self.wkf_on_create_cache[cr.dbname]:
- wkf_ids = self.wkf_on_create_cache[cr.dbname][res_type]
- else:
- cr.execute('select id from wkf where osv=%s and on_create=True', (res_type,))
- wkf_ids = cr.fetchall()
- self.wkf_on_create_cache[cr.dbname][res_type] = wkf_ids
- for (wkf_id,) in wkf_ids:
- instance.create(cr, ident, wkf_id)
+ def trg_create(self, uid, res_type, res_id, cr):
+ ident = (uid,res_type,res_id)
+ self.wkf_on_create_cache.setdefault(cr.dbname, {})
+ if res_type in self.wkf_on_create_cache[cr.dbname]:
+ wkf_ids = self.wkf_on_create_cache[cr.dbname][res_type]
+ else:
+ cr.execute('select id from wkf where osv=%s and on_create=True', (res_type,))
+ wkf_ids = cr.fetchall()
+ self.wkf_on_create_cache[cr.dbname][res_type] = wkf_ids
+ for (wkf_id,) in wkf_ids:
+ instance.create(cr, ident, wkf_id)
- def trg_validate(self, uid, res_type, res_id, signal, cr):
- 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'))
- for (id,) in cr.fetchall():
- res2 = instance.validate(cr, id, ident, signal)
- result = result or res2
- return result
+ def trg_validate(self, uid, res_type, res_id, signal, cr):
+ 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'))
+ for (id,) in cr.fetchall():
+ res2 = instance.validate(cr, id, ident, signal)
+ result = result or res2
+ return result
- # make all workitems which are waiting for a (subflow) workflow instance
- # for the old resource point to the (first active) workflow instance for
- # the new resource
- def trg_redirect(self, uid, res_type, res_id, new_rid, cr):
- # get ids of wkf instances for the old resource (res_id)
+ # make all workitems which are waiting for a (subflow) workflow instance
+ # for the old resource point to the (first active) workflow instance for
+ # the new resource
+ 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))
- 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',
- (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,))
- 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('select id, wkf_id from wkf_instance where res_id=%d 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',
+ (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,))
+ 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))
workflow_service()
diff --git a/bin/workflow/workitem.py b/bin/workflow/workitem.py
index 2dbc3600bd9..54076a9e729 100644
--- a/bin/workflow/workitem.py
+++ b/bin/workflow/workitem.py
@@ -38,158 +38,158 @@ import wkf_expr
import wkf_logs
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,))
- res = cr.dictfetchone()
- wkf_logs.log(cr,ident,act['id'],'active')
- process(cr, res, ident, stack=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,))
+ res = cr.dictfetchone()
+ wkf_logs.log(cr,ident,act['id'],'active')
+ process(cr, res, ident, stack=stack)
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'],))
- activity = cr.dictfetchone()
-
- triggers = False
- if workitem['state']=='active':
- triggers = True
- result = _execute(cr, workitem, activity, ident, stack)
- if not result:
- return False
-
- if workitem['state']=='running':
- pass
-
- if workitem['state']=='complete' or force_running:
- ok = _split_test(cr, workitem, activity['split_mode'], ident, signal, stack)
- triggers = triggers and not ok
-
- if triggers:
- cr.execute('select * from wkf_transition where act_from=%d', (workitem['act_id'],))
- alltrans = cr.dictfetchall()
- for trans in alltrans:
- if trans['trigger_model']:
- ids = wkf_expr._eval_expr(cr,ident,workitem,trans['trigger_expr_id'])
- 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))
-
- return result
+ if stack is None:
+ raise 'Error !!!'
+ result = True
+ cr.execute('select * from wkf_activity where id=%d', (workitem['act_id'],))
+ activity = cr.dictfetchone()
+
+ triggers = False
+ if workitem['state']=='active':
+ triggers = True
+ result = _execute(cr, workitem, activity, ident, stack)
+ if not result:
+ return False
+
+ if workitem['state']=='running':
+ pass
+
+ if workitem['state']=='complete' or force_running:
+ ok = _split_test(cr, workitem, activity['split_mode'], ident, signal, stack)
+ triggers = triggers and not ok
+
+ if triggers:
+ cr.execute('select * from wkf_transition where act_from=%d', (workitem['act_id'],))
+ alltrans = cr.dictfetchall()
+ for trans in alltrans:
+ if trans['trigger_model']:
+ ids = wkf_expr._eval_expr(cr,ident,workitem,trans['trigger_expr_id'])
+ 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))
+
+ return result
# ---------------------- PRIVATE FUNCS --------------------------------
def _state_set(cr, workitem, activity, state, ident):
- cr.execute('update wkf_workitem set state=%s where id=%d', (state,workitem['id']))
- workitem['state'] = state
- wkf_logs.log(cr,ident,activity['id'],state)
+ cr.execute('update wkf_workitem set state=%s where id=%d', (state,workitem['id']))
+ workitem['state'] = state
+ wkf_logs.log(cr,ident,activity['id'],state)
def _execute(cr, workitem, activity, ident, stack):
- result = True
- #
- # 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'],))
- for i in cr.fetchall():
- instance.validate(cr, i[0], (ident[0],i[1],i[2]), activity['signal_send'], force_running=True)
-
- if activity['kind']=='dummy':
- if workitem['state']=='active':
- _state_set(cr, workitem, activity, 'complete', ident)
- elif activity['kind']=='function':
- if workitem['state']=='active':
- _state_set(cr, workitem, activity, 'running', ident)
- wkf_expr.execute(cr, ident, workitem, activity)
- if activity['action_id']:
- res2 = wkf_expr.execute_action(cr, ident, workitem, activity)
- # A client action has been returned
- if res2:
- stack.append(res2)
- result=res2
- _state_set(cr, workitem, activity, 'complete', ident)
- 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']))
- if activity['action']:
- wkf_expr.execute(cr, ident, workitem, activity)
- _state_set(cr, workitem, activity, 'complete', ident)
- elif activity['kind']=='subflow':
- if workitem['state']=='active':
- _state_set(cr, workitem, activity, 'running', ident)
- if activity.get('action', False):
- id_new = wkf_expr.execute(cr, ident, workitem, activity)
- if not (id_new):
- 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']))
- 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']))
- workitem['subflow_id'] = id_new
- if workitem['state']=='running':
- cr.execute("select state from wkf_instance where id=%d", (workitem['subflow_id'],))
- state= cr.fetchone()[0]
- if state=='complete':
- _state_set(cr, workitem, activity, 'complete', ident)
- return result
+ result = True
+ #
+ # 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'],))
+ for i in cr.fetchall():
+ instance.validate(cr, i[0], (ident[0],i[1],i[2]), activity['signal_send'], force_running=True)
+
+ if activity['kind']=='dummy':
+ if workitem['state']=='active':
+ _state_set(cr, workitem, activity, 'complete', ident)
+ elif activity['kind']=='function':
+ if workitem['state']=='active':
+ _state_set(cr, workitem, activity, 'running', ident)
+ wkf_expr.execute(cr, ident, workitem, activity)
+ if activity['action_id']:
+ res2 = wkf_expr.execute_action(cr, ident, workitem, activity)
+ # A client action has been returned
+ if res2:
+ stack.append(res2)
+ result=res2
+ _state_set(cr, workitem, activity, 'complete', ident)
+ 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']))
+ if activity['action']:
+ wkf_expr.execute(cr, ident, workitem, activity)
+ _state_set(cr, workitem, activity, 'complete', ident)
+ elif activity['kind']=='subflow':
+ if workitem['state']=='active':
+ _state_set(cr, workitem, activity, 'running', ident)
+ if activity.get('action', False):
+ id_new = wkf_expr.execute(cr, ident, workitem, activity)
+ if not (id_new):
+ 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']))
+ 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']))
+ workitem['subflow_id'] = id_new
+ if workitem['state']=='running':
+ cr.execute("select state from wkf_instance where id=%d", (workitem['subflow_id'],))
+ state= cr.fetchone()[0]
+ if state=='complete':
+ _state_set(cr, workitem, activity, 'complete', ident)
+ return result
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'],))
- test = False
- transitions = []
- alltrans = cr.dictfetchall()
- if split_mode=='XOR' or split_mode=='OR':
- for transition in alltrans:
- if wkf_expr.check(cr, workitem, ident, transition,signal):
- test = True
- transitions.append((transition['id'], workitem['inst_id']))
- if split_mode=='XOR':
- break
- else:
- test = True
- for transition in alltrans:
- 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']))
- 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'],))
- for t in transitions:
- _join_test(cr, t[0], t[1], ident, stack)
- return True
- return False
+ if stack is None:
+ raise 'Error !!!'
+ cr.execute('select * from wkf_transition where act_from=%d', (workitem['act_id'],))
+ test = False
+ transitions = []
+ alltrans = cr.dictfetchall()
+ if split_mode=='XOR' or split_mode=='OR':
+ for transition in alltrans:
+ if wkf_expr.check(cr, workitem, ident, transition,signal):
+ test = True
+ transitions.append((transition['id'], workitem['inst_id']))
+ if split_mode=='XOR':
+ break
+ else:
+ test = True
+ for transition in alltrans:
+ 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']))
+ 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'],))
+ 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,))
- 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))
- else:
- cr.execute('select id from wkf_transition where act_to=%d', (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))
- 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))
- create(cr, [activity], inst_id, ident, stack)
+ cr.execute('select * from wkf_activity where id=(select act_to from wkf_transition where id=%d)', (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))
+ else:
+ cr.execute('select id from wkf_transition where act_to=%d', (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))
+ 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))
+ create(cr, [activity], inst_id, ident, stack)
diff --git a/doc/migrate/3.3.0-3.4.0/post.py b/doc/migrate/3.3.0-3.4.0/post.py
index cc99e3732c2..6983bfad519 100644
--- a/doc/migrate/3.3.0-3.4.0/post.py
+++ b/doc/migrate/3.3.0-3.4.0/post.py
@@ -53,15 +53,15 @@ options.db_name = 'terp' # default value
parser.parse_args(values=options)
if hasattr(options, 'config'):
- configparser = ConfigParser.ConfigParser()
- configparser.read([options.config])
- for name, value in configparser.items('options'):
- if not (hasattr(options, name) and getattr(options, name)):
- if value in ('true', 'True'):
- value = True
- if value in ('false', 'False'):
- value = False
- setattr(options, name, value)
+ configparser = ConfigParser.ConfigParser()
+ configparser.read([options.config])
+ for name, value in configparser.items('options'):
+ if not (hasattr(options, name) and getattr(options, name)):
+ if value in ('true', 'True'):
+ value = True
+ if value in ('false', 'False'):
+ value = False
+ setattr(options, name, value)
# -----
@@ -91,23 +91,23 @@ cr.execute("SELECT c.relname FROM pg_class c, pg_attribute a WHERE c.relname='re
partners=[]
drop_payment_term=False
if cr.rowcount:
- drop_payment_term=True
- cr.execute("select id, payment_term from res_partner where payment_term is not null")
- partners = cr.dictfetchall()
+ drop_payment_term=True
+ cr.execute("select id, payment_term from res_partner where payment_term is not null")
+ partners = cr.dictfetchall()
# loop over them
for partner in partners:
- value = 'account.payment.term,%d' % partner['payment_term']
- res_id = 'res.partner,%d' % partner['id']
- cr.execute(
- "insert into ir_property(name, value, res_id, company_id, fields_id) "\
- "values(%s, %s, %s, %d, %d)",
- ('property_payment_term', value, res_id, company_id, fields_id))
+ value = 'account.payment.term,%d' % partner['payment_term']
+ res_id = 'res.partner,%d' % partner['id']
+ cr.execute(
+ "insert into ir_property(name, value, res_id, company_id, fields_id) "\
+ "values(%s, %s, %s, %d, %d)",
+ ('property_payment_term', value, res_id, company_id, fields_id))
# remove the field
if drop_payment_term:
- cr.execute("alter table res_partner drop column payment_term")
+ cr.execute("alter table res_partner drop column payment_term")
cr.execute("delete from ir_model_fields where model = 'res.partner' and name = 'payment_term'")
cr.commit()
@@ -124,10 +124,10 @@ registered_reports = cr.fetchall()
reg_reports_ids = ','.join([str(id) for (id,) in registered_reports])
for report in reports_wh_duplicates:
- cr.execute("select id from ir_act_report_xml where model=%s and report_name=%s and id not in ("+reg_reports_ids+")", (report['model'], report['report_name']))
- (id,) = cr.fetchone()
- cr.execute("delete from ir_act_report_xml where id=%d", (id,))
- cr.execute("delete from ir_values where value='ir.actions.report.xml,%d'", (id,))
+ cr.execute("select id from ir_act_report_xml where model=%s and report_name=%s and id not in ("+reg_reports_ids+")", (report['model'], report['report_name']))
+ (id,) = cr.fetchone()
+ cr.execute("delete from ir_act_report_xml where id=%d", (id,))
+ cr.execute("delete from ir_values where value='ir.actions.report.xml,%d'", (id,))
cr.commit()
diff --git a/doc/migrate/3.3.0-3.4.0/pre.py b/doc/migrate/3.3.0-3.4.0/pre.py
index c2cab1b9e0a..df8e4a7d487 100644
--- a/doc/migrate/3.3.0-3.4.0/pre.py
+++ b/doc/migrate/3.3.0-3.4.0/pre.py
@@ -53,15 +53,15 @@ options.db_name = 'terp' # default value
parser.parse_args(values=options)
if hasattr(options, 'config'):
- configparser = ConfigParser.ConfigParser()
- configparser.read([options.config])
- for name, value in configparser.items('options'):
- if not (hasattr(options, name) and getattr(options, name)):
- if value in ('true', 'True'):
- value = True
- if value in ('false', 'False'):
- value = False
- setattr(options, name, value)
+ configparser = ConfigParser.ConfigParser()
+ configparser.read([options.config])
+ for name, value in configparser.items('options'):
+ if not (hasattr(options, name) and getattr(options, name)):
+ if value in ('true', 'True'):
+ value = True
+ if value in ('false', 'False'):
+ value = False
+ setattr(options, name, value)
# -----
@@ -79,18 +79,18 @@ cr = db.cursor()
# ------------------------- #
def change_column(cr, table, column, new_type, copy):
- commands = [
- "ALTER TABLE %s RENAME COLUMN %s TO temp_column" % (table, column),
- "ALTER TABLE %s ADD COLUMN %s %s" % (table, column, new_type),
- "ALTER TABLE %s DROP COLUMN temp_column" % table
- ]
- if copy:
- commands.insert(
- 2,
- "UPDATE %s SET %s=temp_column::%s" % (table, column, new_type))
-
- for command in commands:
- cr.execute(command)
+ commands = [
+ "ALTER TABLE %s RENAME COLUMN %s TO temp_column" % (table, column),
+ "ALTER TABLE %s ADD COLUMN %s %s" % (table, column, new_type),
+ "ALTER TABLE %s DROP COLUMN temp_column" % table
+ ]
+ if copy:
+ commands.insert(
+ 2,
+ "UPDATE %s SET %s=temp_column::%s" % (table, column, new_type))
+
+ for command in commands:
+ cr.execute(command)
change_column(cr, 'account_account_type', 'code_from', 'varchar(10)', False)
change_column(cr, 'account_account_type', 'code_to', 'varchar(10)', False)
@@ -101,17 +101,17 @@ cr.commit()
# ----------------------------------------------------- #
for line in (
- "alter table ir_model_fields add group_name varchar(64)",
- "alter table ir_model_fields add view_load boolean",
- "alter table ir_model_fields alter group_name set default ''",
- "alter table ir_model_fields alter view_load set default False",
- "delete from ir_values where value like '%,False'",
- ):
- try:
- cr.execute(line)
- except psycopg.ProgrammingError, e:
- cr.commit()
- print e
+ "alter table ir_model_fields add group_name varchar(64)",
+ "alter table ir_model_fields add view_load boolean",
+ "alter table ir_model_fields alter group_name set default ''",
+ "alter table ir_model_fields alter view_load set default False",
+ "delete from ir_values where value like '%,False'",
+ ):
+ try:
+ cr.execute(line)
+ except psycopg.ProgrammingError, e:
+ cr.commit()
+ print e
cr.commit()
cr.close()
diff --git a/doc/migrate/3.4.0-4.0.0/post-tiny.py b/doc/migrate/3.4.0-4.0.0/post-tiny.py
index ff47b041398..5c3646de8a0 100644
--- a/doc/migrate/3.4.0-4.0.0/post-tiny.py
+++ b/doc/migrate/3.4.0-4.0.0/post-tiny.py
@@ -53,15 +53,15 @@ options.db_name = 'terp' # default value
parser.parse_args(values=options)
if hasattr(options, 'config'):
- configparser = ConfigParser.ConfigParser()
- configparser.read([options.config])
- for name, value in configparser.items('options'):
- if not (hasattr(options, name) and getattr(options, name)):
- if value in ('true', 'True'):
- value = True
- if value in ('false', 'False'):
- value = False
- setattr(options, name, value)
+ configparser = ConfigParser.ConfigParser()
+ configparser.read([options.config])
+ for name, value in configparser.items('options'):
+ if not (hasattr(options, name) and getattr(options, name)):
+ if value in ('true', 'True'):
+ value = True
+ if value in ('false', 'False'):
+ value = False
+ setattr(options, name, value)
# -----
diff --git a/doc/migrate/3.4.0-4.0.0/post.py b/doc/migrate/3.4.0-4.0.0/post.py
index 9afdd89c038..c90da55750a 100644
--- a/doc/migrate/3.4.0-4.0.0/post.py
+++ b/doc/migrate/3.4.0-4.0.0/post.py
@@ -53,15 +53,15 @@ options.db_name = 'terp' # default value
parser.parse_args(values=options)
if hasattr(options, 'config'):
- configparser = ConfigParser.ConfigParser()
- configparser.read([options.config])
- for name, value in configparser.items('options'):
- if not (hasattr(options, name) and getattr(options, name)):
- if value in ('true', 'True'):
- value = True
- if value in ('false', 'False'):
- value = False
- setattr(options, name, value)
+ configparser = ConfigParser.ConfigParser()
+ configparser.read([options.config])
+ for name, value in configparser.items('options'):
+ if not (hasattr(options, name) and getattr(options, name)):
+ if value in ('true', 'True'):
+ value = True
+ if value in ('false', 'False'):
+ value = False
+ setattr(options, name, value)
# -----
@@ -86,10 +86,10 @@ cr.commit()
# --------------- #
while True:
- cr.execute("select id from ir_ui_menu where (id not in (select parent_id from ir_ui_menu where parent_id is not null)) and (id not in (select res_id from ir_values where model='ir.ui.menu'))")
- if not cr.rowcount:
- break
- cr.execute("delete from ir_ui_menu where (id not in (select parent_id from ir_ui_menu where parent_id is not null)) and (id not in (select res_id from ir_values where model='ir.ui.menu'))")
+ cr.execute("select id from ir_ui_menu where (id not in (select parent_id from ir_ui_menu where parent_id is not null)) and (id not in (select res_id from ir_values where model='ir.ui.menu'))")
+ if not cr.rowcount:
+ break
+ cr.execute("delete from ir_ui_menu where (id not in (select parent_id from ir_ui_menu where parent_id is not null)) and (id not in (select res_id from ir_values where model='ir.ui.menu'))")
cr.commit()
# ----------------------------------------- #
@@ -114,7 +114,7 @@ It is not possible to migrate the data automatically so you need to create the o
And then update the field uos_id of the table account_invoice to match the new id of product_uom.
EXAMPLE:
- UPDATE account_invoice SET uos_id = new_id WHERE uos_id = old_id;
+ UPDATE account_invoice SET uos_id = new_id WHERE uos_id = old_id;
"""
cr.close()
diff --git a/doc/migrate/3.4.0-4.0.0/pre-tiny.py b/doc/migrate/3.4.0-4.0.0/pre-tiny.py
index fadcb2bc37e..c76e3520f5b 100644
--- a/doc/migrate/3.4.0-4.0.0/pre-tiny.py
+++ b/doc/migrate/3.4.0-4.0.0/pre-tiny.py
@@ -53,15 +53,15 @@ options.db_name = 'terp' # default value
parser.parse_args(values=options)
if hasattr(options, 'config'):
- configparser = ConfigParser.ConfigParser()
- configparser.read([options.config])
- for name, value in configparser.items('options'):
- if not (hasattr(options, name) and getattr(options, name)):
- if value in ('true', 'True'):
- value = True
- if value in ('false', 'False'):
- value = False
- setattr(options, name, value)
+ configparser = ConfigParser.ConfigParser()
+ configparser.read([options.config])
+ for name, value in configparser.items('options'):
+ if not (hasattr(options, name) and getattr(options, name)):
+ if value in ('true', 'True'):
+ value = True
+ if value in ('false', 'False'):
+ value = False
+ setattr(options, name, value)
# -----
@@ -79,18 +79,18 @@ cr = db.cursor()
# ------------------------- #
def change_column(cr, table, column, new_type, copy):
- commands = [
- "ALTER TABLE %s RENAME COLUMN %s TO temp_column" % (table, column),
- "ALTER TABLE %s ADD COLUMN %s %s" % (table, column, new_type),
- "ALTER TABLE %s DROP COLUMN temp_column" % table
- ]
- if copy:
- commands.insert(
- 2,
- "UPDATE %s SET %s=temp_column::%s" % (table, column, new_type))
-
- for command in commands:
- cr.execute(command)
+ commands = [
+ "ALTER TABLE %s RENAME COLUMN %s TO temp_column" % (table, column),
+ "ALTER TABLE %s ADD COLUMN %s %s" % (table, column, new_type),
+ "ALTER TABLE %s DROP COLUMN temp_column" % table
+ ]
+ if copy:
+ commands.insert(
+ 2,
+ "UPDATE %s SET %s=temp_column::%s" % (table, column, new_type))
+
+ for command in commands:
+ cr.execute(command)
#change_column(cr, 'crm_case', 'date_closed', 'timestamp', True)
cr.commit()
@@ -101,7 +101,7 @@ cr.commit()
cr.execute("SELECT name FROM ir_module_module")
if not cr.rowcount:
- for module in set(['base', 'marketing', 'subscription', 'account', 'base_partner_relation', 'audittrail', 'account_followup', 'product', 'hr', 'l10n_simple', 'crm', 'stock', 'hr_timesheet', 'purchase', 'report_purchase', 'mrp', 'sale', 'report_sale', 'delivery', 'project', 'sale_crm', 'hr_timesheet_project', 'scrum', 'report_project',
+ for module in set(['base', 'marketing', 'subscription', 'account', 'base_partner_relation', 'audittrail', 'account_followup', 'product', 'hr', 'l10n_simple', 'crm', 'stock', 'hr_timesheet', 'purchase', 'report_purchase', 'mrp', 'sale', 'report_sale', 'delivery', 'project', 'sale_crm', 'hr_timesheet_project', 'scrum', 'report_project',
'account_followup',
'account',
'audittrail',
@@ -131,8 +131,8 @@ if not cr.rowcount:
'sandwich',
'scrum',
'stock']):
- cr.execute("INSERT INTO ir_module_module (name, state) VALUES ('%s', 'installed')" % module)
- cr.commit()
+ cr.execute("INSERT INTO ir_module_module (name, state) VALUES ('%s', 'installed')" % module)
+ cr.commit()
# ----------------------------------------------------- #
@@ -140,11 +140,11 @@ if not cr.rowcount:
# ----------------------------------------------------- #
for line in (
- "ALTER TABLE ir_module_module ADD demo BOOLEAN DEFAULT False",
- "delete from ir_values where value like '%,False'",
- """UPDATE ir_ui_view set arch='<?xml version="1.0"?><tree string="Menu" toolbar="1"><field icon="icon" name="name"/></tree>' where name='ir.ui.menu.tree' and type='tree' and field_parent='child_id'""",
- ):
- cr.execute(line)
+ "ALTER TABLE ir_module_module ADD demo BOOLEAN DEFAULT False",
+ "delete from ir_values where value like '%,False'",
+ """UPDATE ir_ui_view set arch='<?xml version="1.0"?><tree string="Menu" toolbar="1"><field icon="icon" name="name"/></tree>' where name='ir.ui.menu.tree' and type='tree' and field_parent='child_id'""",
+ ):
+ cr.execute(line)
cr.commit()
cr.close()
diff --git a/doc/migrate/3.4.0-4.0.0/pre.py b/doc/migrate/3.4.0-4.0.0/pre.py
index 36cd4c17b97..ceb3683d1bc 100644
--- a/doc/migrate/3.4.0-4.0.0/pre.py
+++ b/doc/migrate/3.4.0-4.0.0/pre.py
@@ -53,15 +53,15 @@ options.db_name = 'terp' # default value
parser.parse_args(values=options)
if hasattr(options, 'config'):
- configparser = ConfigParser.ConfigParser()
- configparser.read([options.config])
- for name, value in configparser.items('options'):
- if not (hasattr(options, name) and getattr(options, name)):
- if value in ('true', 'True'):
- value = True
- if value in ('false', 'False'):
- value = False
- setattr(options, name, value)
+ configparser = ConfigParser.ConfigParser()
+ configparser.read([options.config])
+ for name, value in configparser.items('options'):
+ if not (hasattr(options, name) and getattr(options, name)):
+ if value in ('true', 'True'):
+ value = True
+ if value in ('false', 'False'):
+ value = False
+ setattr(options, name, value)
# -----
@@ -79,18 +79,18 @@ cr = db.cursor()
# ------------------------- #
def change_column(cr, table, column, new_type, copy):
- commands = [
- "ALTER TABLE %s RENAME COLUMN %s TO temp_column" % (table, column),
- "ALTER TABLE %s ADD COLUMN %s %s" % (table, column, new_type),
- "ALTER TABLE %s DROP COLUMN temp_column" % table
- ]
- if copy:
- commands.insert(
- 2,
- "UPDATE %s SET %s=temp_column::%s" % (table, column, new_type))
-
- for command in commands:
- cr.execute(command)
+ commands = [
+ "ALTER TABLE %s RENAME COLUMN %s TO temp_column" % (table, column),
+ "ALTER TABLE %s ADD COLUMN %s %s" % (table, column, new_type),
+ "ALTER TABLE %s DROP COLUMN temp_column" % table
+ ]
+ if copy:
+ commands.insert(
+ 2,
+ "UPDATE %s SET %s=temp_column::%s" % (table, column, new_type))
+
+ for command in commands:
+ cr.execute(command)
change_column(cr, 'crm_case', 'date_closed', 'timestamp', True)
cr.commit()
@@ -101,19 +101,19 @@ cr.commit()
cr.execute("SELECT name FROM ir_module_module")
if not cr.rowcount:
- for module in ('base', 'marketing', 'subscription', 'account', 'base_partner_relation', 'audittrail', 'account_followup', 'product', 'hr', 'l10n_simple', 'crm', 'stock', 'hr_timesheet', 'purchase', 'report_purchase', 'mrp', 'sale', 'report_sale', 'delivery', 'project', 'sale_crm', 'hr_timesheet_project', 'scrum', 'report_project'):
- cr.execute("INSERT INTO ir_module_module (name, state) VALUES ('%s', 'installed')" % module)
- cr.commit()
+ for module in ('base', 'marketing', 'subscription', 'account', 'base_partner_relation', 'audittrail', 'account_followup', 'product', 'hr', 'l10n_simple', 'crm', 'stock', 'hr_timesheet', 'purchase', 'report_purchase', 'mrp', 'sale', 'report_sale', 'delivery', 'project', 'sale_crm', 'hr_timesheet_project', 'scrum', 'report_project'):
+ cr.execute("INSERT INTO ir_module_module (name, state) VALUES ('%s', 'installed')" % module)
+ cr.commit()
# --------------- #
# remove old menu #
# --------------- #
while True:
- cr.execute("select id from ir_ui_menu where id not in (select parent_id from ir_ui_menu where parent_id is not null) and id not in (select res_id from ir_model_data where model='ir.ui.menu')")
- if not cr.rowcount:
- break
- cr.execute("delete from ir_ui_menu where id not in (select parent_id from ir_ui_menu where parent_id is not null) and id not in (select res_id from ir_model_data where model='ir.ui.menu')")
+ cr.execute("select id from ir_ui_menu where id not in (select parent_id from ir_ui_menu where parent_id is not null) and id not in (select res_id from ir_model_data where model='ir.ui.menu')")
+ if not cr.rowcount:
+ break
+ cr.execute("delete from ir_ui_menu where id not in (select parent_id from ir_ui_menu where parent_id is not null) and id not in (select res_id from ir_model_data where model='ir.ui.menu')")
cr.commit()
# ----------------------------------------------------- #
@@ -121,12 +121,12 @@ cr.commit()
# ----------------------------------------------------- #
for line in (
- "ALTER TABLE ir_module_module ADD demo BOOLEAN",
- "ALTER TABLE ir_module_module SET demo DEFAULT False",
- "DELETE FROM ir_values WHERE VALUE LIKE '%,False'",
- """UPDATE ir_ui_view set arch='<?xml version="1.0"?><tree string="Menu" toolbar="1"><field icon="icon" name="name"/></tree>' where name='ir.ui.menu.tree' and type='tree' and field_parent='child_id'""",
- ):
- cr.execute(line)
+ "ALTER TABLE ir_module_module ADD demo BOOLEAN",
+ "ALTER TABLE ir_module_module SET demo DEFAULT False",
+ "DELETE FROM ir_values WHERE VALUE LIKE '%,False'",
+ """UPDATE ir_ui_view set arch='<?xml version="1.0"?><tree string="Menu" toolbar="1"><field icon="icon" name="name"/></tree>' where name='ir.ui.menu.tree' and type='tree' and field_parent='child_id'""",
+ ):
+ cr.execute(line)
cr.commit()
cr.close()
diff --git a/doc/migrate/4.0.0-4.2.0/pre.py b/doc/migrate/4.0.0-4.2.0/pre.py
index cfa9b011aa9..e3f6d4905c3 100644
--- a/doc/migrate/4.0.0-4.2.0/pre.py
+++ b/doc/migrate/4.0.0-4.2.0/pre.py
@@ -54,15 +54,15 @@ options.db_name = 'terp' # default value
parser.parse_args(values=options)
if hasattr(options, 'config'):
- configparser = ConfigParser.ConfigParser()
- configparser.read([options.config])
- for name, value in configparser.items('options'):
- if not (hasattr(options, name) and getattr(options, name)):
- if value in ('true', 'True'):
- value = True
- if value in ('false', 'False'):
- value = False
- setattr(options, name, value)
+ configparser = ConfigParser.ConfigParser()
+ configparser.read([options.config])
+ for name, value in configparser.items('options'):
+ if not (hasattr(options, name) and getattr(options, name)):
+ if value in ('true', 'True'):
+ value = True
+ if value in ('false', 'False'):
+ value = False
+ setattr(options, name, value)
# -----
@@ -82,13 +82,13 @@ cr = db.cursor()
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='res_currency' AND a.attname='rounding' AND c.oid=a.attrelid AND a.atttypid=t.oid""")
res = cr.dictfetchall()
if res[0]['typname'] != 'numeric':
- for line in (
- "ALTER TABLE res_currency RENAME rounding TO rounding_bak",
- "ALTER TABLE res_currency ADD rounding NUMERIC(12,6)",
- "UPDATE res_currency SET rounding = power(10, - rounding_bak)",
- "ALTER TABLE res_currency DROP rounding_bak",
- ):
- cr.execute(line)
+ for line in (
+ "ALTER TABLE res_currency RENAME rounding TO rounding_bak",
+ "ALTER TABLE res_currency ADD rounding NUMERIC(12,6)",
+ "UPDATE res_currency SET rounding = power(10, - rounding_bak)",
+ "ALTER TABLE res_currency DROP rounding_bak",
+ ):
+ cr.execute(line)
cr.commit()
# ----------------------------- #
@@ -97,7 +97,7 @@ cr.commit()
cr.execute('SELECT conname FROM pg_constraint where conname = \'ir_ui_view_type\'')
if cr.fetchall():
- cr.execute('ALTER TABLE ir_ui_view DROP CONSTRAINT ir_ui_view_type')
+ cr.execute('ALTER TABLE ir_ui_view DROP CONSTRAINT ir_ui_view_type')
cr.commit()
# ------------------------ #
@@ -106,7 +106,7 @@ cr.commit()
cr.execute('SELECT a.attname FROM pg_class c, pg_attribute a WHERE c.relname = \'res_partner_bank\' AND a.attname = \'iban\' AND c.oid = a.attrelid')
if cr.fetchall():
- cr.execute('ALTER TABLE res_partner_bank RENAME iban TO acc_number')
+ cr.execute('ALTER TABLE res_partner_bank RENAME iban TO acc_number')
cr.commit()
# ------------------------------------------- #
@@ -115,12 +115,12 @@ cr.commit()
cr.execute('SELECT a.attname FROM pg_class c, pg_attribute a WHERE c.relname = \'ir_model\' AND a.attname = \'perm_id\' AND c.oid = a.attrelid')
if not cr.fetchall():
- cr.execute("ALTER TABLE ir_model ADD perm_id int references perm on delete set null")
+ cr.execute("ALTER TABLE ir_model ADD perm_id int references perm on delete set null")
cr.commit()
cr.execute('SELECT a.attname FROM pg_class c, pg_attribute a WHERE c.relname = \'ir_model_fields\' AND a.attname = \'perm_id\' AND c.oid = a.attrelid')
if not cr.fetchall():
- cr.execute("ALTER TABLE ir_model_fields ADD perm_id int references perm on delete set null")
+ cr.execute("ALTER TABLE ir_model_fields ADD perm_id int references perm on delete set null")
cr.commit()
@@ -138,9 +138,9 @@ cr.commit()
cr.execute('SELECT model_id FROM ir_model_access')
res= cr.fetchall()
for r in res:
- cr.execute('SELECT id FROM ir_model_access WHERE model_id = %d AND group_id IS NULL', (r[0],))
- if not cr.fetchall():
- cr.execute("INSERT into ir_model_access (name,model_id,group_id) VALUES ('Auto-generated access by migration',%d,NULL)",(r[0],))
+ cr.execute('SELECT id FROM ir_model_access WHERE model_id = %d AND group_id IS NULL', (r[0],))
+ if not cr.fetchall():
+ cr.execute("INSERT into ir_model_access (name,model_id,group_id) VALUES ('Auto-generated access by migration',%d,NULL)",(r[0],))
cr.commit()
# ------------------------------------------------- #
@@ -149,7 +149,7 @@ cr.commit()
cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_account_analytic_line_to_invoice\'')
if cr.fetchall():
- cr.execute('DROP VIEW report_account_analytic_line_to_invoice')
+ cr.execute('DROP VIEW report_account_analytic_line_to_invoice')
cr.commit()
# --------------------------- #
@@ -158,7 +158,7 @@ cr.commit()
cr.execute('SELECT * FROM pg_class c, pg_attribute a WHERE c.relname=\'hr_employee\' AND a.attname=\'state\' AND c.oid=a.attrelid')
if cr.fetchall():
- cr.execute('ALTER TABLE hr_employee DROP state')
+ cr.execute('ALTER TABLE hr_employee DROP state')
cr.commit()
# ------------ #
@@ -167,10 +167,10 @@ cr.commit()
cr.execute('SELECT id FROM ir_values where model=\'res.users\' AND key=\'meta\' AND name=\'tz\'')
if not cr.fetchall():
- import pytz, pickle
- meta = pickle.dumps({'type':'selection', 'string':'Timezone', 'selection': [(x, x) for x in pytz.all_timezones]})
- value = pickle.dumps(False)
- cr.execute('INSERT INTO ir_values (name, key, model, meta, key2, object, value) VALUES (\'tz\', \'meta\', \'res.users\', %s, \'tz\', %s, %s)', (meta,False, value))
+ import pytz, pickle
+ meta = pickle.dumps({'type':'selection', 'string':'Timezone', 'selection': [(x, x) for x in pytz.all_timezones]})
+ value = pickle.dumps(False)
+ cr.execute('INSERT INTO ir_values (name, key, model, meta, key2, object, value) VALUES (\'tz\', \'meta\', \'res.users\', %s, \'tz\', %s, %s)', (meta,False, value))
cr.commit()
# ------------------------- #
@@ -179,36 +179,36 @@ cr.commit()
cr.execute('SELECT a.attname FROM pg_class c, pg_attribute a, pg_type t WHERE c.relname = \'product_uom\' AND a.attname = \'factor\' AND c.oid = a.attrelid AND a.atttypid = t.oid AND t.typname = \'float8\'')
if cr.fetchall():
- cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_account_analytic_planning_stat_account\'')
- if cr.fetchall():
- cr.execute('DROP VIEW report_account_analytic_planning_stat_account')
- cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_account_analytic_planning_stat\'')
- if cr.fetchall():
- cr.execute('DROP VIEW report_account_analytic_planning_stat')
- cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_account_analytic_planning_stat_user\'')
- if cr.fetchall():
- cr.execute('DROP VIEW report_account_analytic_planning_stat_user')
- cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_purchase_order_product\'')
- if cr.fetchall():
- cr.execute('DROP VIEW report_purchase_order_product')
- cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_purchase_order_category\'')
- if cr.fetchall():
- cr.execute('DROP VIEW report_purchase_order_category')
- cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_sale_order_product\'')
- if cr.fetchall():
- cr.execute('DROP VIEW report_sale_order_product')
- cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_sale_order_category\'')
- if cr.fetchall():
- cr.execute('DROP VIEW report_sale_order_category')
- cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_hr_timesheet_invoice_journal\'')
- if cr.fetchall():
- cr.execute('DROP VIEW report_hr_timesheet_invoice_journal')
-
- cr.execute('ALTER TABLE product_uom RENAME COLUMN factor to temp_column')
- cr.execute('ALTER TABLE product_uom ADD COLUMN factor NUMERIC(12,6)')
- cr.execute('UPDATE product_uom SET factor = temp_column')
- cr.execute('ALTER TABLE product_uom ALTER factor SET NOT NULL')
- cr.execute('ALTER TABLE product_uom DROP COLUMN temp_column')
+ cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_account_analytic_planning_stat_account\'')
+ if cr.fetchall():
+ cr.execute('DROP VIEW report_account_analytic_planning_stat_account')
+ cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_account_analytic_planning_stat\'')
+ if cr.fetchall():
+ cr.execute('DROP VIEW report_account_analytic_planning_stat')
+ cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_account_analytic_planning_stat_user\'')
+ if cr.fetchall():
+ cr.execute('DROP VIEW report_account_analytic_planning_stat_user')
+ cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_purchase_order_product\'')
+ if cr.fetchall():
+ cr.execute('DROP VIEW report_purchase_order_product')
+ cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_purchase_order_category\'')
+ if cr.fetchall():
+ cr.execute('DROP VIEW report_purchase_order_category')
+ cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_sale_order_product\'')
+ if cr.fetchall():
+ cr.execute('DROP VIEW report_sale_order_product')
+ cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_sale_order_category\'')
+ if cr.fetchall():
+ cr.execute('DROP VIEW report_sale_order_category')
+ cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_hr_timesheet_invoice_journal\'')
+ if cr.fetchall():
+ cr.execute('DROP VIEW report_hr_timesheet_invoice_journal')
+
+ cr.execute('ALTER TABLE product_uom RENAME COLUMN factor to temp_column')
+ cr.execute('ALTER TABLE product_uom ADD COLUMN factor NUMERIC(12,6)')
+ cr.execute('UPDATE product_uom SET factor = temp_column')
+ cr.execute('ALTER TABLE product_uom ALTER factor SET NOT NULL')
+ cr.execute('ALTER TABLE product_uom DROP COLUMN temp_column')
cr.commit()
@@ -218,7 +218,7 @@ cr.commit()
cr.execute('SELECT conname FROM pg_constraint where conname = \'stock_production_lot_name_uniq\'')
if cr.fetchall():
- cr.execute('ALTER TABLE stock_production_lot DROP CONSTRAINT stock_production_lot_name_uniq')
+ cr.execute('ALTER TABLE stock_production_lot DROP CONSTRAINT stock_production_lot_name_uniq')
cr.commit()
# ------------------------------------ #
@@ -235,19 +235,19 @@ cr.commit()
cr.execute('SELECT indexname FROm pg_indexes WHERE indexname = \'ir_act_report_xml_pkey\' and tablename = \'ir_act_report_xml\'')
if not cr.fetchall():
- cr.execute('ALTER TABLE ir_act_report_xml ADD PRIMARY KEY (id)')
+ cr.execute('ALTER TABLE ir_act_report_xml ADD PRIMARY KEY (id)')
cr.execute('SELECT indexname FROm pg_indexes WHERE indexname = \'ir_act_report_custom_pkey\' and tablename = \'ir_act_report_custom\'')
if not cr.fetchall():
- cr.execute('ALTER TABLE ir_act_report_custom ADD PRIMARY KEY (id)')
+ cr.execute('ALTER TABLE ir_act_report_custom ADD PRIMARY KEY (id)')
cr.execute('SELECT indexname FROm pg_indexes WHERE indexname = \'ir_act_group_pkey\' and tablename = \'ir_act_group\'')
if not cr.fetchall():
- cr.execute('ALTER TABLE ir_act_group ADD PRIMARY KEY (id)')
+ cr.execute('ALTER TABLE ir_act_group ADD PRIMARY KEY (id)')
cr.execute('SELECT indexname FROm pg_indexes WHERE indexname = \'ir_act_execute_pkey\' and tablename = \'ir_act_execute\'')
if not cr.fetchall():
- cr.execute('ALTER TABLE ir_act_execute ADD PRIMARY KEY (id)')
+ cr.execute('ALTER TABLE ir_act_execute ADD PRIMARY KEY (id)')
cr.execute('SELECT indexname FROm pg_indexes WHERE indexname = \'ir_act_wizard_pkey\' and tablename = \'ir_act_wizard\'')
if not cr.fetchall():
- cr.execute('ALTER TABLE ir_act_wizard ADD PRIMARY KEY (id)')
+ cr.execute('ALTER TABLE ir_act_wizard ADD PRIMARY KEY (id)')
cr.commit()
cr.close
diff --git a/doc/migrate/4.0.0-4.2.0/tiny/pre-tiny.py b/doc/migrate/4.0.0-4.2.0/tiny/pre-tiny.py
index c341461ab81..b63fff6dda6 100644
--- a/doc/migrate/4.0.0-4.2.0/tiny/pre-tiny.py
+++ b/doc/migrate/4.0.0-4.2.0/tiny/pre-tiny.py
@@ -54,15 +54,15 @@ options.db_name = 'terp' # default value
parser.parse_args(values=options)
if hasattr(options, 'config'):
- configparser = ConfigParser.ConfigParser()
- configparser.read([options.config])
- for name, value in configparser.items('options'):
- if not (hasattr(options, name) and getattr(options, name)):
- if value in ('true', 'True'):
- value = True
- if value in ('false', 'False'):
- value = False
- setattr(options, name, value)
+ configparser = ConfigParser.ConfigParser()
+ configparser.read([options.config])
+ for name, value in configparser.items('options'):
+ if not (hasattr(options, name) and getattr(options, name)):
+ if value in ('true', 'True'):
+ value = True
+ if value in ('false', 'False'):
+ value = False
+ setattr(options, name, value)
raise Exception('This script is provided as an example, you must custom it before')
@@ -84,18 +84,18 @@ cr.execute('SELECT code from res_country where code is not null group by code')
res = cr.fetchall()
for c in res:
- cr.execute('SELECT max(id) from res_country where code = %s group by code', (c[0],))
- res2 = cr.fetchone()
- cr.execute('SELECT id from res_country where code = %s', (c[0],))
- ids = ','.join(map(lambda x: str(x[0]), cr.fetchall()))
- cr.execute('UPDATE res_partner_address set country_id = %d where country_id in ('+ids+')', (res2[0],))
- cr.execute('DELETE FROM res_country WHERE code = %s and id <> %d', (c[0], res2[0],))
+ cr.execute('SELECT max(id) from res_country where code = %s group by code', (c[0],))
+ res2 = cr.fetchone()
+ cr.execute('SELECT id from res_country where code = %s', (c[0],))
+ ids = ','.join(map(lambda x: str(x[0]), cr.fetchall()))
+ cr.execute('UPDATE res_partner_address set country_id = %d where country_id in ('+ids+')', (res2[0],))
+ cr.execute('DELETE FROM res_country WHERE code = %s and id <> %d', (c[0], res2[0],))
cr.commit()
cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_account_analytic_planning_stat\'')
if cr.fetchall():
- cr.execute('DROP VIEW report_account_analytic_planning_stat')
+ cr.execute('DROP VIEW report_account_analytic_planning_stat')
cr.commit()
@@ -104,59 +104,59 @@ res = cr.fetchall()
for p in res:
- cr.execute('SELECT max(id) FROM res_partner WHERE name = %s GROUP BY name', (p[0],))
- res2 = cr.fetchone()
- cr.execute('UPDATE res_partner set active = False WHERE name = %s and id <> %d', (p[0], res2[0],))
- cr.execute('SELECT id FROM res_partner WHERE name = %s AND id <> %d', (p[0], res2[0],))
- res3 = cr.fetchall()
- i = 0
- for id in res3:
- name = p[0]+' old'
- if i:
- name = name + ' ' + str(i)
- cr.execute('UPDATE res_partner set name = %s WHERE id = %d', (name, id[0]))
- i += 1
+ cr.execute('SELECT max(id) FROM res_partner WHERE name = %s GROUP BY name', (p[0],))
+ res2 = cr.fetchone()
+ cr.execute('UPDATE res_partner set active = False WHERE name = %s and id <> %d', (p[0], res2[0],))
+ cr.execute('SELECT id FROM res_partner WHERE name = %s AND id <> %d', (p[0], res2[0],))
+ res3 = cr.fetchall()
+ i = 0
+ for id in res3:
+ name = p[0]+' old'
+ if i:
+ name = name + ' ' + str(i)
+ cr.execute('UPDATE res_partner set name = %s WHERE id = %d', (name, id[0]))
+ i += 1
cr.commit()
cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_account_analytic_line_to_invoice\'')
if cr.fetchall():
- cr.execute('DROP VIEW report_account_analytic_line_to_invoice')
+ cr.execute('DROP VIEW report_account_analytic_line_to_invoice')
cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_timesheet_invoice\'')
if cr.fetchall():
- cr.execute('drop VIEW report_timesheet_invoice')
+ cr.execute('drop VIEW report_timesheet_invoice')
cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_purchase_order_category\'')
if cr.fetchall():
- cr.execute('drop VIEW report_purchase_order_category')
+ cr.execute('drop VIEW report_purchase_order_category')
cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_purchase_order_product\'')
if cr.fetchall():
- cr.execute('drop VIEW report_purchase_order_product')
+ cr.execute('drop VIEW report_purchase_order_product')
cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_sale_order_category\'')
if cr.fetchall():
- cr.execute('drop VIEW report_sale_order_category')
+ cr.execute('drop VIEW report_sale_order_category')
cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_sale_order_product\'')
if cr.fetchall():
- cr.execute('drop VIEW report_sale_order_product')
+ cr.execute('drop VIEW report_sale_order_product')
cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_timesheet_user\'')
if cr.fetchall():
- cr.execute('drop VIEW report_timesheet_user')
+ cr.execute('drop VIEW report_timesheet_user')
cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'report_task_user_pipeline_open\'')
if cr.fetchall():
- cr.execute('drop VIEW report_task_user_pipeline_open')
+ cr.execute('drop VIEW report_task_user_pipeline_open')
cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'hr_timesheet_sheet_sheet_day\'')
if cr.fetchall():
- cr.execute('drop VIEW hr_timesheet_sheet_sheet_day')
+ cr.execute('drop VIEW hr_timesheet_sheet_sheet_day')
cr.execute('SELECT viewname FROM pg_views WHERE viewname = \'hr_timesheet_sheet_sheet_account\'')
if cr.fetchall():
- cr.execute('drop VIEW hr_timesheet_sheet_sheet_account')
+ cr.execute('drop VIEW hr_timesheet_sheet_sheet_account')
cr.execute('SELECT viewname from pg_views where viewname = \'sale_journal_sale_stats\'')
if cr.fetchall():
- cr.execute('drop VIEW sale_journal_sale_stats')
+ cr.execute('drop VIEW sale_journal_sale_stats')
cr.execute('SELECT viewname from pg_views where viewname = \'sale_journal_picking_stats\'')
if cr.fetchall():
- cr.execute('drop VIEW sale_journal_picking_stats')
+ cr.execute('drop VIEW sale_journal_picking_stats')
cr.execute('SELECT viewname from pg_views where viewname = \'sale_journal_invoice_type_stats\'')
if cr.fetchall():
- cr.execute('drop VIEW sale_journal_invoice_type_stats')
+ cr.execute('drop VIEW sale_journal_invoice_type_stats')
cr.execute('ALTER TABLE product_template ALTER list_price TYPE numeric(16,2)')
cr.execute('ALTER TABLE product_template ALTER standard_price TYPE numeric(16,2)')
@@ -171,13 +171,13 @@ cr.commit()
cr.execute('SELECT tablename FROM pg_tables WHERE tablename = \'subscription_document_fields\'')
if cr.fetchall():
- cr.execute('DROP TABLE subscription_document_fields')
+ cr.execute('DROP TABLE subscription_document_fields')
cr.execute('SELECT tablename FROM pg_tables WHERE tablename = \'subscription_document\'')
if cr.fetchall():
- cr.execute('DROP TABLE subscription_document')
+ cr.execute('DROP TABLE subscription_document')
cr.execute('SELECT tablename FROM pg_tables WHERE tablename = \'subscription_subscription_history\'')
if cr.fetchall():
- cr.execute('DROP TABLE subscription_subscription_history')
+ cr.execute('DROP TABLE subscription_subscription_history')
cr.commit()
# -------------------- #
@@ -186,9 +186,9 @@ cr.commit()
cr.execute('SELECT a.attname FROM pg_class c, pg_attribute a WHERE c.relname = \'res_currency_rate\' AND a.attname = \'rate_old\' AND c.oid = a.attrelid')
if not cr.fetchall():
- cr.execute('ALTER TABLE res_currency_rate ADD rate_old NUMERIC(12,6)')
- cr.execute('UPDATE res_currency_rate SET rate_old = rate')
- cr.execute('UPDATE res_currency_rate SET rate = (1 / rate_old)')
+ cr.execute('ALTER TABLE res_currency_rate ADD rate_old NUMERIC(12,6)')
+ cr.execute('UPDATE res_currency_rate SET rate_old = rate')
+ cr.execute('UPDATE res_currency_rate SET rate = (1 / rate_old)')
cr.commit()
cr.close
diff --git a/doc/migrate/4.2.0-4.4.0/pre.py b/doc/migrate/4.2.0-4.4.0/pre.py
index ac8ed0a6017..8d0ad4243a0 100644
--- a/doc/migrate/4.2.0-4.4.0/pre.py
+++ b/doc/migrate/4.2.0-4.4.0/pre.py
@@ -54,15 +54,15 @@ options.db_name = 'terp' # default value
parser.parse_args(values=options)
if hasattr(options, 'config'):
- configparser = ConfigParser.ConfigParser()
- configparser.read([options.config])
- for name, value in configparser.items('options'):
- if not (hasattr(options, name) and getattr(options, name)):
- if value in ('true', 'True'):
- value = True
- if value in ('false', 'False'):
- value = False
- setattr(options, name, value)
+ configparser = ConfigParser.ConfigParser()
+ configparser.read([options.config])
+ for name, value in configparser.items('options'):
+ if not (hasattr(options, name) and getattr(options, name)):
+ if value in ('true', 'True'):
+ value = True
+ if value in ('false', 'False'):
+ value = False
+ setattr(options, name, value)
# -----
@@ -80,8 +80,8 @@ cr = db.cursor()
# ------------------------------ #
cr.execute('ALTER TABLE ir_attachment \
- ALTER COLUMN res_model DROP NOT NULL, \
- ALTER COLUMN res_id DROP NOT NULL')
+ ALTER COLUMN res_model DROP NOT NULL, \
+ ALTER COLUMN res_id DROP NOT NULL')
cr.commit()
# ---------------------------------- #
@@ -96,13 +96,13 @@ a.attname='date_deadline' AND c.oid=a.attrelid AND a.atttypid=t.oid""")
res = cr.dictfetchall()
if res[0]['typname'] != 'timestamp':
- for line in (
- "ALTER TABLE crm_case RENAME date_deadline TO date_deadline_bak",
- "ALTER TABLE crm_case ADD date_deadline timestamp",
- "UPDATE crm_case SET date_deadline = date_deadline_bak",
- "ALTER TABLE crm_case DROP date_deadline_bak",
- ):
- cr.execute(line)
+ for line in (
+ "ALTER TABLE crm_case RENAME date_deadline TO date_deadline_bak",
+ "ALTER TABLE crm_case ADD date_deadline timestamp",
+ "UPDATE crm_case SET date_deadline = date_deadline_bak",
+ "ALTER TABLE crm_case DROP date_deadline_bak",
+ ):
+ cr.execute(line)
cr.commit()
cr.execute('drop view report_task_user_pipeline_open');
diff --git a/doc/tests/check_profile_l10n_all.py b/doc/tests/check_profile_l10n_all.py
index 4404913fc80..d53d911adb8 100755..100644
--- a/doc/tests/check_profile_l10n_all.py
+++ b/doc/tests/check_profile_l10n_all.py
@@ -40,15 +40,15 @@ import base64
url = 'http://localhost:8069/xmlrpc'
profiles = [
- 'profile_accounting',
- 'profile_service',
- 'profile_manufacturing'
+ 'profile_accounting',
+ 'profile_service',
+ 'profile_manufacturing'
]
l10n_charts = [
- 'l10n_chart_uk_minimal',
- False,
- 'l10n_be',
- 'l10n_fr'
+ 'l10n_chart_uk_minimal',
+ False,
+ 'l10n_be',
+ 'l10n_fr'
]
dbname = 'test'
admin_passwd = 'admin'
@@ -64,62 +64,62 @@ demos = [True]
langs = lang or (map(lambda x: x[0], sock2.list_lang()) + ['en_US'])
def wait(id):
- progress=0.0
- while not progress==1.0:
- time.sleep(3)
- progress,users = sock2.get_progress(admin_passwd, id)
- time.sleep(3)
- return True
+ progress=0.0
+ while not progress==1.0:
+ time.sleep(3)
+ progress,users = sock2.get_progress(admin_passwd, id)
+ time.sleep(3)
+ return True
def wizard_run(wizname, fieldvalues={}, endstate='end'):
- wiz_id = sock4.create(dbname, uid, 'admin', wizname)
- state = 'init'
- datas = {'form':{}}
- while state!=endstate:
- res = sock4.execute(dbname, uid, 'admin', wiz_id, datas, state, {})
- if 'datas' in res:
- datas['form'].update( res['datas'] )
- if res['type']=='form':
- for field in res['fields'].keys():
- datas['form'][field] = res['fields'][field].get('value', False)
- state = res['state'][-1][0]
- datas['form'].update(fieldvalues)
- elif res['type']=='state':
- state = res['state']
- return True
+ wiz_id = sock4.create(dbname, uid, 'admin', wizname)
+ state = 'init'
+ datas = {'form':{}}
+ while state!=endstate:
+ res = sock4.execute(dbname, uid, 'admin', wiz_id, datas, state, {})
+ if 'datas' in res:
+ datas['form'].update( res['datas'] )
+ if res['type']=='form':
+ for field in res['fields'].keys():
+ datas['form'][field] = res['fields'][field].get('value', False)
+ state = res['state'][-1][0]
+ datas['form'].update(fieldvalues)
+ elif res['type']=='state':
+ state = res['state']
+ return True
for demo in demos:
- for l10n in l10n_charts:
- print 'Testing localisation', l10n, '...'
- for prof in profiles:
- print '\tTesting profile', prof, '...'
- id = sock2.create(admin_passwd, dbname, demo, lang)
- wait(id)
- uid = sock3.login(dbname, 'admin','admin')
+ for l10n in l10n_charts:
+ print 'Testing localisation', l10n, '...'
+ for prof in profiles:
+ print '\tTesting profile', prof, '...'
+ id = sock2.create(admin_passwd, dbname, demo, lang)
+ wait(id)
+ uid = sock3.login(dbname, 'admin','admin')
- idprof = sock.execute(dbname, uid, 'admin', 'ir.module.module', 'search', [('name','=',prof)])
- if l10n:
- idl10n = sock.execute(dbname, uid, 'admin', 'ir.module.module', 'search', [('name','=',l10n)])
- else:
- idl10n = [-1]
- wizard_run('base_setup.base_setup', {
- 'profile': idprof[0],
- 'charts': idl10n[0],
- }, 'menu')
- for lang in langs:
- print '\t\tTesting Language', lang, '...'
- wizard_run('module.lang.install', {'lang': lang})
+ idprof = sock.execute(dbname, uid, 'admin', 'ir.module.module', 'search', [('name','=',prof)])
+ if l10n:
+ idl10n = sock.execute(dbname, uid, 'admin', 'ir.module.module', 'search', [('name','=',l10n)])
+ else:
+ idl10n = [-1]
+ wizard_run('base_setup.base_setup', {
+ 'profile': idprof[0],
+ 'charts': idl10n[0],
+ }, 'menu')
+ for lang in langs:
+ print '\t\tTesting Language', lang, '...'
+ wizard_run('module.lang.install', {'lang': lang})
- ok = False
- range = 4
- while (not ok) and range:
- try:
- time.sleep(2)
- id = sock2.drop(admin_passwd, dbname)
- ok = True
- except:
- range -= 1
- time.sleep(2)
+ ok = False
+ range = 4
+ while (not ok) and range:
+ try:
+ time.sleep(2)
+ id = sock2.drop(admin_passwd, dbname)
+ ok = True
+ except:
+ range -= 1
+ time.sleep(2)
diff --git a/setup.py b/setup.py
index 2c8923f4f3b..2c8923f4f3b 100755..100644
--- a/setup.py
+++ b/setup.py
diff --git a/win32/TinyERPServerService.py b/win32/TinyERPServerService.py
index b39c0c6701a..ca07917ac94 100644
--- a/win32/TinyERPServerService.py
+++ b/win32/TinyERPServerService.py
@@ -72,15 +72,15 @@ class TinyERPServerService(win32serviceutil.ServiceFramework):
def StartTERP(self):
- # The server finds now its configuration automatically on Windows
- # We start the ERP Server as an independent process, but we keep its handle
- # The server's binary must be one directory above the service's binary (when py2exe'd the python libraries shouldn' mix)
- service_dir = os.path.dirname(sys.argv[0])
- server_dir = os.path.split(service_dir)[0]
- server_path = os.path.join(server_dir, 'tinyerp-server.exe')
- self.terpprocess = subprocess.Popen([server_path], \
+ # The server finds now its configuration automatically on Windows
+ # We start the ERP Server as an independent process, but we keep its handle
+ # The server's binary must be one directory above the service's binary (when py2exe'd the python libraries shouldn' mix)
+ service_dir = os.path.dirname(sys.argv[0])
+ server_dir = os.path.split(service_dir)[0]
+ server_path = os.path.join(server_dir, 'tinyerp-server.exe')
+ self.terpprocess = subprocess.Popen([server_path], \
cwd=server_dir,
- creationflags=win32process.CREATE_NO_WINDOW)
+ creationflags=win32process.CREATE_NO_WINDOW)
def StartControl(self,ws):
@@ -89,15 +89,15 @@ class TinyERPServerService(win32serviceutil.ServiceFramework):
self.stopping = True
def SvcDoRun(self):
- # Start Tiny ERP Server itself
+ # Start Tiny ERP Server itself
self.StartTERP()
# start the loop waiting for the Service Manager's stop signal
- thread.start_new_thread(self.StartControl, (self.hWaitStop,))
- # Log a info message that the server is running
- servicemanager.LogInfoMsg("Tiny ERP Server up and running")
- # verification if the server is really running, else quit with an error
+ thread.start_new_thread(self.StartControl, (self.hWaitStop,))
+ # Log a info message that the server is running
+ servicemanager.LogInfoMsg("Tiny ERP Server up and running")
+ # verification if the server is really running, else quit with an error
self.terpprocess.wait()
- if not self.stopping:
+ if not self.stopping:
sys.exit("Tiny ERP Server check: server not running, check the logfile for more info")