Merge commit 'origin/master' into mdv-gpl3

Conflicts:
	bin/report/interface.py
	bin/tools/translate.py

bzr revid: p_christ@hol.gr-20081215095422-9jc4m1qrknku6ux8
This commit is contained in:
P. Christeas 2008-12-15 11:54:22 +02:00
commit 087f5bc171
62 changed files with 1675 additions and 1213 deletions

View File

@ -138,7 +138,7 @@ def get_module_path(module):
if os.path.exists(opj(_ad, module)) or os.path.exists(opj(_ad, '%s.zip' % module)):
return opj(_ad, module)
logger.notifyChannel('init', netsvc.LOG_WARNING, 'addon %s: module not found' % (module,))
logger.notifyChannel('init', netsvc.LOG_WARNING, 'module %s: module not found' % (module,))
return False
raise IOError, 'Module not found : %s' % module
@ -216,7 +216,7 @@ def create_graph(module_list, force=None):
try:
info = eval(tools.file_open(terp_file).read())
except:
logger.notifyChannel('init', netsvc.LOG_ERROR, 'addon %s: eval file %s' % (module, terp_file))
logger.notifyChannel('init', netsvc.LOG_ERROR, 'module %s: eval file %s' % (module, terp_file))
raise
if info.get('installable', True):
packages.append((module, info.get('depends', []), info))
@ -246,18 +246,25 @@ def create_graph(module_list, force=None):
for package in later:
unmet_deps = filter(lambda p: p not in graph, dependencies[package])
logger.notifyChannel('init', netsvc.LOG_ERROR, 'addon %s: Unmet dependencies: %s' % (package, ', '.join(unmet_deps)))
logger.notifyChannel('init', netsvc.LOG_ERROR, 'module %s: Unmet dependencies: %s' % (package, ', '.join(unmet_deps)))
return graph
def init_module_objects(cr, module_name, obj_list):
pool = pooler.get_pool(cr.dbname)
logger.notifyChannel('init', netsvc.LOG_INFO, 'addon %s: creating or updating database tables' % module_name)
logger.notifyChannel('init', netsvc.LOG_INFO, 'module %s: creating or updating database tables' % module_name)
todo = []
for obj in obj_list:
if hasattr(obj, 'init'):
obj.init(cr)
obj._auto_init(cr, {'module': module_name})
result = obj._auto_init(cr, {'module': module_name})
if result:
todo += result
cr.commit()
todo.sort()
for t in todo:
t[1](cr, *t[2])
cr.commit()
#
# Register module named m, if not already registered
@ -266,7 +273,7 @@ def register_class(m):
global loaded
if m in loaded:
return
logger.notifyChannel('init', netsvc.LOG_INFO, 'addon %s: registering classes' % m)
logger.notifyChannel('init', netsvc.LOG_INFO, 'module %s: registering objects' % m)
loaded.append(m)
mod_path = get_module_path(m)
if not os.path.isfile(mod_path+'.zip'):
@ -380,7 +387,7 @@ class MigrationManager(object):
from tools.parse_version import parse_version
parsed_installed_version = parse_version(pkg.latest_version)
parsed_installed_version = parse_version(pkg.installed_version or '')
current_version = parse_version(convert_version(pkg.data.get('version', '0')))
versions = _get_migration_versions(pkg)
@ -401,20 +408,20 @@ class MigrationManager(object):
mod = None
try:
mod = imp.load_source(name, pyfile, fp)
logger.notifyChannel('migration', netsvc.LOG_INFO, 'addon %(addon)s: Running migration %(version)s %(name)s"' % mergedict({'name': mod.__name__},strfmt))
mod.migrate(self.cr, pkg.latest_version)
logger.notifyChannel('migration', netsvc.LOG_INFO, 'module %(addon)s: Running migration %(version)s %(name)s"' % mergedict({'name': mod.__name__},strfmt))
mod.migrate(self.cr, pkg.installed_version)
except ImportError:
logger.notifyChannel('migration', netsvc.LOG_ERROR, 'addon %(addon)s: Unable to load %(stage)-migration file %(file)s' % mergedict({'file': opj(modulename,pyfile)}, strfmt))
logger.notifyChannel('migration', netsvc.LOG_ERROR, 'module %(addon)s: Unable to load %(stage)-migration file %(file)s' % mergedict({'file': opj(modulename,pyfile)}, strfmt))
raise
except AttributeError:
logger.notifyChannel('migration', netsvc.LOG_ERROR, 'addon %(addon)s: Each %(stage)-migration file must have a "migrate(cr, installed_version)" function' % strfmt)
logger.notifyChannel('migration', netsvc.LOG_ERROR, 'module %(addon)s: Each %(stage)-migration file must have a "migrate(cr, installed_version)" function' % strfmt)
except:
raise
fp.close()
del mod
def load_module_graph(cr, graph, status=None, **kwargs):
def load_module_graph(cr, graph, status=None, check_access_rules=True, **kwargs):
# **kwargs is passed directly to convert_xml_import
if not status:
status={}
@ -427,13 +434,14 @@ def load_module_graph(cr, graph, status=None, **kwargs):
# update the graph with values from the database (if exist)
## First, we set the default values for each package in graph
additional_data = dict.fromkeys([p.name for p in graph], {'id': 0, 'state': 'uninstalled', 'dbdemo': False, 'latest_version': None})
additional_data = dict.fromkeys([p.name for p in graph], {'id': 0, 'state': 'uninstalled', 'dbdemo': False, 'installed_version': None})
## Then we get the values from the database
cr.execute('SELECT name, id, state, demo AS dbdemo, latest_version'
cr.execute('SELECT name, id, state, demo AS dbdemo, latest_version AS installed_version'
' FROM ir_module_module'
' WHERE name in (%s)' % (','.join(['%s'] * len(graph))),
additional_data.keys()
)
## and we update the default values with values from the database
additional_data.update(dict([(x.pop('name'), x) for x in cr.dictfetchall()]))
@ -443,6 +451,7 @@ def load_module_graph(cr, graph, status=None, **kwargs):
migrations = MigrationManager(cr, graph)
check_rules = False
for package in graph:
status['progress'] = (float(statusi)+0.1)/len(graph)
m = package.name
@ -451,19 +460,20 @@ def load_module_graph(cr, graph, status=None, **kwargs):
migrations.migrate_module(package, 'pre')
register_class(m)
logger.notifyChannel('init', netsvc.LOG_INFO, 'addon %s' % m)
logger.notifyChannel('init', netsvc.LOG_INFO, 'module %s loading objects' % m)
modules = pool.instanciate(m, cr)
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'):
check_rules = True
init_module_objects(cr, m, modules)
for kind in ('init', 'update'):
for filename in package.data.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))
logger.notifyChannel('init', netsvc.LOG_INFO, 'module %s: loading %s' % (m, filename))
name, ext = os.path.splitext(filename)
fp = tools.file_open(opj(m, filename))
if ext == '.csv':
@ -481,17 +491,18 @@ def load_module_graph(cr, graph, status=None, **kwargs):
status['progress'] = (float(statusi)+0.75)/len(graph)
for xml in package.data.get('demo_xml', []):
name, ext = os.path.splitext(xml)
logger.notifyChannel('init', netsvc.LOG_INFO, 'addon %s: loading %s' % (m, xml))
logger.notifyChannel('init', netsvc.LOG_INFO, 'module %s: loading %s' % (m, xml))
fp = tools.file_open(opj(m, xml))
if ext == '.csv':
tools.convert_csv_import(cr, m, os.path.basename(xml), fp.read(), idref, noupdate=True)
else:
tools.convert_xml_import(cr, m, fp, idref, noupdate=True, **kwargs)
fp.close()
cr.execute('update ir_module_module set demo=%s where id=%d', (True, mid))
cr.execute('update ir_module_module set demo=%s where id=%s', (True, mid))
package_todo.append(package.name)
ver = release.major_version + '.' + package.data.get('version', '1.0')
cr.execute("update ir_module_module set state='installed', latest_version=%s where id=%d", (ver, mid,))
# update the installed version in database...
cr.execute("update ir_module_module set state='installed', latest_version=%s where id=%s", (ver, mid,))
cr.commit()
# Set new modules and dependencies
@ -501,18 +512,18 @@ def load_module_graph(cr, graph, status=None, **kwargs):
if modobj:
modobj.update_translations(cr, 1, [mid], None)
cr.commit()
migrations.migrate_module(package, 'post')
statusi+=1
cr.execute("""select model,name from ir_model where id not in (select model_id from ir_model_access)""")
for (model,name) in cr.fetchall():
logger.notifyChannel('init', netsvc.LOG_WARNING, 'addon object %s (%s) has no access rules!' % (model,name))
if check_access_rules and check_rules:
cr.execute("""select model,name from ir_model where id not in (select model_id from ir_model_access)""")
for (model,name) in cr.fetchall():
logger.notifyChannel('init', netsvc.LOG_WARNING, 'object %s (%s) has no access rules!' % (model,name))
pool = pooler.get_pool(cr.dbname)
cr.execute('select * from ir_model where state=%s', ('manual',))
cr.execute('select model from ir_model where state=%s', ('manual',))
for model in cr.dictfetchall():
pool.get('ir.model').instanciate(cr, 1, model['model'], {})
@ -527,31 +538,46 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
if force_demo:
force.append('demo')
pool = pooler.get_pool(cr.dbname)
report = tools.assertion_report()
if update_module:
for module in tools.config['init']:
cr.execute('update ir_module_module set state=%s where state=%s and name=%s', ('to install', 'uninstalled', module))
cr.commit()
basegraph = create_graph(['base'], force)
load_module_graph(cr, basegraph, status, check_access_rules=False, report=report)
register_class('base')
pool.instanciate('base', cr)
modobj = pool.get('ir.module.module')
modobj = pool.get('ir.module.module')
logger.notifyChannel('init', netsvc.LOG_INFO, 'updating modules list')
cr.execute("select id from ir_module_module where state in ('to install','to upgrade') and name=%s", ('base',))
if cr.rowcount:
modobj.update_list(cr, 1)
mids = modobj.search(cr, 1, [('state','in',('installed','to install'))])
for m in modobj.browse(cr, 1, mids):
for dep in m.dependencies_id:
if dep.state=='uninstalled':
modobj.button_install(cr, 1, [m.id])
cr.execute("select name from ir_module_module where state in ('installed', 'to install', 'to upgrade','to remove')")
mods = [k for k in tools.config['init'] if tools.config['init'][k]]
if mods:
ids = modobj.search(cr, 1, ['&', ('state', '=', 'uninstalled'), ('name', 'in', mods)])
if ids:
modobj.button_install(cr, 1, ids)
mods = [k for k in tools.config['update'] if tools.config['update'][k]]
if mods:
ids = modobj.search(cr, 1, ['&',('state', '=', 'installed'), ('name', 'in', mods)])
if ids:
modobj.button_upgrade(cr, 1, ids)
cr.execute("update ir_module_module set state=%s where name=%s", ('installed', 'base'))
cr.execute("select name from ir_module_module where state in ('installed', 'to install', 'to upgrade')")
else:
cr.execute("select name from ir_module_module where state in ('installed', 'to upgrade', 'to remove')")
cr.execute("select name from ir_module_module where state in ('installed', 'to upgrade')")
module_list = [name for (name,) in cr.fetchall()]
graph = create_graph(module_list, force)
report = tools.assertion_report()
# the 'base' module has already been updated
base = graph['base']
base.state = 'installed'
for kind in ('init', 'demo', 'update'):
if hasattr(base, kind):
delattr(base, kind)
load_module_graph(cr, graph, status, report=report)
if report.get_report():
logger.notifyChannel('init', netsvc.LOG_INFO, 'assert: %s' % report)
logger.notifyChannel('init', netsvc.LOG_INFO, report)
for kind in ('init', 'demo', 'update'):
tools.config[kind]={}
@ -563,29 +589,29 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
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'))''')
while True:
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'))''')
if not cr.rowcount:
break
else:
logger.notifyChannel('init', netsvc.LOG_INFO, 'removed %d unused menus' % (cr.rowcount,))
cr.execute("update ir_module_module set state=%s where state in ('to remove')", ('uninstalled', ))
cr.commit()
pooler.restart_pool(cr.dbname)
#pooler.restart_pool(cr.dbname)
cr.close()

View File

@ -21,9 +21,9 @@
##############################################################################
{
"name" : "Base",
"version" : "1.0",
"version" : "1.1",
"author" : "Tiny",
"website" : "http://openerp.com",
"website" : "http://www.openerp.com",
"category" : "Generic Modules/Base",
"description": "The kernel of OpenERP, needed for all installation.",
"depends" : [],

View File

@ -2,7 +2,11 @@
<openerp>
<data>
<menuitem icon="terp-administration" id="menu_administration" name="Administration" sequence="20"/>
<menuitem id="menu_custom" name="Custom" parent="base.menu_administration" sequence="2"/>
<menuitem id="next_id_4" name="Low Level Objects" parent="base.menu_administration" sequence="3"/>
<menuitem id="menu_low_workflow" name="Workflow Items" parent="base.next_id_4"/>
<menuitem id="menu_custom" name="Customization" parent="base.menu_administration" sequence="2"/>
<menuitem id="menu_custom_action" name="Actions" parent="base.menu_custom" sequence="20"/>
<menuitem id="menu_config" name="Configuration" parent="base.menu_administration" sequence="1"/>
<menuitem id="menu_translation" name="Translations" parent="base.menu_administration" sequence="4"/>
<menuitem id="menu_translation_app" name="Application Terms" parent="base.menu_translation" sequence="4"/>
<menuitem id="menu_translation_export" name="Import / Export" parent="base.menu_translation" sequence="4"/>

View File

@ -6,7 +6,7 @@
Languages
======================
-->
<menuitem id="next_id_2" name="Interface" parent="base.menu_custom"/>
<menuitem id="next_id_2" name="User Interface" parent="base.menu_custom"/>
<!--
======================

View File

@ -41,7 +41,7 @@
</record>
<record id="act_values_form" model="ir.actions.act_window">
<field name="name">Values</field>
<field name="name">Client Actions Connections</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.values</field>
<field name="view_type">form</field>
@ -49,7 +49,6 @@
<field name="context">{'read':'default'}</field>
</record>
<menuitem id="next_id_4" name="Low Level" parent="menu_custom"/>
<menuitem action="act_values_form" id="menu_values_form" parent="next_id_4"/>
<!-- Sequences -->
@ -114,7 +113,7 @@
<field name="view_id" ref="sequence_view_tree"/>
<field name="context">{'active_test': False}</field>
</record>
<menuitem id="next_id_5" name="Sequences" parent="base.menu_custom"/>
<menuitem id="next_id_5" name="Sequences" parent="base.menu_config"/>
<menuitem action="ir_sequence_form" id="menu_ir_sequence_form" parent="next_id_5"/>
<!-- Sequences Types -->
@ -152,7 +151,6 @@
<field name="name" select="1"/>
<field name="type" select="1"/>
<field name="usage"/>
<field name="parent_id"/>
</form>
</field>
</record>
@ -465,7 +463,7 @@
<field name="model">ir.ui.view</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="User Interface - Views">
<form string="Views">
<field name="name" select="1"/>
<field name="type" select="1"/>
<field name="model" select="1"/>
@ -481,7 +479,7 @@
<field name="model">ir.ui.view</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree>
<tree string="Views">
<field name="name"/>
<field name="type"/>
<field name="model"/>
@ -489,7 +487,7 @@
</field>
</record>
<record id="action_ui_view" model="ir.actions.act_window">
<field name="name">View</field>
<field name="name">Views</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.ui.view</field>
<field name="view_id" ref="view_view_tree"/>
@ -690,9 +688,9 @@
<group colspan="2" col="2">
<separator string="Field Type" colspan="2"/>
<field name="ttype" select="2"/>
<field name="relation" select="2" attrs="{'required': [('ttype','in',['many2one','one2many','many2many'])],
'readonly': [('ttype','not in', ['many2one','one2many','many2many'])]}"/>
<field name="relation_field" attrs="{'required': [('ttype','=','one2many')],
<field name="relation_id" select="2" attrs="{'required': [('ttype','in',['many2one','one2many','many2many'])],
'readonly': [('ttype','!=','one2many'), ('ttype','!=','many2one'), ('ttype','!=','many2many')]}"/>
<field name="relation_field_id" domain="[('model_id','=',relation_id)]" attrs="{'required': [('ttype','=','one2many')],
'readonly': [('ttype','!=','one2many')]}"/>
<field name="selection" attrs="{'required': [('ttype','=','selection')], 'readonly': [('ttype','!=','selection')]}"/>
<field name="size" attrs="{'required': [('ttype','=','char')], 'readonly': [('ttype','!=','char')]}"/>
@ -720,7 +718,7 @@
</page>
<page string="Access Rights">
<field colspan="4" name="access_ids" select="1" nolabel="1">
<tree string="Access Rules" editable="bottom" colspan="4">
<tree string="Access Rules" editable="bottom">
<field name="group_id"/>
<field name="perm_read"/>
<field name="perm_write"/>
@ -769,9 +767,11 @@
<page string="Properties">
<group colspan="2" col="2">
<field name="ttype" select="2"/>
<field name="relation" select="2" attrs="{'required': [('ttype','in', ['many2one','one2many','many2many'])],
<field name="relation_id" select="2" on_change="on_relation_change(relation_id)" attrs="{'required': [('ttype','in', ['many2one','one2many','many2many'])],
'readonly': [('ttype','not in', ['many2one','one2many','many2many'])]}"/>
<field name="relation_field" attrs="{'required': [('ttype','=','one2many')],
<!-- <field name="relation" select="2" attrs="{'required': [('ttype','in', ['many2one','one2many','many2many'])],-->
<!-- 'readonly': [('ttype','not in', ['many2one','one2many','many2many'])]}"/>-->
<field name="relation_field_id" domain="[('model_id','=',relation_id)]" attrs="{'required': [('ttype','=','one2many')],
'readonly': [('ttype','!=','one2many')]}"/>
<field name="selection" attrs="{'required': [('ttype','=','selection')], 'readonly': [('ttype','!=','selection')]}"/>
<field name="size" attrs="{'required': [('ttype','=','char')], 'readonly': [('ttype','!=','char')]}"/>
@ -787,7 +787,7 @@
<field name="on_delete" attrs="{'readonly': [('ttype','!=','many2one')]}"/>
</group>
</page>
<page string="Security on Groups" colspan="4">
<page string="Security on Groups">
<field name="groups" colspan="4" nolabel="1"/>
</page>
</notebook>
@ -934,7 +934,7 @@
</field>
</record>
<record id="grant_menu_access" model="ir.actions.act_window">
<field name="name">Grant access to menu</field>
<field name="name">Grant Access To Menus</field>
<field name="res_model">ir.ui.menu</field>
<field name="view_type">form</field>
<field name="view_id" ref="edit_menu"/>
@ -992,7 +992,7 @@
<field name="context">{'active_test': False}</field>
<field name="view_id" ref="ir_cron_view_tree"/>
</record>
<menuitem id="next_id_10" name="Scheduler" parent="base.menu_custom"/>
<menuitem id="next_id_10" name="Scheduler" parent="base.menu_config"/>
<menuitem action="ir_cron_act" id="menu_ir_cron_act" parent="next_id_10"/>
@ -1143,15 +1143,16 @@
<field name="model_id" select="1"/>
<field name="sequence" select="2"/>
<notebook colspan="4">
<page string="Python Code" attrs="{'invisible':[('state','!=','python')]}">
<!--<page string="Python Code" attrs="{'invisible':[('state','!=','python')]}">
<separator colspan="4" string="Python code"/>
<field name="code" colspan="4" nolabel="1" />
<button string="Create Action" name="%(wizard_server_action_create)d" type="action"/>
</page>
<page string="Trigger" attrs="{'invisible':[('state','!=','trigger')]}">
--><page string="Trigger" attrs="{'invisible':[('state','!=','trigger')]}">
<separator colspan="4" string="Trigger Configuration"/>
<field name="trigger_obj_id" select="2" colspan="4"/>
<field name="wkf_model_id"/>
<field name="trigger_obj_id" select="2" domain="[('model_id','=',model_id)]" on_change="on_trigger_obj_id(trigger_obj_id)"/>
<field name="trigger_name" select="2"/>
</page>
@ -1159,42 +1160,49 @@
<field name="action_id" select="2" colspan="4"/>
</page>
<page string="Email / SMS" attrs="{'invisible':[('state','!=','sms'),('state','!=','email')]}">
<page string="Email Configuration" attrs="{'invisible':[('state','!=','email')]}">
<separator colspan="4" string="Email Configuration"/>
<field name="address" domain="[('model_id','=',model_id)]"/>
<field name="sms" colspan="4" attrs="{'readonly':[('state','!=','sms')]}"/>
<field name="message" select="2" colspan="4" attrs="{'readonly':[('state','!=','email')]}" />
<field name="email" domain="[('model_id','=',model_id)]"/>
<field name="message" select="2" colspan="4"/>
<newline/>
<label colspan="4" string="Access all the fields related to the current object using expression in double brackets, i.e. [[ object.partner_id.name ]]" align="0.0"/>
</page>
<page string="SMS Configuration" attrs="{'invisible':[('state','!=','sms')]}">
<separator colspan="4" string="SMS Configuration"/>
<field name="mobile" domain="[('model_id','=',model_id)]"/>
<field name="sms" colspan="4"/>
<newline/>
<label colspan="4" string="Access all the fields related to the current object using expression in double brackets, i.e. [[ object.partner_id.name ]]" align="0.0"/>
</page>
<page string="Create / Write" attrs="{'invisible':[('state','!=','object_create'),('state','!=','object_write')]}">
<separator colspan="4" string="Fields Mapping"/>
<field name="otype"/>
<field name="srcmodel_id" select="2"/>
<field name="fields_lines" nolabel="1" select="2" colspan="4">
<tree string="Field Mappings" editable="top">
<field name="col1" domain="[('model_id','=',parent.srcmodel_id or parent.model_id)]"/>
<field name="type"/>
<field name="value" colsapan="4"/>
<field name="value" colspan="4"/>
</tree>
<form string="Field Mapping">
<field name="col1" domain="[('model_id','=',parent.srcmodel_id or parent.model_id)]"/>
<field name="type"/>
<field name="value" colsapan="4"/>
<field name="value" colspan="4"/>
</form>
</field>
<field name="record_id" attrs="{'invisible':[('state','!=','object_create')]}" domain="[('model_id','in',[model_id])]"/>
<label colspan="4" string="If you use a formula type, use a python expression using the variable 'object'." align="0.0"/>
</page>
<page string="Other Actions" attrs="{'invisible':[('state','!=','other')]}">
<page string="Multi Actions" attrs="{'invisible':[('state','!=','other')]}">
<separator colspan="4" string="Other Actions Configuration"/>
<field name="child_ids" nolabel="1" colspan="4" />
<field name="child_ids" nolabel="1" colspan="4"/>
<label colspan="4" string="Only one client action will be execute, last clinent action will be consider in case of multipls clinets actions" align="0.0"/>
</page>
</notebook>
<field name="usage"/>
<field name="type"/>
<field name="type" readonly="1"/>
</form>
</field>
</record>
@ -1219,7 +1227,7 @@
<field name="view_id" ref="view_server_action_tree"/>
<field name="context">{'key':'server_action'}</field>
</record>
<menuitem action="action_server_action" id="menu_server_action" parent="base.next_id_6"/>
<menuitem action="action_server_action" id="menu_server_action" parent="base.menu_custom_action"/>
<record id="view_model_fields_tree" model="ir.ui.view">
<field name="name">ir.model.fields.tree</field>
@ -1279,7 +1287,8 @@
<field name="view_type">form</field>
<field name="domain">[('type','=','configure')]</field>
</record>
<menuitem id="next_id_11" name="Configuration Wizards" parent="base.menu_custom"/><menuitem action="act_ir_actions_todo_form" id="menu_ir_actions_todo_form" parent="next_id_11"/>
<menuitem id="next_id_11" name="Configuration Wizards" parent="base.menu_config" sequence="1"/>
<menuitem action="act_ir_actions_todo_form" id="menu_ir_actions_todo_form" parent="next_id_11"/>
<record id="view_config_wizard_form" model="ir.ui.view">
<field name="name">Main Configuration Wizard</field>

View File

@ -34,7 +34,6 @@ class actions(osv.osv):
'name': fields.char('Action Name', required=True, size=64),
'type': fields.char('Action Type', required=True, size=32),
'usage': fields.char('Action Usage', size=32),
'parent_id': fields.many2one('ir.actions.server', 'Parent Action'),
}
_defaults = {
'usage': lambda *a: False,
@ -291,7 +290,7 @@ class ir_model_fields(osv.osv):
'complete_name': fields.char('Complete Name', size=64, select=1),
}
def name_search(self, cr, uid, name, args=None, operator='ilike', context=None, limit=80):
def name_search(self, cr, uid, name, args=None, operator='ilike', context=None, limit=800):
def get_fields(cr, uid, field, rel):
result = []
mobj = self.pool.get('ir.model')
@ -366,6 +365,23 @@ server_object_lines()
# Actions that are run on the server side
#
class actions_server(osv.osv):
def _select_signals(self, cr, uid, context={}):
cr.execute("select distinct t.signal as key, t.signal || ' - [ ' || w.osv || ' ] ' as val from wkf w, wkf_activity a, wkf_transition t "\
" where w.id = a.wkf_id " \
" and t.act_from = a.wkf_id " \
" or t.act_to = a.wkf_id ")
return cr.fetchall()
def on_trigger_obj_id(self, cr, uid, ids, context={}):
cr.execute("select distinct t.signal as key, t.signal as val from wkf w, wkf_activity a, wkf_transition t "\
" where w.id = a.wkf_id " \
" and t.act_from = a.wkf_id " \
" or t.act_to = a.wkf_id " \
" and w.osv = %s ", ('account.invoice'))
data = cr.fetchall()
return {"values":{'trigger_name':data}}
_name = 'ir.actions.server'
_table = 'ir_act_server'
_sequence = 'ir_actions_id_seq'
@ -373,33 +389,31 @@ class actions_server(osv.osv):
'name': fields.char('Action Name', required=True, size=64),
'state': fields.selection([
('client_action','Client Action'),
('python','Python Code'),
('dummy','Dummy'),
('trigger','Trigger'),
('email','Email'),
('sms','SMS'),
('object_create','Create Object'),
('object_write','Write Object'),
('other','Others Actions'),
('other','Multi Actions'),
], 'Action State', required=True, size=32),
'code': fields.text('Python Code'),
'sequence': fields.integer('Sequence'),
'model_id': fields.many2one('ir.model', 'Object', required=True),
'action_id': fields.many2one('ir.actions.actions', 'Client Action'),
'trigger_name': fields.char('Trigger Name', size=128),
'trigger_obj_id': fields.reference('Trigger On', selection=model_get, size=128),
'trigger_name': fields.selection(_select_signals, string='Trigger Name', size=128),
'wkf_model_id': fields.many2one('ir.model', 'Workflow on'),
'trigger_obj_id': fields.many2one('ir.model.fields','Trigger On'),
'email': fields.many2one('ir.model.fields', 'Contact'),
'message': fields.text('Message', translate=True),
'address': fields.many2one('ir.model.fields', 'Email / Mobile'),
'mobile': fields.many2one('ir.model.fields', 'Contact'),
'sms': fields.char('SMS', size=160, translate=True),
'child_ids': fields.one2many('ir.actions.actions', 'parent_id', 'Others Actions'),
'child_ids': fields.many2many('ir.actions.server', 'rel_server_actions', 'server_id', 'action_id', 'Others Actions'),
'usage': fields.char('Action Usage', size=32),
'type': fields.char('Report Type', size=32, required=True),
'srcmodel_id': fields.many2one('ir.model', 'Model'),
'type': fields.char('Action Type', size=32, required=True),
'srcmodel_id': fields.many2one('ir.model', 'Model', help="In which object you want to create / write the object if its empty refer to the Object field"),
'fields_lines': fields.one2many('ir.server.object.lines', 'server_id', 'Fields Mapping'),
'otype': fields.selection([
('copy','Create in Same Model'),
('new','Create in Other Model')
], 'Create Model', size=32, change_default=True),
'record_id':fields.many2one('ir.model.fields', 'Record Id', help="privide the field name from where the record id refers, if its empty it will refer to the active id of the object")
}
_defaults = {
'state': lambda *a: 'dummy',
@ -414,26 +428,49 @@ class actions_server(osv.osv):
# - ids
# If you plan to return an action, assign: action = {...}
""",
'otype': lambda *a: 'copy',
}
def get_field_value(self, cr, uid, action, context):
def get_email(self, cr, uid, action, context):
logger = netsvc.Logger()
obj_pool = self.pool.get(action.model_id.model)
id = context.get('active_id')
obj = obj_pool.browse(cr, uid, id)
fields = None
if '/' in action.address.complete_name:
fields = action.address.complete_name.split('/')
elif '.' in action.address.complete_name:
fields = action.address.complete_name.split('.')
if '/' in action.email.complete_name:
fields = action.email.complete_name.split('/')
elif '.' in action.email.complete_name:
fields = action.email.complete_name.split('.')
for field in fields:
try:
obj = getattr(obj, field)
except Exception,e :
logger.notifyChannel('Workflow', netsvc.LOG_ERROR, 'Failed to parse : %s' % (match.group()))
logger.notifyChannel('Workflow', netsvc.LOG_ERROR, 'Failed to parse : %s' % (field))
return obj
def get_mobile(self, cr, uid, action, context):
logger = netsvc.Logger()
obj_pool = self.pool.get(action.model_id.model)
id = context.get('active_id')
obj = obj_pool.browse(cr, uid, id)
fields = None
if '/' in action.mobile.complete_name:
fields = action.mobile.complete_name.split('/')
elif '.' in action.mobile.complete_name:
fields = action.mobile.complete_name.split('.')
for field in fields:
try:
obj = getattr(obj, field)
except Exception,e :
logger.notifyChannel('Workflow', netsvc.LOG_ERROR, 'Failed to parse : %s' % (field))
return obj
@ -443,13 +480,17 @@ class actions_server(osv.osv):
obj_pool = self.pool.get(action.model_id.model)
id = context.get('active_id')
obj = obj_pool.browse(cr, uid, id)
return eval(match[2:-2], {'object':obj, 'context': context,'time':time})
exp = str(match.group()[2:-2]).strip()
result = eval(exp, {'object':obj, 'context': context,'time':time})
if result in (None, False):
return str("--------")
return str(result)
com = re.compile('(\[\[.+?\]\])')
message = com.sub(merge, keystr)
return message
#
# Context should contains:
# ids : original ids
# id : current id of the object
@ -459,10 +500,12 @@ class actions_server(osv.osv):
def run(self, cr, uid, ids, context={}):
logger = netsvc.Logger()
for action in self.browse(cr, uid, ids, context):
if action.state=='client_action':
if not action.action_id:
raise osv.except_osv(_('Error'), _("Please specify an action to launch !"))
return self.pool.get(action.action_id.type).read(cr, uid, action.action_id.id, context=context)
if action.state=='python':
localdict = {
'self': self.pool.get(action.model_id.model),
@ -479,20 +522,24 @@ class actions_server(osv.osv):
if action.state == 'email':
user = config['email_from']
subject = action.name
address = self.get_field_value(cr, uid, action, context)
address = self.get_email(cr, uid, action, context)
if not address:
raise osv.except_osv(_('Error'), _("Please specify the Partner Email address !"))
if not user:
raise osv.except_osv(_('Error'), _("Please specify server option --smtp-from !"))
body = self.merge_message(cr, uid, str(action.message), action, context)
if tools.email_send_attach(user, address, subject, body, debug=False) == True:
if tools.email_send(user, [address], subject, body, debug=False, subtype='html') == True:
logger.notifyChannel('email', netsvc.LOG_INFO, 'Email successfully send to : %s' % (address))
else:
logger.notifyChannel('email', netsvc.LOG_ERROR, 'Failed to send email to : %s' % (address))
if action.state == 'trigger':
wf_service = netsvc.LocalService("workflow")
res = str(action.trigger_obj_id).split(',')
model = res[0]
id = res[1]
model = action.wkf_model_id.model
obj_pool = self.pool.get(action.model_id.model)
res_id = self.pool.get(action.model_id.model).read(cr, uid, [context.get('active_id')], [action.trigger_obj_id.name])
id = res_id [0][action.trigger_obj_id.name]
wf_service.trg_validate(uid, model, int(id), action.trigger_name, cr)
if action.state == 'sms':
@ -500,27 +547,20 @@ class actions_server(osv.osv):
# for the sms gateway user / password
api_id = ''
text = action.sms
to = self.get_field_value(cr, uid, action, context)
to = self.get_mobile(cr, uid, action, context)
#TODO: Apply message mearge with the field
if tools.sms_send(user, password, api_id, text, to) == True:
logger.notifyChannel('sms', netsvc.LOG_INFO, 'SMS successfully send to : %s' % (action.address))
else:
logger.notifyChannel('sms', netsvc.LOG_ERROR, 'Failed to send SMS to : %s' % (action.address))
if action.state == 'other':
localdict = {
'self': self.pool.get(action.model_id.model),
'context': context,
'time': time,
'ids': ids,
'cr': cr,
'uid': uid
}
res = None
for act in action.child_ids:
code = """action = {'model':'%s','type':'%s', %s}""" % (action.model_id.model, act.type, act.usage)
exec code in localdict
if 'action' in localdict:
return localdict['action']
result = self.run(cr, uid, [act.id], context)
if result:
res = result
return res
if action.state == 'object_write':
res = {}
@ -533,9 +573,19 @@ class actions_server(osv.osv):
else:
expr = exp.value
res[exp.col1.name] = expr
obj_pool = self.pool.get(action.model_id.model)
obj_pool.write(cr, uid, [context.get('active_id')], res)
if not action.record_id:
if not action.srcmodel_id:
obj_pool = self.pool.get(action.model_id.model)
obj_pool.write(cr, uid, [context.get('active_id')], res)
else:
obj_pool = self.pool.get(action.srcmodel_id.model)
obj_pool.write(cr, uid, [context.get('active_id')], res)
else:
obj_pool = self.pool.get(action.srcmodel_id.model)
id = self.pool.get(action.model_id.model).read(cr, uid, [context.get('active_id')], [action.record_id.name])
obj_pool.write(cr, uid, [int(id[0][action.record_id.name])], res)
if action.state == 'object_create':
res = {}
for exp in action.fields_lines:
@ -549,13 +599,10 @@ class actions_server(osv.osv):
res[exp.col1.name] = expr
obj_pool = None
if action.state == 'object_create' and action.otype == 'new':
obj_pool = self.pool.get(action.srcmodel_id.model)
obj_pool.create(cr, uid, res)
else:
obj_pool = self.pool.get(action.model_id.model)
id = context.get('active_id')
obj_pool.copy(cr, uid, id, res)
res_id = False
obj_pool = self.pool.get(action.srcmodel_id.model)
res_id = obj_pool.create(cr, uid, res)
self.pool.get(action.model_id.model).write(cr, uid, [context.get('active_id')], {action.record_id.name:res_id})
return False
actions_server()

View File

@ -25,20 +25,16 @@ from osv.orm import except_orm
import tools
class ir_attachment(osv.osv):
def check(self, cr, uid, ids, mode):
if not ids:
return
ima = self.pool.get('ir.model.access')
if isinstance(ids, (int, long)):
ids = [ids]
objs = self.browse(cr, uid, ids) or []
for o in objs:
if o and o.res_model:
ima.check(cr, uid, o.res_model, mode)
check = tools.cache()(check)
cr.execute('select distinct res_model from ir_attachment where id in ('+','.join(map(str, ids))+')')
for obj in cr.fetchall():
ima.check(cr, uid, obj[0], mode)
def search(self, cr, uid, args, offset=0, limit=None, order=None,
context=None, count=False):
ids = super(ir_attachment, self).search(cr, uid, args, offset=offset,
@ -83,24 +79,12 @@ class ir_attachment(osv.osv):
self.pool.get('ir.model.access').check(cr, uid, values['res_model'], 'create')
return super(ir_attachment, self).create(cr, uid, values, *args, **kwargs)
def clear_cache(self):
self.check()
def action_get(self, cr, uid, context=None):
dataobj = self.pool.get('ir.model.data')
data_id = dataobj._get_id(cr, 1, 'base', 'action_attachment')
res_id = dataobj.browse(cr, uid, data_id, context).res_id
return self.pool.get('ir.actions.act_window').read(cr, uid, res_id, [], context)
def __init__(self, *args, **kwargs):
r = super(ir_attachment, self).__init__(*args, **kwargs)
self.pool.get('ir.model.access').register_cache_clearing_method(self._name, 'clear_cache')
return r
def __del__(self):
self.pool.get('ir.model.access').unregister_cache_clearing_method(self._name, 'clear_cache')
return super(ir_attachment, self).__del__()
def _get_preview(self, cr, uid, ids, name, arg, context=None):
result = {}
if context is None:

View File

@ -101,7 +101,7 @@ class ir_cron(osv.osv, netsvc.Agent):
addsql=''
if not numbercall:
addsql = ', active=False'
cr.execute("update ir_cron set nextcall=%s, numbercall=%d"+addsql+" where id=%d", (nextcall.strftime('%Y-%m-%d %H:%M:%S'), numbercall, job['id']))
cr.execute("update ir_cron set nextcall=%s, numbercall=%s"+addsql+" where id=%s", (nextcall.strftime('%Y-%m-%d %H:%M:%S'), numbercall, job['id']))
cr.commit()
finally:
cr.close()

View File

@ -193,7 +193,9 @@ class ir_model_fields(osv.osv):
_columns = {
'name': fields.char('Name', required=True, size=64, select=1),
'model': fields.char('Object Name', size=64, required=True),
'relation_id':fields.many2one('ir.model', 'Object Relation'),
'relation': fields.char('Object Relation', size=64),
'relation_field_id':fields.many2one('ir.model.fields', 'Relation Field'),
'relation_field': fields.char('Relation Field', size=64),
'model_id': fields.many2one('ir.model', 'Object id', required=True, select=True, ondelete='cascade'),
'field_description': fields.char('Field Label', required=True, size=256),
@ -231,8 +233,26 @@ class ir_model_fields(osv.osv):
# MAY BE ADD A ALTER TABLE DROP ?
#
return super(ir_model_fields, self).unlink(cr, user, ids, context)
def write(self, cr, uid, ids, vals, context=None):
res = False
if 'relation_id' in vals:
model_data = self.pool.get('ir.model').browse(cr, uid, vals['relation_id'])
vals['relation'] = model_data.model
if 'relation_field_id' in vals:
field_data = self.pool.get('ir.model.fields').browse(cr, uid, vals['relation_field_id'])
vals['relation'] = field_data.name
res = super(ir_model_fields, self).write(cr, uid, ids, vals, context)
return res
def create(self, cr, user, vals, context=None):
if 'relation_id' in vals:
model_data = self.pool.get('ir.model').browse(cr,user,vals['relation_id'])
vals['relation']=model_data.model
if 'relation_field_id' in vals:
field_data = self.pool.get('ir.model.fields').browse(cr, uid, vals['relation_field_id'])
vals['relation_field'] = field_data.name
if 'model_id' in vals:
model_data=self.pool.get('ir.model').browse(cr,user,vals['model_id'])
vals['model']=model_data.model
@ -266,7 +286,7 @@ class ir_model_access(osv.osv):
if not grouparr:
return False
cr.execute("select 1 from res_groups_users_rel where uid=%d and gid in(select res_id from ir_model_data where module=%s and name=%s)", (uid, grouparr[0], grouparr[1],))
cr.execute("select 1 from res_groups_users_rel where uid=%s and gid in(select res_id from ir_model_data where module=%s and name=%s)", (uid, grouparr[0], grouparr[1],))
return bool(cr.fetchone())
def check_group(self, cr, uid, model, mode, group_ids):
@ -285,7 +305,7 @@ class ir_model_access(osv.osv):
cr.execute("SELECT perm_" + mode + " "
" FROM ir_model_access a "
" JOIN ir_model m ON (m.id = a.model_id) "
" WHERE m.model = %s AND a.group_id = %d", (model_name, group_id)
" WHERE m.model = %s AND a.group_id = %s", (model_name, group_id)
)
r = cr.fetchone()
if r is None:
@ -415,7 +435,7 @@ class ir_model_data(osv.osv):
ids = self.search(cr, uid, [('module','=',module),('name','=', xml_id)])
assert len(ids)==1, '%d reference(s) to %s.%s. You should have one and only one !' % (len(ids), module, xml_id)
return ids[0]
_get_id = tools.cache()(_get_id)
_get_id = tools.cache(skiparg=2)(_get_id)
def _update_dummy(self,cr, uid, model, module, xml_id=False, store=True):
if not xml_id:
@ -442,10 +462,10 @@ class ir_model_data(osv.osv):
cr.execute('select id,res_id from ir_model_data where module=%s and name=%s', (module,xml_id))
results = cr.fetchall()
for action_id2,res_id2 in results:
cr.execute('select id from '+self.pool.get(model)._table+' where id=%d', (res_id2,))
cr.execute('select id from '+self.pool.get(model)._table+' where id=%s', (res_id2,))
result3 = cr.fetchone()
if not result3:
cr.execute('delete from ir_model_data where id=%d', (action_id2,))
cr.execute('delete from ir_model_data where id=%s', (action_id2,))
else:
res_id,action_id = res_id2,action_id2
@ -513,7 +533,7 @@ class ir_model_data(osv.osv):
#self.pool.get(model).unlink(cr, uid, ids)
for id in ids:
self.unlink_mark[(model, id)]=False
cr.execute('delete from ir_model_data where res_id=%d and model=\'%s\'', (id,model))
cr.execute('delete from ir_model_data where res_id=%s and model=\'%s\'', (id,model))
return True
def ir_set(self, cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=None, xml_id=False):
@ -525,7 +545,7 @@ class ir_model_data(osv.osv):
model = models[0]
if res_id:
where = ' and res_id=%d' % (res_id,)
where = ' and res_id=%s' % (res_id,)
else:
where = ' and (res_id is null)'
@ -552,10 +572,10 @@ class ir_model_data(osv.osv):
if (module,name) not in self.loads:
self.unlink_mark[(model,res_id)] = id
if model=='workflow.activity':
cr.execute('select res_type,res_id from wkf_instance where id in (select inst_id from wkf_workitem where act_id=%d)', (res_id,))
cr.execute('select res_type,res_id from wkf_instance where id in (select inst_id from wkf_workitem where act_id=%s)', (res_id,))
wkf_todo.extend(cr.fetchall())
cr.execute("update wkf_transition set condition='True', role_id=NULL, signal=NULL,act_to=act_from,act_from=%d where act_to=%d", (res_id,res_id))
cr.execute("delete from wkf_transition where act_to=%d", (res_id,))
cr.execute("update wkf_transition set condition='True', role_id=NULL, signal=NULL,act_to=act_from,act_from=%s where act_to=%s", (res_id,res_id))
cr.execute("delete from wkf_transition where act_to=%s", (res_id,))
for model,id in wkf_todo:
wf_service = netsvc.LocalService("workflow")

View File

@ -25,6 +25,7 @@ from osv.orm import browse_null
import ir
import report.custom
from tools.translate import _
import netsvc
class report_custom(osv.osv):
_name = 'ir.report.custom'
@ -187,7 +188,7 @@ class report_custom_fields(osv.osv):
}
}
else:
print _("Warning: using a relation field which uses an unknown object") #TODO use the logger
netsvc.Logger().notifyChannel('web-services', netsvc.LOG_WARNING, _("Using a relation field which uses an unknown object"))
return {'required': {next_level_field_name: True}}
else:
return {'domain': {next_level_field_name: []}}

View File

@ -148,7 +148,7 @@ class ir_rule(osv.osv):
WHERE m.model = %s
AND (g.id IN (SELECT rule_group_id FROM group_rule_group_rel g_rel
JOIN res_groups_users_rel u_rel ON (g_rel.group_id = u_rel.gid)
WHERE u_rel.uid = %d) OR g.global)""", (model_name, uid))
WHERE u_rel.uid = %s) OR g.global)""", (model_name, uid))
ids = map(lambda x:x[0], cr.fetchall())
if not ids:
return '', []

View File

@ -69,11 +69,11 @@ class ir_sequence(osv.osv):
'sec': time.strftime('%S'),
}
def get_id(self, cr, uid, sequence_id, test='id=%d'):
def get_id(self, cr, uid, sequence_id, test='id=%s'):
cr.execute('select id,number_next,number_increment,prefix,suffix,padding from ir_sequence where '+test+' and active=True FOR UPDATE', (sequence_id,))
res = cr.dictfetchone()
if res:
cr.execute('update ir_sequence set number_next=number_next+number_increment where id=%d and active=True', (res['id'],))
cr.execute('update ir_sequence set number_next=number_next+number_increment where id=%s and active=True', (res['id'],))
if res['number_next']:
return self._process(res['prefix']) + '%%0%sd' % res['padding'] % res['number_next'] + self._process(res['suffix'])
else:

View File

@ -21,7 +21,6 @@
##############################################################################
from osv import fields, osv
from osv.osv import Cacheable
import tools
TRANSLATION_TYPE = [
@ -39,7 +38,7 @@ TRANSLATION_TYPE = [
('constraint', 'Constraint'),
]
class ir_translation(osv.osv, Cacheable):
class ir_translation(osv.osv):
_name = "ir.translation"
_log_access = False
@ -48,7 +47,7 @@ class ir_translation(osv.osv, Cacheable):
lang_ids = lang_obj.search(cr, uid, [('translatable', '=', True)],
context=context)
langs = lang_obj.browse(cr, uid, lang_ids, context=context)
res = [(lang.code, unicode(lang.name,'utf-8')) for lang in langs]
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)
@ -81,27 +80,19 @@ class ir_translation(osv.osv, Cacheable):
cr.commit()
def _get_ids(self, cr, uid, name, tt, lang, ids):
translations, to_fetch = {}, []
for id in ids:
trans = self.get((lang, name, id))
if trans is not None:
translations[id] = trans
else:
to_fetch.append(id)
if to_fetch:
translations = {}
if ids:
cr.execute('select res_id,value ' \
'from ir_translation ' \
'where lang=%s ' \
'and type=%s ' \
'and name=%s ' \
'and res_id in ('+','.join(map(str, to_fetch))+')',
'and res_id in ('+','.join(map(str, ids))+')',
(lang,tt,name))
for res_id, value in cr.fetchall():
self.add((lang, tt, name, res_id), value)
translations[res_id] = value
for res_id in ids:
if res_id not in translations:
self.add((lang, tt, name, res_id), False)
translations[res_id] = False
return translations
@ -122,11 +113,8 @@ class ir_translation(osv.osv, Cacheable):
})
return len(ids)
@tools.cache(skiparg=3)
def _get_source(self, cr, uid, name, tt, lang, source=None):
trans = self.get((lang, tt, name, source))
if trans is not None:
return trans
if source:
#if isinstance(source, unicode):
# source = source.encode('utf8')
@ -145,26 +133,9 @@ class ir_translation(osv.osv, Cacheable):
'and name=%s',
(lang, tt, str(name)))
res = cr.fetchone()
trad = res and res[0] or ''
self.add((lang, tt, name, source), trad)
return trad
def unlink(self, cursor, user, ids, context=None):
self.clear()
return super(ir_translation, self).unlink(cursor, user, ids,
context=context)
def create(self, cursor, user, vals, context=None):
self.clear()
return super(ir_translation, self).create(cursor, user, vals,
context=context)
def write(self, cursor, user, ids, vals, context=None):
self.clear()
return super(ir_translation, self).write(cursor, user, ids, vals,
context=context)
ir_translation()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -41,7 +41,7 @@ class many2many_unique(fields.many2many):
for act in values:
if act[0]==4:
cr.execute('SELECT * FROM '+self._rel+' \
WHERE '+self._id1+'=%d AND '+self._id2+'=%d', (id, act[1]))
WHERE '+self._id1+'=%s AND '+self._id2+'=%s', (id, act[1]))
if cr.fetchall():
val.remove(act)
return super(many2many_unique, self).set(cr, obj, id, name, val, user=user,

View File

@ -27,14 +27,13 @@ import netsvc
import os
def _check_xml(self, cr, uid, ids, context={}):
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.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, 'The view does not fit the required schema !')
logger.notifyChannel('init', netsvc.LOG_ERROR, relaxng.error_log.last_error)
return False
return True
@ -99,7 +98,7 @@ class view(osv.osv):
for rs in result:
if rs.get('model') == 'board.board':
cr.execute("select id,arch,ref_id from ir_ui_view_custom where user_id=%d and ref_id=%d", (uid, rs['id']))
cr.execute("select id,arch,ref_id from ir_ui_view_custom where user_id=%s and ref_id=%s", (uid, rs['id']))
oview = cr.dictfetchall()
if oview:
rs['arch'] = oview[0]['arch']

View File

@ -211,7 +211,7 @@ class ir_values(osv.osv):
#ir_del(cr, uid, x[0])
return False
else:
datas = pickle.loads(x[2])
datas = pickle.loads(str(x[2]))
if meta:
meta2 = pickle.loads(x[4])
return (x[0],x[1],datas,meta2)

View File

@ -28,7 +28,7 @@ import report,pooler,tools
def graph_get(cr, graph, wkf_id, nested=False, workitem={}):
import pydot
cr.execute('select * from wkf_activity where wkf_id=%d', (wkf_id,))
cr.execute('select * from wkf_activity where wkf_id=%s', (wkf_id,))
nodes = cr.dictfetchall()
activities = {}
actfrom = {}
@ -36,7 +36,7 @@ def graph_get(cr, graph, wkf_id, nested=False, workitem={}):
for n in nodes:
activities[n['id']] = n
if n['subflow_id'] and nested:
cr.execute('select * from wkf where id=%d', (n['subflow_id'],))
cr.execute('select * from wkf where id=%s', (n['subflow_id'],))
wkfinfo = cr.dictfetchone()
graph2 = pydot.Cluster('subflow'+str(n['subflow_id']), fontsize='12', label = """\"Subflow: %s\\nOSV: %s\"""" % ( n['name'], wkfinfo['osv']) )
(s1,s2) = graph_get(cr, graph2, n['subflow_id'], nested,workitem)
@ -78,9 +78,9 @@ def graph_get(cr, graph, wkf_id, nested=False, workitem={}):
activity_to = actto[t['act_to']][1].get(t['signal'], actto[t['act_to']][0])
graph.add_edge(pydot.Edge( str(activity_from) ,str(activity_to), fontsize='10', **args))
nodes = cr.dictfetchall()
cr.execute('select id from wkf_activity where flow_start=True and wkf_id=%d limit 1', (wkf_id,))
cr.execute('select id from wkf_activity where flow_start=True and wkf_id=%s limit 1', (wkf_id,))
start = cr.fetchone()[0]
cr.execute("select 'subflow.'||name,id from wkf_activity where flow_stop=True and wkf_id=%d", (wkf_id,))
cr.execute("select 'subflow.'||name,id from wkf_activity where flow_stop=True and wkf_id=%s", (wkf_id,))
stop = cr.fetchall()
stop = (stop[0][1], dict(stop))
return ((start,{}),stop)
@ -88,14 +88,14 @@ def graph_get(cr, graph, wkf_id, nested=False, workitem={}):
def graph_instance_get(cr, graph, inst_id, nested=False):
workitems = {}
cr.execute('select * from wkf_instance where id=%d', (inst_id,))
cr.execute('select * from wkf_instance where id=%s', (inst_id,))
inst = cr.dictfetchone()
def workitem_get(instance):
cr.execute('select act_id,count(*) from wkf_workitem where inst_id=%d group by act_id', (instance,))
cr.execute('select act_id,count(*) from wkf_workitem where inst_id=%s group by act_id', (instance,))
workitems = dict(cr.fetchall())
cr.execute('select subflow_id from wkf_workitem where inst_id=%d', (instance,))
cr.execute('select subflow_id from wkf_workitem where inst_id=%s', (instance,))
for (subflow_id,) in cr.fetchall():
workitems.update(workitem_get(subflow_id))
return workitems
@ -130,7 +130,7 @@ class report_graph_instance(object):
showpage'''
else:
cr.execute('SELECT id FROM wkf_instance \
WHERE res_id=%d AND wkf_id=%d \
WHERE res_id=%s AND wkf_id=%s \
ORDER BY state LIMIT 1',
(data['id'], wkfinfo['id']))
inst_id = cr.fetchone()

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<menuitem id="menu_workflow_root" name="Workflows" parent="menu_custom"/>
<menuitem id="menu_workflow_root" name="Workflow Definitions" parent="menu_custom"/>
<!--
================================
@ -110,7 +110,7 @@
</record>
<record id="action_workflow_activity_form" model="ir.actions.act_window">
<field name="name">Activites</field>
<field name="name">Activities</field>
<field name="res_model">workflow.activity</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_workflow_activity_tree"/>
@ -207,7 +207,7 @@
<field name="view_type">form</field>
<field name="view_id" ref="view_workflow_instance_tree"/>
</record>
<menuitem action="action_workflow_instance_form" id="menu_workflow_instance" parent="base.menu_workflow_root"/>
<menuitem action="action_workflow_instance_form" id="menu_workflow_instance" parent="base.menu_low_workflow"/>
<!--
================================
@ -248,7 +248,7 @@
<field name="view_type">form</field>
<field name="view_id" ref="view_workflow_workitem_tree"/>
</record>
<menuitem action="action_workflow_workitem_form" id="menu_workflow_workitem" parent="base.menu_workflow_root"/>
<menuitem action="action_workflow_workitem_form" id="menu_workflow_workitem" parent="base.menu_low_workflow"/>
</data>
</openerp>

View File

@ -32,78 +32,46 @@ from osv import osv, fields
import pooler
import time
import math
from pprint import pprint as pp
from tools import config
import xmlrpclib
class maintenance_contract_module(osv.osv):
_name ="maintenance.contract.module"
_description = "maintenance contract modules"
_columns = {
'name' : fields.char('Name', size=128, required=True),
'version': fields.char('Version', size=64,),
}
maintenance_contract_module()
class maintenance_contract(osv.osv):
_name = "maintenance.contract"
_description = "Maintenance Contract"
def _valid_get(self, cr, uid, ids, field_name, arg, context=None):
res = {}
for contract in self.browse(cr, uid, ids, context=context):
res[contract.id] = ("unvalid", "valid")[contract.date_stop >= time.strftime('%Y-%m-%d')]
return res
_columns = {
'name' : fields.char('Contract ID', size=256, required=True, readonly=True),
'password' : fields.char('Password', size=64, invisible=True, required=True, readonly=True),
'date_start' : fields.date('Starting Date', readonly=True),
'date_stop' : fields.date('Ending Date', readonly=True),
'modules': fields.text('Covered Modules')
'module_ids' : fields.many2many('maintenance.contract.module', 'maintenance_contract_module_rel', 'contract_id', 'module_id', 'Covered Modules', readonly=True),
'state' : fields.function(_valid_get, method=True, string="State", type="selection", selection=[('valid', 'Valid'),('unvalid', 'Unvalid')], readonly=True),
'kind' : fields.selection([('full', 'Full'),('partial', 'Partial')], 'Kind', required=True, readonly=True),
}
_defaults = {
'password' : lambda obj,cr,uid,context={} : '',
}
def _test_maintenance(self, cr, uid, ids, context):
remote_db='trunk'
remote_server='localhost'
port=8069
module_obj=self.pool.get('ir.module.module')
contract_obj=self.pool.get('maintenance.contract')
module_ids=module_obj.search(cr, uid, [('state','=','installed')])
modules=module_obj.read(cr, uid, module_ids, ['name','installed_version'])
contract_obj=contract_obj.read(cr, uid, ids[0])
local_url = 'http://%s:%d/xmlrpc/common'%(remote_server,port)
rpc = xmlrpclib.ServerProxy(local_url)
ruid = rpc.login(remote_db, 'admin', 'admin')
local_url = 'http://%s:%d/xmlrpc/object'%(remote_server,port)
rrpc = xmlrpclib.ServerProxy(local_url)
try:
result=rrpc.execute(remote_db, ruid, 'admin', 'maintenance.maintenance', 'check_contract' , modules,contract_obj)
except:
raise osv.except_osv(_('Maintenance Error !'),('''Module Maintenance_Editor is not installed at server : %s Database : %s'''%(remote_server,remote_db)))
if context.get('active_id',False):
if result['status']=='ko':
raise osv.except_osv(_('Maintenance Error !'),('''Maintenance Contract
-----------------------------------------------------------
You have no valid maintenance contract! If you are using
Open ERP, it is highly suggested to take maintenance contract.
The maintenance program offers you:
* Migrations on new versions,
* Bugfix guarantee,
* Monthly announces of bugs,
* Security alerts,
* Access to the customer portal.
* Check the maintenance contract (www.openerp.com)'''))
elif result['status']=='partial':
raise osv.except_osv(_('Maintenance Error !'),('''Maintenance Contract
-----------------------------------------------------------
You have a maintenance contract, But you installed modules those
are not covered by your maintenance contract:
%s
It means we can not offer you the garantee of maintenance on
your whole installation.
The maintenance program includes:
* Migrations on new versions,
* Bugfix guarantee,
* Monthly announces of bugs,
* Security alerts,
* Access to the customer portal.
To include these modules in your maintenance contract, you should
extend your contract with the editor. We will review and validate
your installed modules.
* Extend your maintenance to the modules you used.
* Check your maintenance contract''') % ','.join(result['modules']))
else:
raise osv.except_osv(_('Valid Maintenance Contract !'),('''Your Maintenance Contract is up to date'''))
return result
_sql_constraints = [
('uniq_name', 'unique(name)', "Your maintenance contract is already subscribed in the system !")
]
maintenance_contract()
@ -114,11 +82,55 @@ class maintenance_contract_wizard(osv.osv_memory):
_columns = {
'name' : fields.char('Contract ID', size=256, required=True ),
'password' : fields.char('Password', size=64, required=True),
'state' : fields.selection([('draft', 'Draft'),('validated', 'Validated'),('unvalidated', 'Unvalidated')], 'States'),
}
def validate_cb(self, cr, uid, ids, context):
print "Validate_cb"
return False
_defaults = {
'state' : lambda *a: 'draft',
}
def action_validate(self, cr, uid, ids, context):
if not ids:
return False
module_proxy = self.pool.get('ir.module.module')
module_ids = module_proxy.search(cr, uid, [('state', '=', 'installed')])
modules = module_proxy.read(cr, uid, module_ids, ['name', 'installed_version'])
contract = self.read(cr, uid, ids, ['name', 'password'])[0]
login, password, remote_db, remote_server, port = 'admin', 'admin', 'trunk', 'localhost', 8069
rpc = xmlrpclib.ServerProxy('http://%s:%d/xmlrpc/common' % (remote_server, port))
ruid = rpc.login(remote_db, login, password)
rpc = xmlrpclib.ServerProxy('http://%s:%d/xmlrpc/object' % (remote_server, port))
contract_info = rpc.execute(remote_db, ruid, password, 'maintenance.maintenance', 'check_contract', modules, contract )
is_ok = contract_info['status'] in ('partial', 'full')
if is_ok:
if contract_info['modules_with_contract']:
module_ids = []
for name, version in contract_info['modules_with_contract']:
contract_module = self.pool.get('maintenance.contract.module')
res = contract_module.search(cr, uid, [('name', '=', name),('version', '=', version)])
if not res:
id = contract_module.create(cr, uid, { 'name' : name, 'version' : version } )
else:
id = res[0]
module_ids.append(id)
self.pool.get('maintenance.contract').create(
cr,
uid, {
'name' : contract['name'],
'password' : contract['password'],
'date_start' : contract_info['date_from'],
'date_stop' : contract_info['date_to'],
'kind' : contract_info['status'],
'module_ids' : [(6,0,module_ids)],
}
)
return self.write(cr, uid, ids, {'state' : ('unvalidated', 'validated')[is_ok] }, context=context)
maintenance_contract_wizard()

View File

@ -11,6 +11,7 @@
<field name="name"/>
<field name="date_start"/>
<field name="date_stop"/>
<field name="state" />
</tree>
</field>
</record>
@ -22,11 +23,17 @@
<field name="arch" type="xml">
<form string="Maintenance Contract">
<separator string="Information" colspan="4"/>
<field name="name" select="1" colspan="4"/>
<field name="name" select="1" />
<field name="state" />
<field name="date_start" select="1"/>
<field name="date_stop" select="1"/>
<separator string="Covered Modules" colspan="4"/>
<field name="modules" nolabel="1" colspan="4"/>
<field name="module_ids" nolabel="1" colspan="4">
<tree string="Covered Modules">
<field name="name" />
<field name="version" />
</tree>
</field>
</form>
</field>
</record>
@ -54,14 +61,28 @@
<field name="model">maintenance.contract.wizard</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Add Maintenance Contract">
<separator string="Add Maintenance Contract" colspan="2"/>
<newline />
<field name="name" />
<newline />
<field name="password" password="True" />
<newline />
<label string="" /><button name="validate_cb" type="object" string="Validate" />
<form string="Add Maintenance Contract" col="2">
<image name="gtk-dialog-info" />
<group col="1">
<separator string="Add Maintenance Contract" />
<group states="draft">
<field name="name" width="250" />
<newline />
<field name="password" password="True" />
<field name="state" invisible="1" />
</group>
<group states="validated">
<label string="Maintenance contract added !"/>
</group>
<group states="unvalidated">
<label string="Could you check your contract information ?" />
</group>
</group>
<group colspan="4">
<button type="object" string="_Cancel" icon="gtk-cancel" special="cancel" states="draft"/>
<button type="object" string="_Validate" icon="gtk-apply" name="action_validate" states="draft"/>
<button type="object" string="_Close" icon="gtk-close" special="cancel" states="validated,unvalidated"/>
</group>
</form>
</field>
</record>

View File

@ -68,7 +68,7 @@ class module_category(osv.osv):
cr.execute('select category_id,count(*) from ir_module_module where category_id in ('+','.join(map(str,ids))+') or category_id in (select id from ir_module_category where parent_id in ('+','.join(map(str,ids))+')) group by category_id')
result = dict(cr.fetchall())
for id in ids:
cr.execute('select id from ir_module_category where parent_id=%d', (id,))
cr.execute('select id from ir_module_category where parent_id=%s', (id,))
childs = [c for c, in cr.fetchall()]
result[id] = reduce(lambda x,y:x+y, [result.get(c, 0) for c in childs], result.get(id, 0))
return result
@ -98,58 +98,43 @@ class module(osv.osv):
return {}
return info
def _get_installed_version(self, cr, uid, ids, field_name=None, arg=None, context={}):
res = {}
def _get_latest_version(self, cr, uid, ids, field_name=None, arg=None, context={}):
res = dict.fromkeys(ids, '')
for m in self.browse(cr, uid, ids):
if m.state in ('installed', 'to upgrade', 'to remove'):
res[m.id] = self.get_module_info(m.name).get('version', '')
else:
res[m.id] = ''
return res
def _get_menus(self, cr, uid, ids, field_name=None, arg=None, context={}):
res = {}
model_data_obj = self.pool.get('ir.model.data')
menu_obj = self.pool.get('ir.ui.menu')
for m in self.browse(cr, uid, ids):
if m.state == 'installed':
menu_txt = ''
menus_id = model_data_obj.search(cr,uid,[('module','=',m.name),('model','=','ir.ui.menu')])
for data_id in model_data_obj.browse(cr,uid,menus_id):
menu_txt += menu_obj.browse(cr,uid,data_id.res_id).complete_name + '\n'
res[m.id] = menu_txt
else:
res[m.id] = ''
return res
def _get_reports(self, cr, uid, ids, field_name=None, arg=None, context={}):
res = {}
model_data_obj = self.pool.get('ir.model.data')
report_obj = self.pool.get('ir.actions.report.xml')
for m in self.browse(cr, uid, ids):
if m.state == 'installed':
report_txt = ''
report_id = model_data_obj.search(cr,uid,[('module','=',m.name),('model','=','ir.actions.report.xml')])
for data_id in model_data_obj.browse(cr,uid,report_id):
report_txt += report_obj.browse(cr,uid,data_id.res_id).name + '\n'
res[m.id] = report_txt
else:
res[m.id] = ''
res[m.id] = self.get_module_info(m.name).get('version', '')
return res
def _get_views(self, cr, uid, ids, field_name=None, arg=None, context={}):
res = {}
model_data_obj = self.pool.get('ir.model.data')
view_obj = self.pool.get('ir.ui.view')
for m in self.browse(cr, uid, ids, context=context):
if m.state == 'installed':
view_txt = ''
view_id = model_data_obj.search(cr,uid,[('module','=',m.name),('model','=','ir.ui.view')])
for data_id in model_data_obj.browse(cr,uid,view_id):
view_txt += view_obj.browse(cr,uid,data_id.res_id).name + '\n'
res[m.id] = view_txt
else:
res[m.id] = ''
report_obj = self.pool.get('ir.actions.report.xml')
menu_obj = self.pool.get('ir.ui.menu')
mlist = self.browse(cr, uid, ids, context=context)
mnames = {}
for m in mlist:
mnames[m.name] = m.id
res[m.id] = {
'menus_by_module':'',
'reports_by_module':'',
'views_by_module': ''
}
view_id = model_data_obj.search(cr,uid,[('module','in', mnames.keys()),
('model','in',('ir.ui.view','ir.actions.report.xml','ir.ui.menu'))])
for data_id in model_data_obj.browse(cr,uid,view_id,context):
# We use try except, because views or menus may not exist
try:
key = data_id['model']
if key=='ir.ui.view':
v = view_obj.browse(cr,uid,data_id.res_id)
aa = v.inherit_id and '* INHERIT ' or ''
res[mnames[data_id.module]]['views_by_module'] += aa + v.name + ' ('+v.type+')\n'
elif key=='ir.actions.report.xml':
res[mnames[data_id.module]]['reports_by_module'] += report_obj.browse(cr,uid,data_id.res_id).name + '\n'
elif key=='ir.ui.menu':
res[mnames[data_id.module]]['menus_by_module'] += menu_obj.browse(cr,uid,data_id.res_id).complete_name + '\n'
except KeyError, e:
pass
return res
_columns = {
@ -159,10 +144,16 @@ class module(osv.osv):
'description': fields.text("Description", readonly=True, translate=True),
'author': fields.char("Author", size=128, readonly=True),
'website': fields.char("Website", size=256, readonly=True),
'installed_version': fields.function(_get_installed_version, method=True,
string='Installed version', type='char'),
'latest_version': fields.char('Latest version', size=64, readonly=True),
# attention: Incorrect field names !!
# installed_version refer the latest version (the one on disk)
# latest_version refer the installed version (the one in database)
# published_version refer the version available on the repository
'installed_version': fields.function(_get_latest_version, method=True,
string='Latest version', type='char'),
'latest_version': fields.char('Installed version', size=64, readonly=True),
'published_version': fields.char('Published Version', size=64, readonly=True),
'url': fields.char('URL', size=128),
'dependencies_id': fields.one2many('ir.module.module.dependency',
'module_id', 'Dependencies', readonly=True),
@ -182,9 +173,9 @@ class module(osv.osv):
('GPL-3 or any later version', 'GPL-3 or later version'),
('Other proprietary', 'Other proprietary')
], string='License', readonly=True),
'menus_by_module': fields.function(_get_menus, method=True, string='Menus', type='text'),
'reports_by_module': fields.function(_get_reports, method=True, string='Reports', type='text'),
'views_by_module': fields.function(_get_views, method=True, string='Views', type='text'),
'menus_by_module': fields.function(_get_views, method=True, string='Menus', type='text', multi="meta", store=True),
'reports_by_module': fields.function(_get_views, method=True, string='Reports', type='text', multi="meta", store=True),
'views_by_module': fields.function(_get_views, method=True, string='Views', type='text', multi="meta", store=True),
}
_defaults = {
@ -270,9 +261,22 @@ class module(osv.osv):
_("Can not upgrade module '%s'. It is not installed.") % (mod.name,))
iids = depobj.search(cr, uid, [('name', '=', mod.name)], context=context)
for dep in depobj.browse(cr, uid, iids, context=context):
if dep.module_id.state=='installed':
if dep.module_id.state=='installed' and dep.module_id not in todo:
todo.append(dep.module_id)
self.write(cr,uid, map(lambda x: x.id, todo), {'state':'to upgrade'}, context=context)
ids = map(lambda x: x.id, todo)
self.write(cr, uid, ids, {'state':'to upgrade'}, context=context)
to_install = []
for mod in todo:
for dep in mod.dependencies_id:
if dep.state == 'unknown':
raise orm.except_orm(_('Error'), _('You try to upgrade a module that depends on the module: %s.\nBut this module is not available in your system.') % (dep.name,))
if dep.state == 'uninstalled':
ids2 = self.search(cr, uid, [('name','=',dep.name)])
to_install.extend(ids2)
self.button_install(cr, uid, to_install, context=context)
return True
def button_upgrade_cancel(self, cr, uid, ids, context={}):
@ -301,7 +305,6 @@ class module(osv.osv):
self.write(cr, uid, id, {'state': 'uninstalled'})
if parse_version(terp.get('version', '')) > parse_version(mod.latest_version or ''):
self.write(cr, uid, id, {
'latest_version': terp.get('version'),
'url': ''})
res[0] += 1
self.write(cr, uid, id, {
@ -312,7 +315,7 @@ class module(osv.osv):
'license': terp.get('license', 'GPL-2'),
})
cr.execute('DELETE FROM ir_module_module_dependency\
WHERE module_id = %d', (id,))
WHERE module_id = %s', (id,))
self._update_dependencies(cr, uid, ids[0], terp.get('depends',
[]))
self._update_category(cr, uid, ids[0], terp.get('category',
@ -340,7 +343,6 @@ class module(osv.osv):
'shortdesc': terp.get('name', ''),
'author': terp.get('author', 'Unknown'),
'website': terp.get('website', ''),
'latest_version': terp.get('version', ''),
'license': terp.get('license', 'GPL-2'),
})
res[1] += 1
@ -377,7 +379,6 @@ class module(osv.osv):
if not ids:
self.create(cr, uid, {
'name': name,
'latest_version': version,
'published_version': version,
'url': url,
'state': 'uninstalled',
@ -385,16 +386,15 @@ class module(osv.osv):
res[1] += 1
else:
id = ids[0]
latest_version = self.read(cr, uid, id, ['latest_version'])\
['latest_version']
if latest_version == 'x': # 'x' version was a mistake
latest_version = '0'
if parse_version(version) > parse_version(latest_version):
self.write(cr, uid, id,
{'latest_version': version, 'url': url})
installed_version = self.read(cr, uid, id, ['latest_version'])['latest_version']
if installed_version == 'x': # 'x' version was a mistake
installed_version = '0'
if parse_version(version) > parse_version(installed_version):
self.write(cr, uid, id, {
'url': url
})
res[0] += 1
published_version = self.read(cr, uid, id, ['published_version'])\
['published_version']
published_version = self.read(cr, uid, id, ['published_version'])['published_version']
if published_version == 'x' or not published_version:
published_version = '0'
if parse_version(version) > parse_version(published_version):
@ -433,7 +433,7 @@ class module(osv.osv):
'license': terp.get('license', 'GPL-2'),
})
cr.execute('DELETE FROM ir_module_module_dependency ' \
'WHERE module_id = %d', (mod.id,))
'WHERE module_id = %s', (mod.id,))
self._update_dependencies(cr, uid, mod.id, terp.get('depends',
[]))
self._update_category(cr, uid, mod.id, terp.get('category',
@ -445,21 +445,21 @@ class module(osv.osv):
def _update_dependencies(self, cr, uid, id, depends=[]):
for d in depends:
cr.execute('INSERT INTO ir_module_module_dependency (module_id, name) values (%d, %s)', (id, d))
cr.execute('INSERT INTO ir_module_module_dependency (module_id, name) values (%s, %s)', (id, d))
def _update_category(self, cr, uid, id, category='Uncategorized'):
categs = category.split('/')
p_id = None
while categs:
if p_id is not None:
cr.execute('select id from ir_module_category where name=%s and parent_id=%d', (categs[0], p_id))
cr.execute('select id from ir_module_category where name=%s and parent_id=%s', (categs[0], p_id))
else:
cr.execute('select id from ir_module_category where name=%s and parent_id is NULL', (categs[0],))
c_id = cr.fetchone()
if not c_id:
cr.execute('select nextval(\'ir_module_category_id_seq\')')
c_id = cr.fetchone()[0]
cr.execute('insert into ir_module_category (id, name, parent_id) values (%d, %s, %d)', (c_id, categs[0], p_id))
cr.execute('insert into ir_module_category (id, name, parent_id) values (%s, %s, %s)', (c_id, categs[0], p_id))
else:
c_id = c_id[0]
p_id = c_id

View File

@ -28,30 +28,30 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form col="3" string="Export language">
<notebook>
<page string="Export Data">
<group col="2" fill="0" states="choose">
<separator colspan="2" string="Export translation file"/>
<field name="lang" required="1" width="300"/>
<field name="format" required="1"/>
<field height="200" name="modules" width="500"/>
<field invisible="1" name="state"/>
</group>
<group col="1" fill="0" states="get">
<separator string="Export done"/>
<field name="name" invisible="1"/>
<field name="data" nolabel="1" readonly="1" fieldname="name"/>
<field height="80" name="advice" nolabel="1"/>
</group>
</page>
<page string="Help">
<label align="0.0" colspan="4" string="The official translations pack of all OpenERP/OpenObjects module are managed through launchpad. We use their online interface to synchronize all translations efforts."/>
<label align="0.0" colspan="4" string="To improve some terms of the official translations of OpenERP, you should modify the terms directly on the launchpad interface. If you made lots of translations for your own module, you can also publish all your translation at once."/>
<label align="0.0" colspan="4" string="To browse official translations, you can visit this link: "/>
<label align="0.0" colspan="4" string="https://translations.launchpad.net/openobject"/>
</page>
<notebook>
<page string="Export Data">
<group col="2" fill="0" states="choose">
<separator colspan="2" string="Export translation file"/>
<field name="lang" required="1" width="300"/>
<field name="format" required="1"/>
<field height="200" name="modules" width="500"/>
<field invisible="1" name="state"/>
</group>
<group col="1" fill="0" states="get">
<separator string="Export done"/>
<field name="name" invisible="1"/>
<field name="data" nolabel="1" readonly="1" fieldname="name"/>
<field height="80" name="advice" nolabel="1"/>
</group>
</page>
<page string="Help">
<label align="0.0" colspan="4" string="The official translations pack of all OpenERP/OpenObjects module are managed through launchpad. We use their online interface to synchronize all translations efforts."/>
<label align="0.0" colspan="4" string="To improve some terms of the official translations of OpenERP, you should modify the terms directly on the launchpad interface. If you made lots of translations for your own module, you can also publish all your translation at once."/>
<label align="0.0" colspan="4" string="To browse official translations, you can visit this link: "/>
<label align="0.0" colspan="4" string="https://translations.launchpad.net/openobject"/>
</page>
</notebook>
<group col="2" colspan="3" fill="0">
<button icon="gtk-cancel" name="act_cancel" special="cancel" states="choose" string="Cancel" type="object"/>
<button icon="gtk-ok" name="act_getfile" states="choose" string="Get file" type="object"/>

View File

@ -13,57 +13,62 @@
<blockTableStyle id="Table1">
<blockAlignment value="LEFT"/>
<blockValign value="TOP"/>
<blockBackground colorName="#e6e6e6" start="0,0" stop="0,-1"/>
<blockBackground colorName="#e6e6e6" start="1,0" stop="1,-1"/>
<blockBackground colorName="#e6e6e6" start="2,0" stop="2,-1"/>
<blockBackground colorName="#e6e6e6" start="0,1" stop="0,-1"/>
<blockBackground colorName="#e6e6e6" start="1,1" stop="1,-1"/>
<blockBackground colorName="#e6e6e6" start="2,1" stop="2,-1"/>
</blockTableStyle>
<blockTableStyle id="Tableau1">
<blockTableStyle id="module_tbl_heading">
<blockAlignment value="LEFT"/>
<blockValign value="TOP"/>
<lineStyle kind="LINEBEFORE" colorName="#000000" start="0,0" stop="0,-1"/>
<lineStyle kind="LINEAFTER" colorName="#000000" start="0,0" stop="0,-1"/>
<lineStyle kind="LINEABOVE" colorName="#000000" start="0,0" stop="0,0"/>
<lineStyle kind="LINEBELOW" colorName="#000000" start="0,-1" stop="0,-1"/>
<blockBackground colorName="#ff6633" start="0,0" stop="0,-1"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="0,0" stop="0,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="0,0" stop="0,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,-1" stop="0,-1"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="1,0" stop="1,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="1,0" stop="1,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="1,-1" stop="1,-1"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="2,0" stop="2,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="2,0" stop="2,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="2,-1" stop="2,-1"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="3,0" stop="3,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="3,0" stop="3,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="3,-1" stop="3,-1"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="4,0" stop="4,-1"/>
<lineStyle kind="LINEAFTER" colorName="#e6e6e6" start="4,0" stop="4,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="4,0" stop="4,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="4,-1" stop="4,-1"/>
</blockTableStyle>
<blockTableStyle id="Tableau2">
<blockTableStyle id="module_tbl_content">
<blockAlignment value="LEFT"/>
<blockValign value="TOP"/>
<blockBackground colorName="#e6e6e6" start="0,0" stop="0,-1"/>
<blockBackground colorName="#e6e6e6" start="1,0" stop="1,-1"/>
<blockBackground colorName="#e6e6e6" start="0,1" stop="0,-1"/>
<blockBackground colorName="#e6e6e6" start="1,1" stop="1,-1"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="0,0" stop="0,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="0,0" stop="0,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,-1" stop="0,-1"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="1,0" stop="1,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="1,0" stop="1,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="1,-1" stop="1,-1"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="2,0" stop="2,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="2,0" stop="2,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="2,-1" stop="2,-1"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="3,0" stop="3,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="3,0" stop="3,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="3,-1" stop="3,-1"/>
<lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="4,0" stop="4,-1"/>
<lineStyle kind="LINEAFTER" colorName="#e6e6e6" start="4,0" stop="4,-1"/>
<lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="4,0" stop="4,0"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="4,-1" stop="4,-1"/>
</blockTableStyle>
<blockTableStyle id="Tableau3">
<blockAlignment value="LEFT"/>
<blockValign value="TOP"/>
<lineStyle kind="LINEBEFORE" colorName="#800000" start="0,0" stop="0,-1"/>
<lineStyle kind="LINEAFTER" colorName="#800000" start="0,0" stop="0,-1"/>
<lineStyle kind="LINEABOVE" colorName="#800000" start="0,0" stop="0,0"/>
<lineStyle kind="LINEBELOW" colorName="#800000" start="0,-1" stop="0,-1"/>
<blockBackground colorName="#ffcc99" start="0,0" stop="0,-1"/>
<lineStyle kind="LINEBELOW" colorName="#000000" start="0,-1" stop="0,-1"/>
</blockTableStyle>
<blockTableStyle id="Tableau4">
<blockTableStyle id="Table2">
<blockAlignment value="LEFT"/>
<blockValign value="TOP"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,-1" stop="0,-1"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="1,-1" stop="1,-1"/>
</blockTableStyle>
<initialize>
<paraStyle name="all" alignment="justify"/>
</initialize>
<paraStyle name="P1" fontName="Times-Roman" fontSize="20.0" leading="25" alignment="CENTER" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="P2" fontName="Times-Roman" fontSize="10.0" leading="13" alignment="RIGHT" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="P3" fontName="Times-Roman" alignment="CENTER" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="P4" fontName="Times-Roman" fontSize="11.0" leading="14" alignment="RIGHT" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="P5" fontName="Times-Roman" fontSize="11.0" leading="14" alignment="LEFT" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="P6" fontName="Times-Roman"/>
<paraStyle name="P7" fontName="Times-Roman" alignment="LEFT" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="P8" fontName="Times-Roman"/>
<paraStyle name="P9" fontName="Times-Roman" fontSize="16.0" leading="20" alignment="CENTER" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="P10" fontName="Times-Roman" fontSize="15.0" leading="19" alignment="CENTER" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="P11" fontName="Times-Roman" fontSize="12.0" leading="15" alignment="CENTER" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="P1" fontName="Helvetica-Oblique" fontSize="2.0" leading="3" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="Standard" fontName="Times-Roman"/>
<paraStyle name="Text body" fontName="Times-Roman" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="Heading" fontName="Helvetica" fontSize="14.0" leading="17" spaceBefore="12.0" spaceAfter="6.0"/>
@ -72,6 +77,28 @@
<paraStyle name="Table Heading" fontName="Times-Roman" alignment="CENTER" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="Caption" fontName="Times-Roman" fontSize="12.0" leading="15" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="Index" fontName="Times-Roman"/>
<paraStyle name="Footer" fontName="Times-Roman"/>
<paraStyle name="Horizontal Line" fontName="Times-Roman" fontSize="6.0" leading="8" spaceBefore="0.0" spaceAfter="14.0"/>
<paraStyle name="terp_header" fontName="Helvetica-Bold" fontSize="15.0" leading="19" alignment="LEFT" spaceBefore="12.0" spaceAfter="6.0"/>
<paraStyle name="Heading 9" fontName="Helvetica-Bold" fontSize="75%" leading="NaN" spaceBefore="12.0" spaceAfter="6.0"/>
<paraStyle name="terp_tblheader_General" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="terp_tblheader_Details" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="LEFT" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="terp_default_8" fontName="Helvetica" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="terp_default_Bold_8" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="terp_tblheader_General_Centre" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="CENTER" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="terp_tblheader_General_Right" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="RIGHT" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="terp_tblheader_Details_Centre" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="CENTER" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="terp_tblheader_Details_Right" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="RIGHT" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="terp_default_Right_8" fontName="Helvetica" fontSize="8.0" leading="10" alignment="RIGHT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="terp_default_Centre_8" fontName="Helvetica" fontSize="8.0" leading="10" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="terp_header_Right" fontName="Helvetica-Bold" fontSize="15.0" leading="19" alignment="LEFT" spaceBefore="12.0" spaceAfter="6.0"/>
<paraStyle name="terp_header_Centre" fontName="Helvetica-Bold" fontSize="15.0" leading="19" alignment="CENTER" spaceBefore="12.0" spaceAfter="6.0"/>
<paraStyle name="terp_default_address" fontName="Helvetica" fontSize="10.0" leading="13" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="terp_default_9" fontName="Helvetica" fontSize="9.0" leading="11" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="terp_default_Bold_9" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="terp_default_Centre_9" fontName="Helvetica" fontSize="9.0" leading="11" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="terp_default_Right_9" fontName="Helvetica" fontSize="9.0" leading="11" alignment="RIGHT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="terp_default_1" fontName="Helvetica" fontSize="2.0" leading="3" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
</stylesheet>
<images/>
<story>
@ -81,28 +108,28 @@
<blockTable colWidths="139.0,220.0,152.0" repeatRows="1" style="Table1">
<tr>
<td>
<para style="Table Contents">
<para style="terp_header_Centre">
<font color="white"> </font>
</para>
</td>
<td>
<para style="P1">Reference Guide</para>
<para style="terp_header_Centre">Reference Guide</para>
</td>
<td>
<para style="P2">
<para style="terp_header_Centre">
<font color="white"> </font>
</para>
</td>
</tr>
<tr>
<td>
<para style="Table Contents">[[ company.name ]]</para>
<para style="terp_default_9">[[ company.name ]]</para>
</td>
<td>
<para style="P3">Introspection report on objects</para>
<para style="terp_default_Centre_9">Introspection report on objects</para>
</td>
<td>
<para style="P4">Printed: [[ time.strftime('%y-%m-%d')]]</para>
<para style="terp_default_Right_9">Printed: [[ time.strftime('%y-%m-%d')]]</para>
</td>
</tr>
</blockTable>
@ -111,70 +138,86 @@
</para>
<section>
<para style="Text body">[[ repeatIn(objects, 'module') ]]</para>
<blockTable colWidths="510.0" repeatRows="1" style="Tableau1">
<blockTable colWidths="102.0,102.0,102.0,102.0,102.0" style="module_tbl_heading">
<tr>
<td>
<para style="P9">Module: [[ module.name ]]</para>
<para style="terp_tblheader_General_Centre">Module</para>
</td>
<td>
<para style="terp_tblheader_General_Centre">Name</para>
</td>
<td>
<para style="terp_tblheader_General_Centre">Version</para>
</td>
<td>
<para style="terp_tblheader_General_Centre">Directory</para>
</td>
<td>
<para style="terp_tblheader_General_Centre">Web</para>
</td>
</tr>
</blockTable>
<blockTable colWidths="277.0,234.0" repeatRows="1" style="Tableau2">
<blockTable colWidths="102.0,102.0,102.0,102.0,102.0" style="module_tbl_content">
<tr>
<td>
<para style="Standard">Name: [[ module.shortdesc]]</para>
<para style="terp_default_Centre_8">[[ module.name ]]</para>
</td>
<td>
<para style="Standard">Version: [[module.latest_version]]</para>
</td>
</tr>
<tr>
<td>
<para style="Standard">Directory: [[ module.name ]]</para>
<para style="terp_default_Centre_8">[[ module.shortdesc]]</para>
</td>
<td>
<para style="Standard">Web: [[ module.website ]]</para>
<para style="terp_default_Centre_8">[[module.latest_version]]</para>
</td>
<td>
<para style="terp_default_Centre_8">[[ module.name ]]</para>
</td>
<td>
<para style="terp_default_Centre_8">[[ module.website ]]</para>
</td>
</tr>
</blockTable>
<para style="P6">[[ format(module.description or '') ]]</para>
<para style="terp_default_9">
<font color="white"> </font>
</para>
<para style="terp_default_9">[[ module.description ]]</para>
<section>
<para style="Standard">[[ repeatIn(findobj(module.name) ,'object') ]]</para>
<para style="terp_default_9">
<font color="white"> </font>
</para>
<para style="terp_default_9">[[ repeatIn(findobj(module.name) ,'object') ]]</para>
<para style="terp_default_1">
<font color="white"> </font>
</para>
<blockTable colWidths="510.0" repeatRows="1" style="Tableau3">
<tr>
<td>
<para style="P10">Object: [[ object.model ]]</para>
<para style="P11">Description : [[ object.name ]]</para>
<para style="P5">[[ format(objdoc(object.model)) ]]</para>
<para style="terp_tblheader_Details">Object: [[ object.name ]] [[ objdoc(object.model) ]]</para>
</td>
</tr>
</blockTable>
<blockTable colWidths="113.0,397.0" repeatRows="1" style="Tableau4">
<tr>
<td>
<para style="P7">[[ repeatIn(findflds(object.model), 'field') ]] <i>[[ field[0] ]]</i></para>
</td>
<td>
<para style="P8">[[ field[1].get('string', 'Unknown') ]], [[ field[1]['type'] ]] [[field[1].get('required',False) and ', required']] [[field[1].get('readonly',False) and ', readonly']] </para>
<para style="Standard">[[ field[1].get('help', '') ]]</para>
</td>
</tr>
</blockTable>
<para style="Standard">
<font color="white"> </font>
</para>
<section>
<para style="terp_default_1">
<font color="white"> </font>
</para>
</section>
<section>
<para style="P1">[[ repeatIn(findflds(object.model), 'field') ]]</para>
<blockTable colWidths="113.0,397.0" repeatRows="1" style="Table2">
<tr>
<td>
<para style="terp_default_9">[[ field[0] ]]</para>
</td>
<td>
<para style="terp_default_9">[[ field[1].get('string', 'Unknown') ]], [[ field[1]['type'] ]] [[field[1].get('required',False) and ', required']] [[field[1].get('readonly',False) and ', readonly']] </para>
<para style="terp_default_9">[[ field[1].get('help', '') ]]</para>
</td>
</tr>
</blockTable>
<para style="terp_default_1">
<font color="white"> </font>
</para>
</section>
</section>
<para style="Standard">
<font color="white"> </font>
</para>
<para style="Standard">
<font color="white"> </font>
</para>
<para style="Standard">
<font color="white"> </font>
</para>
</section>
<para style="Standard">
<font color="white"> </font>
</para>
</story>
</document>

View File

@ -38,7 +38,8 @@
<field name="domain">[('res_id','=',False)]</field>
<field name="view_id" ref="ir_property_view_tree"/>
</record>
<menuitem id="next_id_15" name="Properties" parent="base.menu_custom"/><menuitem action="ir_property_form" id="menu_ir_property_form" parent="next_id_15"/>
<menuitem id="next_id_15" name="Properties" parent="base.menu_config"/>
<menuitem action="ir_property_form" id="menu_ir_property_form" parent="next_id_15"/>
<record id="ir_property_form_all" model="ir.actions.act_window">
<field name="name">All Properties</field>

View File

@ -259,7 +259,7 @@ class res_partner(osv.osv):
raise osv.except_osv(_('Warning'), _("Couldn't generate the next id because some partners have an alphabetic id !"))
# update the current partner
cr.execute("update res_partner set ref=%d where id=%d", (nextref, ids[0]))
cr.execute("update res_partner set ref=%s where id=%s", (nextref, ids[0]))
return True
def view_header_get(self, cr, uid, view_id, view_type, context):
@ -306,10 +306,10 @@ class res_partner_address(osv.osv):
if context.get('contact_display', 'contact')=='partner':
res.append((r['id'], r['partner_id'][1]))
else:
addr = str(r['name'] or '')
addr = r['name'] or ''
if r['name'] and (r['zip'] or r['city']):
addr += ', '
addr += str(r['street'] or '') + ' ' + str(r['zip'] or '') + ' ' + str(r['city'] or '')
addr += (r['street'] or '') + ' ' + (r['zip'] or '') + ' ' + (r['city'] or '')
res.append((r['id'], addr.strip() or '/'))
return res

View File

@ -94,7 +94,7 @@
<field name="fax"/>
<newline/>
<field name="mobile" select="2"/>
<field name="email" select="2"/>
<field name="email" select="2" widget="email"/>
</form>
</field>
</record>
@ -146,7 +146,7 @@
<field name="fax"/>
<newline/>
<field name="mobile"/>
<field name="email"/>
<field name="email" widget="email"/>
</form>
</field>
</record>
@ -183,7 +183,7 @@
<field name="view_type">form</field>
<field name="domain">[('domain','=','partner')]</field>
</record>
<menuitem action="action_partner_title_partner" id="menu_partner_title_partner" parent="action_partner_title"/>
<menuitem action="action_partner_title_partner" id="menu_partner_title_partner" parent="menu_partner_title"/>
<record id="action_partner_title_contact" model="ir.actions.act_window">
<field name="name">Contacts Titles</field>
@ -192,7 +192,7 @@
<field name="view_type">form</field>
<field name="domain">[('domain','=','contact')]</field>
</record>
<menuitem action="action_partner_title_contact" id="menu_partner_title_contact" parent="action_partner_title"/>
<menuitem action="action_partner_title_contact" id="menu_partner_title_contact" parent="menu_partner_title"/>
<!--
=======================

View File

@ -39,7 +39,7 @@ class res_currency(osv.osv):
date=time.strftime('%Y-%m-%d')
date= date or time.strftime('%Y-%m-%d')
for id in ids:
cr.execute("SELECT currency_id, rate FROM res_currency_rate WHERE currency_id = %d AND name <= '%s' ORDER BY name desc LIMIT 1" % (id, date))
cr.execute("SELECT currency_id, rate FROM res_currency_rate WHERE currency_id = %s AND name <= '%s' ORDER BY name desc LIMIT 1" % (id, date))
if cr.rowcount:
id, rate=cr.fetchall()[0]
res[id]=rate
@ -91,7 +91,7 @@ class res_currency(osv.osv):
if account and (account.currency_mode=='average') and account.currency_id:
q = self.pool.get('account.move.line')._query_get(cr, uid, context=context)
cr.execute('select sum(debit-credit),sum(amount_currency) from account_move_line l ' \
'where l.currency_id=%d and l.account_id=%d and '+q, (account.currency_id.id,account.id,))
'where l.currency_id=%s and l.account_id=%s and '+q, (account.currency_id.id,account.id,))
tot1,tot2 = cr.fetchone()
if tot2 and not account_invert:
rate = float(tot1)/float(tot2)

View File

@ -1,7 +1,7 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
@ -21,24 +21,118 @@
##############################################################################
from osv import fields, osv
from locale import localeconv
class lang(osv.osv):
_name = "res.lang"
_description = "Languages"
def _get_default_date_format(self,cursor,user,context={}):
return '%Y-%m-%d'
def _get_default_time_format(self,cursor,user,context={}):
return '%H:%M:%S'
_columns = {
'name': fields.char('Name', size=64, required=True),
'code': fields.char('Code', size=5, required=True),
'translatable': fields.boolean('Translatable'),
'active': fields.boolean('Active'),
'direction': fields.selection([('ltr', 'Left-to-right'), ('rtl', 'Right-to-left')], 'Direction',resuired=True),
'direction': fields.selection([('ltr', 'Left-to-Right'), ('rtl', 'Right-to-Left')], 'Direction',required=True),
'date_format':fields.char('Date Format',size=64,required=True),
'time_format':fields.char('Time Format',size=64,required=True),
'grouping':fields.char('Separator Format',size=64,required=True,help="The Separator Format should be like [,n] where 0 < n :starting from Unit digit.-1 will end the separation. e.g. [3,2,-1] will represent 106500 to be 1,06,500;[1,2,-1] will represent it to be 106,50,0;[3] will represent it as 106,500. Provided ',' as the thousand separator in each case."),
'decimal_point':fields.char('Decimal Separator', size=64,required=True),
'thousands_sep':fields.char('Thousands Separator',size=64),
}
_defaults = {
'active': lambda *a: 1,
'translatable': lambda *a: 0,
'direction': lambda *a: 'ltr',
'date_format':_get_default_date_format,
'time_format':_get_default_time_format,
'grouping':lambda *a: '[]',
'decimal_point':lambda *a: '.',
'thousands_sep':lambda *a: ',',
}
def _group(self,cr,uid,ids,s, monetary=False):
conv = localeconv()
lang_obj=self.browse(cr,uid,ids[0])
thousands_sep = lang_obj.thousands_sep or conv[monetary and 'mon_thousands_sep' or 'thousands_sep']
grouping = eval(lang_obj.grouping)
if not grouping:
return (s, 0)
result = ""
seps = 0
spaces = ""
if s[-1] == ' ':
sp = s.find(' ')
spaces = s[sp:]
s = s[:sp]
while s and grouping:
# if grouping is -1, we are done
if grouping[0] == -1:
break
# 0: re-use last group ad infinitum
elif grouping[0] != 0:
#process last group
group = grouping[0]
grouping = grouping[1:]
if result:
result = s[-group:] + thousands_sep + result
seps += 1
else:
result = s[-group:]
s = s[:-group]
if s and s[-1] not in "0123456789":
# the leading string is only spaces and signs
return s + result + spaces, seps
if not result:
return s + spaces, seps
if s:
result = s + thousands_sep + result
seps += 1
return result + spaces, seps
def format(self,cr,uid,ids,percent, value, grouping=False, monetary=False):
""" Format() will return the language-specific output for float values"""
if percent[0] != '%':
raise ValueError("format() must be given exactly one %char format specifier")
lang_obj=self.browse(cr,uid,ids[0])
formatted = percent % value
# floats and decimal ints need special action!
if percent[-1] in 'eEfFgG':
seps = 0
parts = formatted.split('.')
if grouping:
parts[0], seps = self._group(cr,uid,ids,parts[0], monetary=monetary)
decimal_point=lang_obj.decimal_point
formatted = decimal_point.join(parts)
while seps:
sp = formatted.find(' ')
if sp == -1: break
formatted = formatted[:sp] + formatted[sp+1:]
seps -= 1
elif percent[-1] in 'diu':
if grouping:
formatted = self._group(cr,uid,ids,formatted, monetary=monetary)[0]
return formatted
# import re, operator
# _percent_re = re.compile(r'%(?:\((?P<key>.*?)\))?'
# r'(?P<modifiers>[-#0-9 +*.hlL]*?)[eEfFgGdiouxXcrs%]')
lang()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -15,6 +15,88 @@
</tree>
</field>
</record>
<record id="res_lang_form" model="ir.ui.view">
<field name="name">res.lang.form</field>
<field name="model">res.lang</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Languages">
<group col="4" colspan="4">
<field name="name" />
<field name="code" />
<field name="active" />
<field name="translatable"/>
<field name="grouping" />
<field name="direction" />
<newline/>
<field name="date_format"/>
<field name="time_format"/>
<field name="decimal_point"/>
<field name="thousands_sep"/>
<newline/>
</group>
<separator colspan="4" string="Legends for Date and Time Formats"/>
<group col="4" colspan="4">
<label align="0.0" string="%%a - Abbreviated weekday name."/>
<label align="0.0" string="%%A - Full weekday name."/>
<newline/>
<label align="0.0" string="%%b - Abbreviated month name."/>
<label align="0.0" string="%%B - Full month name." />
<newline/>
<label align="0.0" string="%%c - Appropriate date and time representation." />
<label align="0.0" string="%%d - Day of the month as a decimal number [01,31]." />
<newline/>
<label align="0.0" string="%%H - Hour (24-hour clock) as a decimal number [00,23]." />
<label align="0.0" string="%%I - Hour (12-hour clock) as a decimal number [01,12]." />
<newline/>
<label align="0.0" string="%%j - Day of the year as a decimal number [001,366]." />
<label align="0.0" string="%%m - Month as a decimal number [01,12]." />
<newline/>
<label align="0.0" string="%%M - Minute as a decimal number [00,59]." />
<label align="0.0" string="%%p - Equivalent of either AM or PM." />
<newline/>
<label align="0.0" string="%%S - Second as a decimal number [00,61]." />
<label align="0.0" string="%%w - Weekday as a decimal number [0(Sunday),6]." />
<newline/>
<label align="0.0" string="%%x - Appropriate date representation." />
<label align="0.0" string="%%X - Appropriate time representation." />
<newline/>
<label align="0.0" string="%%y - Year without century as a decimal number [00,99]." />
<label align="0.0" string="%%Y - Year with century as a decimal number." />
<newline/>
<label align="0.0" string="%%U - Week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Sunday are considered to be in week 0." />
<label align="0.0" string="%%W - Week number of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Monday are considered to be in week 0." />
<newline/>
<label align="0.0" string="======================================================" />
</group>
<newline/>
<group colspan="4" col="4">
<separator string="Examples"/>
<newline/>
<label align="0.0" string="1. %%c ==> Fri Dec 5 18:25:20 2008"/>
<label align="0.0" string="2. %%a ,%%A ==> Fri, Friday"/>
<newline/>
<label align="0.0" string="3. %%x ,%%X ==> 12/05/08, 18:25:20"/>
<label align="0.0" string="4. %%b, %%B ==> Dec, December"/>
<newline/>
<label align="0.0" string="5. %%y, %%Y ==> 08, 2008"/>
<label align="0.0" string="6. %%d, %%m ==> 05, 12"/>
<newline/>
<label align="0.0" string="7. %%H:%%M:%%S ==> 18:25:20"/>
<label align="0.0" string="8. %%I:%%M:%%S %%p ==> 06:25:20 PM"/>
<newline/>
<label align="0.0" string="9. %%j ==> 340"/>
<label align="0.0" string="10. %%S ==> 20"/>
<newline/>
<label align="0.0" string="11. %%U or %%W ==> 48 (49th week)"/>
<label align="0.0" string="12. %%w ==> 5 ( Friday is the 6th day)"/>
<newline/>
</group>
</form>
</field>
</record>
<record id="res_lang_act_window" model="ir.actions.act_window">
<field name="name">Languages</field>
<field name="res_model">res.lang</field>

View File

@ -34,8 +34,8 @@ class res_request(osv.osv):
def request_send(self, cr, uid, ids, *args):
for id in ids:
cr.execute('update res_request set state=%s,date_sent=%s where id=%d', ('waiting', time.strftime('%Y-%m-%d %H:%M:%S'), id))
cr.execute('select act_from,act_to,body,date_sent from res_request where id=%d', (id,))
cr.execute('update res_request set state=%s,date_sent=%s where id=%s', ('waiting', time.strftime('%Y-%m-%d %H:%M:%S'), id))
cr.execute('select act_from,act_to,body,date_sent from res_request where id=%s', (id,))
values = cr.dictfetchone()
if values['body'] and (len(values['body']) > 128):
values['name'] = values['body'][:125] + '...'
@ -47,7 +47,7 @@ class res_request(osv.osv):
def request_reply(self, cr, uid, ids, *args):
for id in ids:
cr.execute("update res_request set state='active', act_from=%d, act_to=act_from, trigger_date=NULL, body='' where id=%d", (uid,id))
cr.execute("update res_request set state='active', act_from=%s, act_to=act_from, trigger_date=NULL, body='' where id=%s", (uid,id))
return True
def request_close(self, cr, uid, ids, *args):
@ -55,9 +55,9 @@ class res_request(osv.osv):
return True
def request_get(self, cr, uid):
cr.execute('select id from res_request where act_to=%d and (trigger_date<=%s or trigger_date is null) and active=True', (uid,time.strftime('%Y-%m-%d')))
cr.execute('select id from res_request where act_to=%s and (trigger_date<=%s or trigger_date is null) and active=True', (uid,time.strftime('%Y-%m-%d')))
ids = map(lambda x:x[0], cr.fetchall())
cr.execute('select id from res_request where act_from=%d and (act_to<>%d) and (trigger_date<=%s or trigger_date is null) and active=True', (uid,uid,time.strftime('%Y-%m-%d')))
cr.execute('select id from res_request where act_from=%s and (act_to<>%s) and (trigger_date<=%s or trigger_date is null) and active=True', (uid,uid,time.strftime('%Y-%m-%d')))
ids2 = map(lambda x:x[0], cr.fetchall())
return (ids, ids2)

View File

@ -74,7 +74,7 @@ class roles(osv.osv):
def check(self, cr, uid, ids, role_id):
if role_id in ids:
return True
cr.execute('select parent_id from res_roles where id=%d', (role_id,))
cr.execute('select parent_id from res_roles where id=%s', (role_id,))
roles = cr.fetchone()[0]
if roles:
return self.check(cr, uid, ids, roles)
@ -152,7 +152,7 @@ class users(osv.osv):
'groups_id': _get_group,
}
def company_get(self, cr, uid, uid2):
company_id = self.pool.get('res.users').browse(cr, uid, uid).company_id.id
company_id = self.pool.get('res.users').browse(cr, uid, uid2).company_id.id
return company_id
company_get = tools.cache()(company_get)

View File

@ -7,6 +7,7 @@
<rng:optional><rng:attribute name="editable"/></rng:optional>
<rng:optional><rng:attribute name="type"/></rng:optional>
<rng:optional><rng:attribute name="position"/></rng:optional>
<rng:optional><rng:attribute name="link"/></rng:optional>
<rng:zeroOrMore>
<rng:choice>
<rng:ref name="notebook"/>
@ -33,12 +34,15 @@
<rng:optional><rng:attribute name="editable"/></rng:optional>
<rng:optional><rng:attribute name="toolbar"/></rng:optional>
<rng:optional><rng:attribute name="position"/></rng:optional>
<rng:optional><rng:attribute name="link"/></rng:optional>
<rng:optional><rng:attribute name="type"/></rng:optional>
<rng:zeroOrMore>
<rng:choice>
<rng:ref name="field"/>
<rng:ref name="separator"/>
<rng:ref name="tree"/>
<rng:ref name="group"/>
<rng:ref name="button"/>
<rng:element name="newline"><rng:empty/></rng:element>
</rng:choice>
</rng:zeroOrMore>
@ -57,6 +61,35 @@
<rng:optional><rng:attribute name="nolabel"/></rng:optional>
<rng:optional><rng:attribute name="colspan"/></rng:optional>
<rng:optional><rng:attribute name="string"/></rng:optional>
<rng:optional><rng:attribute name="angle"/></rng:optional>
<rng:zeroOrMore>
<rng:text/>
</rng:zeroOrMore>
</rng:element>
</rng:define>
<rng:define name="level">
<rng:element name="level">
<rng:optional><rng:attribute name="object"/></rng:optional>
<rng:optional><rng:attribute name="link"/></rng:optional>
<rng:optional><rng:attribute name="domain"/></rng:optional>
<rng:oneOrMore>
<rng:optional><rng:ref name="field"/></rng:optional>
</rng:oneOrMore>
</rng:element>
</rng:define>
<rng:define name="gantt">
<rng:element name="gantt">
<rng:optional><rng:attribute name="color"/></rng:optional>
<rng:optional><rng:attribute name="date_delay"/></rng:optional>
<rng:optional><rng:attribute name="date_start"/></rng:optional>
<rng:optional><rng:attribute name="date_string"/></rng:optional>
<rng:optional><rng:attribute name="string"/></rng:optional>
<rng:zeroOrMore>
<rng:optional><rng:ref name="level"/></rng:optional>
<rng:optional><rng:ref name="field"/></rng:optional>
</rng:zeroOrMore>
</rng:element>
</rng:define>
@ -123,6 +156,17 @@
<rng:optional><rng:attribute name="col"/></rng:optional>
<rng:optional><rng:attribute name="select"/></rng:optional>
<rng:optional><rng:attribute name="position"/></rng:optional>
<rng:zeroOrMore>
<rng:choice>
<rng:ref name="separator"/>
<rng:ref name="button"/>
<rng:ref name="field"/>
<rng:ref name="label" />
<rng:ref name="group" />
<rng:element name="properties"><rng:empty/></rng:element>
<rng:element name="newline"><rng:empty/></rng:element>
</rng:choice>
</rng:zeroOrMore>
</rng:element>
</rng:define>
@ -132,9 +176,10 @@
<rng:optional><rng:attribute name="position"/></rng:optional>
<rng:zeroOrMore>
<rng:choice>
<rng:ref name="notebook" />
<rng:ref name="graph" />
<rng:ref name="calendar" />
<rng:ref name="notebook" />
<rng:ref name="graph" />
<rng:ref name="calendar" />
<rng:ref name="gantt" />
<rng:ref name="form"/>
<rng:ref name="tree"/>
<rng:ref name="field"/>
@ -181,17 +226,25 @@
<rng:optional><rng:attribute name="digits"/></rng:optional>
<rng:optional><rng:attribute name="icon"/></rng:optional>
<rng:optional><rng:attribute name="mode"/></rng:optional>
<rng:optional><rng:attribute name="img_width"/></rng:optional>
<rng:optional><rng:attribute name="img_height"/></rng:optional>
<rng:optional><rng:attribute name="size"/></rng:optional>
<rng:optional><rng:attribute name="filename"/></rng:optional>
<rng:optional><rng:attribute name="fieldname"/></rng:optional>
<rng:optional><rng:attribute name="height"/></rng:optional>
<rng:optional><rng:attribute name="rowspan"/></rng:optional>
<rng:optional><rng:attribute name="align"/></rng:optional>
<rng:zeroOrMore>
<rng:choice>
<rng:ref name="form"/>
<rng:ref name="tree"/>
<rng:ref name="field"/>
<rng:ref name="label"/>
<rng:ref name="separator"/>
<rng:ref name="xpath"/>
<rng:ref name="button"/>
<rng:ref name="group"/>
<rng:ref name="graph"/>
<rng:element name="newline"><rng:empty/></rng:element>
</rng:choice>
</rng:zeroOrMore>
@ -203,12 +256,15 @@
<rng:optional><rng:attribute name="attrs"/></rng:optional>
<rng:optional><rng:attribute name="col"/></rng:optional>
<rng:optional><rng:attribute name="colspan"/></rng:optional>
<rng:optional><rng:attribute name="position"/></rng:optional>
<rng:optional><rng:attribute name="expand"/></rng:optional>
<rng:optional><rng:attribute name="states"/></rng:optional>
<rng:optional><rng:attribute name="groups"/></rng:optional>
<rng:optional><rng:attribute name="string"/></rng:optional>
<rng:optional><rng:attribute name="fill"/></rng:optional>
<rng:optional><rng:attribute name="height"/></rng:optional>
<rng:optional><rng:attribute name="name"/></rng:optional>
<rng:optional><rng:attribute name="color" /></rng:optional>
<rng:zeroOrMore>
<rng:choice>
<rng:ref name="separator"/>
@ -231,6 +287,7 @@
<rng:optional><rng:attribute name="date_stop" /></rng:optional>
<rng:optional><rng:attribute name="day_length" /></rng:optional>
<rng:optional><rng:attribute name="date_delay" /></rng:optional>
<rng:optional><rng:attribute name="type" /></rng:optional>
<rng:oneOrMore>
<rng:ref name="field"/>
</rng:oneOrMore>
@ -242,6 +299,7 @@
<rng:optional><rng:attribute name="string" /></rng:optional>
<rng:optional><rng:attribute name="orientation" /></rng:optional>
<rng:optional><rng:attribute name="type" /></rng:optional>
<rng:optional><rng:attribute name="color"/></rng:optional>
<rng:oneOrMore>
<rng:ref name="field"/>
</rng:oneOrMore>
@ -263,18 +321,20 @@
<rng:optional><rng:attribute name="target"/></rng:optional>
<rng:optional><rng:attribute name="readonly"/></rng:optional>
<rng:optional><rng:attribute name="position"/></rng:optional>
<rng:optional><rng:attribute name="context"/></rng:optional>
<rng:zeroOrMore>
<rng:choice>
<rng:ref name="form" />
<rng:ref name="field" />
<rng:ref name="tree" />
<rng:ref name="notebook" />
<rng:ref name="graph" />
<rng:ref name="calendar" />
<rng:ref name="xpath" />
<rng:ref name="page" />
<rng:ref name="separator"/>
<rng:ref name="button"/>
<rng:ref name="form" />
<rng:ref name="field" />
<rng:ref name="tree" />
<rng:ref name="notebook" />
<rng:ref name="graph" />
<rng:ref name="calendar" />
<rng:ref name="gantt" />
<rng:ref name="xpath" />
<rng:ref name="page" />
<rng:ref name="separator"/>
<rng:ref name="button"/>
<rng:element name="properties"><rng:empty/></rng:element>
<rng:element name="newline"><rng:empty/></rng:element>
</rng:choice>
@ -286,11 +346,13 @@
<rng:start>
<rng:choice>
<rng:ref name="form" />
<rng:ref name="group" />
<rng:ref name="field" />
<rng:ref name="tree" />
<rng:ref name="notebook" />
<rng:ref name="graph" />
<rng:ref name="calendar" />
<rng:ref name="gantt" />
<rng:ref name="xpath" />
<rng:ref name="page" />
<rng:ref name="separator"/>

View File

@ -2,7 +2,7 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
@ -157,13 +157,12 @@ def init_logger():
if config['logfile']:
logf = config['logfile']
# test if the directories exist, else create them
try:
dirname = os.path.dirname(logf)
if not os.path.isdir(dirname):
res = os.makedirs(dirname)
if dirname and not os.path.isdir(dirname):
os.makedirs(dirname)
handler = logging.handlers.TimedRotatingFileHandler(logf,'D',1,30)
except:
except Exception, ex:
sys.stderr.write("ERROR: couldn't create the logfile directory\n")
handler = logging.StreamHandler(sys.stdout)
else:
@ -177,7 +176,7 @@ def init_logger():
# add the handler to the root logger
logging.getLogger().addHandler(handler)
logging.getLogger().setLevel(logging.INFO)
logging.getLogger().setLevel(config['log_level'])
if (not isinstance(handler, logging.FileHandler)) and os.name != 'nt':
# change color of level names
@ -204,8 +203,16 @@ def init_logger():
class Logger(object):
def notifyChannel(self, name, level, msg):
log = logging.getLogger(name)
getattr(log, level)(msg)
level_method = getattr(log, level)
result = str(msg).strip().split('\n')
if len(result)>1:
for idx, s in enumerate(result):
level_method('[%02d]: %s' % (idx+1, s,))
elif result:
level_method(result[0])
init_logger()
class Agent(object):
_timers = []
@ -391,12 +398,14 @@ class TinySocketClientThread(threading.Thread):
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)
print e
print tb_s
import tools
if tools.config['debug_mode']:
import pdb
tb = sys.exc_info()[2]
pdb.post_mortem(tb)
e = Exception(e.message)
ts.mysend(e, exception=True, traceback=tb_s)
except:
pass

View File

@ -53,23 +53,24 @@ __version__ = release.version
# get logger
#----------------------------------------------------------
import netsvc
netsvc.init_logger()
logger = netsvc.Logger()
#-----------------------------------------------------------------------
# import the tools module so that the commandline parameters are parsed
#-----------------------------------------------------------------------
import tools
logger.notifyChannel("server", netsvc.LOG_INFO, "version - %s" % release.version )
for name, value in [('addons_path', tools.config['addons_path']),
('database hostname', tools.config['db_host'] or 'localhost')]:
logger.notifyChannel("server", netsvc.LOG_INFO, "%s - %s" % ( name, value ))
import time
if sys.platform == 'win32':
import mx.DateTime
mx.DateTime.strptime = lambda x, y: mx.DateTime.mktime(time.strptime(x, y))
#os.chdir(tools.file_path_root)
#----------------------------------------------------------
# init net service
#----------------------------------------------------------
@ -81,35 +82,13 @@ dispatcher.monitor(signal.SIGINT)
#---------------------------------------------------------------
# connect to the database and initialize it with base if needed
#---------------------------------------------------------------
import psycopg
import pooler
db_name = tools.config["db_name"]
# test whether it is needed to initialize the db (the db is empty)
#try:
# cr = pooler.get_db_only(db_name).cursor()
#except psycopg.OperationalError:
# logger.notifyChannel("init", netsvc.LOG_INFO, "could not connect to database '%s'!" % db_name,)
# cr = None
#if cr:
# cr.execute("SELECT relname FROM pg_class WHERE relkind='r' AND relname='ir_ui_menu'")
# if len(cr.fetchall())==0:
##if False:
# logger.notifyChannel("init", netsvc.LOG_INFO, "init db")
# tools.init_db(cr)
# # in that case, force --init=all
# tools.config["init"]["all"] = 1
# tools.config['update']['all'] = 1
# if not tools.config['without_demo']:
# tools.config["demo"]['all'] = 1
# cr.close()
#----------------------------------------------------------
# launch modules install/upgrade/removes if needed
#----------------------------------------------------------
if tools.config['upgrade']:
print 'Upgrading new modules...'
logger.notifyChannel('init', netsvc.LOG_INFO, 'Upgrading new modules...')
import tools.upgrade
(toinit, toupdate) = tools.upgrade.upgrade()
for m in toinit:
@ -120,15 +99,24 @@ if tools.config['upgrade']:
#----------------------------------------------------------
# import basic modules
#----------------------------------------------------------
import osv, workflow, report, service
import osv
import workflow
import report
import service
#----------------------------------------------------------
# import addons
#----------------------------------------------------------
import addons
if tools.config['init'] or tools.config['update']:
pooler.get_db_and_pool(tools.config['db_name'], update_module=True)
#----------------------------------------------------------
# Load and update databases if requested
#----------------------------------------------------------
if tools.config['db_name']:
for db in tools.config['db_name'].split(','):
pooler.get_db_and_pool(db, update_module=tools.config['init'] or tools.config['update'])
#----------------------------------------------------------
# translation stuff
@ -179,17 +167,14 @@ if tools.config['xmlrpc']:
if tools.config["xmlrpc"]:
xml_gw = netsvc.xmlrpc.RpcGateway('web-services')
httpd.attach("/xmlrpc", xml_gw)
logger.notifyChannel("web-services", netsvc.LOG_INFO,
"starting XML-RPC" + \
(tools.config['secure'] and ' Secure' or '') + \
" services, port " + str(port))
logger.notifyChannel("web-services", netsvc.LOG_INFO, "starting XML-RPC%s services, port %s" % ((tools.config['secure'] and ' Secure' or ''), port))
#
#if tools.config["soap"]:
# soap_gw = netsvc.xmlrpc.RpcGateway('web-services')
# httpd.attach("/soap", soap_gw )
# logger.notifyChannel("web-services", netsvc.LOG_INFO, 'starting SOAP services, port '+str(port))
#
#
#if tools.config["soap"]:
# soap_gw = netsvc.xmlrpc.RpcGateway('web-services')
# httpd.attach("/soap", soap_gw )
# logger.notifyChannel("web-services", netsvc.LOG_INFO, 'starting SOAP services, port '+str(port))
#
if tools.config['netrpc']:
try:

View File

@ -51,7 +51,7 @@ class expression(object):
subids = ids[i:i+cr.IN_MAX]
cr.execute('SELECT "%s"' \
' FROM "%s"' \
' WHERE "%s" in (%s)' % (s, f, w, ','.join(['%d']*len(subids))),
' WHERE "%s" in (%s)' % (s, f, w, ','.join(['%s']*len(subids))),
subids)
res.extend([r[0] for r in cr.fetchall()])
return res
@ -244,7 +244,7 @@ class expression(object):
if len_after:
if left == 'id':
instr = ','.join(['%d'] * len_after)
instr = ','.join(['%s'] * len_after)
else:
instr = ','.join([table._columns[left]._symbol_set[0]] * len_after)
query = '(%s.%s %s (%s))' % (table._table, left, operator, instr)

View File

@ -35,7 +35,7 @@
import string
import netsvc
import psycopg
from psycopg2 import Binary
import warnings
import tools
@ -86,7 +86,7 @@ class _column(object):
pass
def set(self, cr, obj, id, name, value, user=None, context=None):
cr.execute('update '+obj._table+' set '+name+'='+self._symbol_set[0]+' where id=%d', (self._symbol_set[1](value), id))
cr.execute('update '+obj._table+' set '+name+'='+self._symbol_set[0]+' where id=%s', (self._symbol_set[1](value), id))
def set_memory(self, cr, obj, id, name, value, user=None, context=None):
raise Exception(_('Not implemented set_memory method !'))
@ -118,13 +118,13 @@ class boolean(_column):
class integer_big(_column):
_type = 'integer_big'
_symbol_c = '%d'
_symbol_c = '%s'
_symbol_f = lambda x: int(x or 0)
_symbol_set = (_symbol_c, _symbol_f)
class integer(_column):
_type = 'integer'
_symbol_c = '%d'
_symbol_c = '%s'
_symbol_f = lambda x: int(x or 0)
_symbol_set = (_symbol_c, _symbol_f)
@ -168,10 +168,9 @@ class text(_column):
import __builtin__
class float(_column):
_type = 'float'
_symbol_c = '%f'
_symbol_c = '%s'
_symbol_f = lambda x: __builtin__.float(x or 0.0)
_symbol_set = (_symbol_c, _symbol_f)
@ -195,8 +194,9 @@ class time(_column):
class binary(_column):
_type = 'binary'
_symbol_c = '%s'
_symbol_f = lambda symb: symb and psycopg.Binary(symb) or None
_symbol_f = lambda symb: symb and Binary(symb) or None
_symbol_set = (_symbol_c, _symbol_f)
_symbol_get = lambda self, x: x and str(x)
_classic_read = False
@ -209,7 +209,6 @@ class binary(_column):
context = {}
if not values:
values = []
res = {}
for i in ids:
val = None
@ -217,10 +216,10 @@ class binary(_column):
if v['id'] == i:
val = v[name]
break
res.setdefault(i, val)
if context.get('bin_size', False):
res[i] = tools.human_size(val)
else:
res[i] = val
return res
get = get_memory
@ -263,9 +262,9 @@ class one2one(_column):
self._table = obj_src.pool.get(self._obj)._table
if act[0] == 0:
id_new = obj.create(cr, user, act[1])
cr.execute('update '+obj_src._table+' set '+field+'=%d where id=%d', (id_new, id))
cr.execute('update '+obj_src._table+' set '+field+'=%s where id=%s', (id_new, id))
else:
cr.execute('select '+field+' from '+obj_src._table+' where id=%d', (act[0],))
cr.execute('select '+field+' from '+obj_src._table+' where id=%s', (act[0],))
id = cr.fetchone()[0]
obj.write(cr, user, [id], act[1], context=context)
@ -277,6 +276,9 @@ class many2one(_column):
_classic_read = False
_classic_write = True
_type = 'many2one'
_symbol_c = '%s'
_symbol_f = lambda x: x or None
_symbol_set = (_symbol_c, _symbol_f)
def __init__(self, obj, string='unknown', **args):
_column.__init__(self, string=string, **args)
@ -331,20 +333,20 @@ class many2one(_column):
for act in values:
if act[0] == 0:
id_new = obj.create(cr, act[2])
cr.execute('update '+obj_src._table+' set '+field+'=%d where id=%d', (id_new, id))
cr.execute('update '+obj_src._table+' set '+field+'=%s where id=%s', (id_new, id))
elif act[0] == 1:
obj.write(cr, [act[1]], act[2], context=context)
elif act[0] == 2:
cr.execute('delete from '+self._table+' where id=%d', (act[1],))
cr.execute('delete from '+self._table+' where id=%s', (act[1],))
elif act[0] == 3 or act[0] == 5:
cr.execute('update '+obj_src._table+' set '+field+'=null where id=%d', (id,))
cr.execute('update '+obj_src._table+' set '+field+'=null where id=%s', (id,))
elif act[0] == 4:
cr.execute('update '+obj_src._table+' set '+field+'=%d where id=%d', (act[1], id))
cr.execute('update '+obj_src._table+' set '+field+'=%s where id=%s', (act[1], id))
else:
if values:
cr.execute('update '+obj_src._table+' set '+field+'=%d where id=%d', (values, id))
cr.execute('update '+obj_src._table+' set '+field+'=%s where id=%s', (values, id))
else:
cr.execute('update '+obj_src._table+' set '+field+'=null where id=%d', (id,))
cr.execute('update '+obj_src._table+' set '+field+'=null where id=%s', (id,))
def search(self, cr, obj, args, name, value, offset=0, limit=None, uid=None):
return obj.pool.get(self._obj).search(cr, uid, args+self._domain+[('name', 'like', value)], offset, limit)
@ -435,19 +437,19 @@ class one2many(_column):
elif act[0] == 2:
obj.unlink(cr, user, [act[1]], context=context)
elif act[0] == 3:
cr.execute('update '+_table+' set '+self._fields_id+'=null where id=%d', (act[1],))
cr.execute('update '+_table+' set '+self._fields_id+'=null where id=%s', (act[1],))
elif act[0] == 4:
cr.execute('update '+_table+' set '+self._fields_id+'=%d where id=%d', (id, act[1]))
cr.execute('update '+_table+' set '+self._fields_id+'=%s where id=%s', (id, act[1]))
elif act[0] == 5:
cr.execute('update '+_table+' set '+self._fields_id+'=null where '+self._fields_id+'=%d', (id,))
cr.execute('update '+_table+' set '+self._fields_id+'=null where '+self._fields_id+'=%s', (id,))
elif act[0] == 6:
if not act[2]:
ids2 = [0]
else:
ids2 = act[2]
cr.execute('update '+_table+' set '+self._fields_id+'=NULL where '+self._fields_id+'=%d and id not in ('+','.join(map(str, ids2))+')', (id,))
cr.execute('update '+_table+' set '+self._fields_id+'=NULL where '+self._fields_id+'=%s and id not in ('+','.join(map(str, ids2))+')', (id,))
if act[2]:
cr.execute('update '+_table+' set '+self._fields_id+'=%d where id in ('+','.join(map(str, act[2]))+')', (id,))
cr.execute('update '+_table+' set '+self._fields_id+'=%s where id in ('+','.join(map(str, act[2]))+')', (id,))
def search(self, cr, obj, args, name, value, offset=0, limit=None, uid=None, operator='like'):
return obj.pool.get(self._obj).name_search(cr, uid, value, self._domain, offset, limit)
@ -500,7 +502,7 @@ class many2many(_column):
FROM '+self._rel+' , '+obj._table+' \
WHERE '+self._rel+'.'+self._id1+' in ('+ids_s+') \
AND '+self._rel+'.'+self._id2+' = '+obj._table+'.id '+d1
+limit_str+' order by '+obj._table+'.'+obj._order+' offset %d',
+limit_str+' order by '+obj._table+'.'+obj._order+' offset %s',
d2+[offset])
for r in cr.fetchall():
res[r[1]].append(r[0])
@ -515,26 +517,26 @@ class many2many(_column):
for act in values:
if act[0] == 0:
idnew = obj.create(cr, user, act[2])
cr.execute('insert into '+self._rel+' ('+self._id1+','+self._id2+') values (%d,%d)', (id, idnew))
cr.execute('insert into '+self._rel+' ('+self._id1+','+self._id2+') values (%s,%s)', (id, idnew))
elif act[0] == 1:
obj.write(cr, user, [act[1]], act[2], context=context)
elif act[0] == 2:
obj.unlink(cr, user, [act[1]], context=context)
elif act[0] == 3:
cr.execute('delete from '+self._rel+' where ' + self._id1 + '=%d and '+ self._id2 + '=%d', (id, act[1]))
cr.execute('delete from '+self._rel+' where ' + self._id1 + '=%s and '+ self._id2 + '=%s', (id, act[1]))
elif act[0] == 4:
cr.execute('insert into '+self._rel+' ('+self._id1+','+self._id2+') values (%d,%d)', (id, act[1]))
cr.execute('insert into '+self._rel+' ('+self._id1+','+self._id2+') values (%s,%s)', (id, act[1]))
elif act[0] == 5:
cr.execute('update '+self._rel+' set '+self._id2+'=null where '+self._id2+'=%d', (id,))
cr.execute('update '+self._rel+' set '+self._id2+'=null where '+self._id2+'=%s', (id,))
elif act[0] == 6:
d1, d2 = obj.pool.get('ir.rule').domain_get(cr, user, obj._name)
if d1:
d1 = ' and ' + d1
cr.execute('delete from '+self._rel+' where '+self._id1+'=%d AND '+self._id2+' IN (SELECT '+self._rel+'.'+self._id2+' FROM '+self._rel+', '+obj._table+' WHERE '+self._rel+'.'+self._id1+'=%d AND '+self._rel+'.'+self._id2+' = '+obj._table+'.id '+ d1 +')', [id, id]+d2)
cr.execute('delete from '+self._rel+' where '+self._id1+'=%s AND '+self._id2+' IN (SELECT '+self._rel+'.'+self._id2+' FROM '+self._rel+', '+obj._table+' WHERE '+self._rel+'.'+self._id1+'=%s AND '+self._rel+'.'+self._id2+' = '+obj._table+'.id '+ d1 +')', [id, id]+d2)
for act_nbr in act[2]:
cr.execute('insert into '+self._rel+' ('+self._id1+','+self._id2+') values (%d, %d)', (id, act_nbr))
cr.execute('insert into '+self._rel+' ('+self._id1+','+self._id2+') values (%s, %s)', (id, act_nbr))
#
# TODO: use a name_search
@ -601,9 +603,9 @@ class function(_column):
self._classic_read = True
self._classic_write = True
if type == 'float':
self._symbol_c = '%f'
self._symbol_f = lambda x: __builtin__.float(x or 0.0)
self._symbol_set = (self._symbol_c, self._symbol_f)
self._symbol_c = float._symbol_c
self._symbol_f = float._symbol_f
self._symbol_set = float._symbol_set
def search(self, cr, uid, obj, name, args):
if not self._fnct_search:
@ -655,8 +657,33 @@ class related(function):
i -= 1
return [(self._arg[0], 'in', sarg)]
def _fnct_write(self,obj,cr, uid, ids,values, field_name, args, context=None):
raise 'Not Implemented Yet'
def _fnct_write(self,obj,cr, uid, ids, field_name, values, args, context=None):
print 'Related Write', obj._name
if values and field_name:
self._field_get2(cr, uid, obj, context)
relation = obj._name
res = {}
if type(ids) != type([]):
ids=[ids]
objlst = obj.browse(cr, uid, ids)
for data in objlst:
t_id=None
t_data = data
relation = obj._name
for i in range(len(self.arg)):
field_detail = self._relations[i]
relation = field_detail['object']
if not t_data[self.arg[i]]:
t_data = False
break
if field_detail['type'] in ('one2many', 'many2many'):
t_id=t_data.id
t_data = t_data[self.arg[i]][0]
else:
t_id=t_data['id']
t_data = t_data[self.arg[i]]
if t_id:
obj.pool.get(field_detail['object']).write(cr,uid,[t_id],{args[-1]:values})
def _fnct_read(self, obj, cr, uid, ids, field_name, args, context=None):
self._field_get2(cr, uid, obj, context)
@ -686,7 +713,7 @@ class related(function):
def __init__(self, *arg, **args):
self.arg = arg
self._relations = []
super(related, self).__init__(self._fnct_read, arg, fnct_inv_arg=arg, method=True, fnct_search=self._fnct_search, **args)
super(related, self).__init__(self._fnct_read, arg, self._fnct_write, fnct_inv_arg=arg, method=True, fnct_search=self._fnct_search, **args)
def _field_get2(self, cr, uid, obj, context={}):
if self._relations:
@ -728,7 +755,7 @@ class property(function):
nid = property.search(cr, uid, [('fields_id', '=', definition_id),
('res_id', '=', obj._name+','+str(id))])
while len(nid):
cr.execute('DELETE FROM ir_property WHERE id=%d', (nid.pop(),))
cr.execute('DELETE FROM ir_property WHERE id=%s', (nid.pop(),))
nid = property.search(cr, uid, [('fields_id', '=', definition_id),
('res_id', '=', False)])

View File

@ -349,7 +349,7 @@ class orm_template(object):
id, model_id, model, name, field_description, ttype,
relation,view_load,state,select_level
) VALUES (
%d,%s,%s,%s,%s,%s,%s,%s,%s,%s
%s,%s,%s,%s,%s,%s,%s,%s,%s,%s
)""", (
id, vals['model_id'], vals['model'], vals['name'], vals['field_description'], vals['ttype'],
vals['relation'], bool(vals['view_load']), 'base',
@ -732,7 +732,6 @@ class orm_template(object):
and getattr(self._columns[f], arg):
res[f][arg] = getattr(self._columns[f], arg)
# translate the field label
res_trans = translation_obj._get_source(cr, user,
self._name + ',' + f, 'field', context.get('lang', False) or 'en_US')
if res_trans:
@ -843,15 +842,15 @@ class orm_template(object):
# translate view
if ('lang' in context) and not result:
if node.hasAttribute('string') and node.getAttribute('string'):
trans = tools.translate(cr, self._name, 'view', context['lang'], node.getAttribute('string').encode('utf8'))
trans = self.pool.get('ir.translation')._get_source(cr, user, self._name, 'view', context['lang'], node.getAttribute('string').encode('utf8'))
if not trans and ('base_model_name' in context):
trans = tools.translate(cr, context['base_model_name'], 'view', context['lang'], node.getAttribute('string').encode('utf8'))
trans = self.pool.get('ir.translation')._get_source(cr, user, context['base_model_name'], 'view', context['lang'], node.getAttribute('string').encode('utf8'))
if trans:
node.setAttribute('string', trans.decode('utf8'))
node.setAttribute('string', trans)
if node.hasAttribute('sum') and node.getAttribute('sum'):
trans = tools.translate(cr, self._name, 'view', context['lang'], node.getAttribute('sum').encode('utf8'))
trans = self.pool.get('ir.translation')._get_source(cr, user, self._name, 'view', context['lang'], node.getAttribute('sum').encode('utf8'))
if trans:
node.setAttribute('sum', trans.decode('utf8'))
node.setAttribute('sum', trans)
if childs:
for f in node.childNodes:
@ -1004,7 +1003,7 @@ class orm_template(object):
while ok:
if view_id:
where = (model and (" and model='%s'" % (self._name,))) or ''
cr.execute('SELECT arch,name,field_parent,id,type,inherit_id FROM ir_ui_view WHERE id=%d'+where, (view_id,))
cr.execute('SELECT arch,name,field_parent,id,type,inherit_id FROM ir_ui_view WHERE id=%s'+where, (view_id,))
else:
cr.execute('''SELECT
arch,name,field_parent,id,type,inherit_id
@ -1030,7 +1029,7 @@ class orm_template(object):
def _inherit_apply_rec(result, inherit_id):
# get all views which inherit from (ie modify) this view
cr.execute('select arch,id from ir_ui_view where inherit_id=%d and model=%s order by priority', (inherit_id, self._name))
cr.execute('select arch,id from ir_ui_view where inherit_id=%s and model=%s order by priority', (inherit_id, self._name))
sql_inherit = cr.fetchall()
for (inherit, id) in sql_inherit:
result = _inherit_apply(result, inherit)
@ -1377,15 +1376,36 @@ class orm(orm_template):
childs = cr.fetchall()
for id in childs:
pos2 = browse_rec(id[0], pos2)
cr.execute('update '+self._table+' set parent_left=%d, parent_right=%d where id=%d', (pos,pos2,root))
cr.execute('update '+self._table+' set parent_left=%s, parent_right=%s where id=%s', (pos,pos2,root))
return pos2+1
browse_rec(None)
return True
def _update_store(self, cr, f, k):
logger = netsvc.Logger()
logger.notifyChannel('init', netsvc.LOG_INFO, "storing computed values of fields.function '%s'" % (k,))
ss = self._columns[k]._symbol_set
update_query = 'UPDATE "%s" SET "%s"=%s WHERE id=%%s' % (self._table, k, ss[0])
cr.execute('select id from '+self._table)
ids_lst = map(lambda x: x[0], cr.fetchall())
while ids_lst:
iids = ids_lst[:40]
ids_lst = ids_lst[40:]
res = f.get(cr, self, iids, k, 1, {})
for key,val in res.items():
if f._multi:
val = val[k]
# if val is a many2one, just write the ID
if type(val)==tuple:
val = val[0]
if (val<>False) or (type(val)<>bool):
cr.execute(update_query, (ss[1](val), key))
def _auto_init(self, cr, context={}):
store_compute = False
logger = netsvc.Logger()
create = False
todo_end = []
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)
@ -1405,8 +1425,8 @@ class orm(orm_template):
logger.notifyChannel('init', netsvc.LOG_ERROR, 'create a column parent_right on object %s: fields.integer(\'Right Parent\', select=1)' % (self._table, ))
if self._columns[self._parent_name].ondelete<>'cascade':
logger.notifyChannel('init', netsvc.LOG_ERROR, "the columns %s on object must be set as ondelete='cascasde'" % (self._name, self._parent_name))
cr.execute("ALTER TABLE \"%s\" ADD COLUMN \"%s\" INTEGER" % (self._table, 'parent_left'))
cr.execute("ALTER TABLE \"%s\" ADD COLUMN \"%s\" INTEGER" % (self._table, 'parent_right'))
cr.execute('ALTER TABLE "%s" ADD COLUMN "parent_left" INTEGER' % (self._table,))
cr.execute('ALTER TABLE "%s" ADD COLUMN "parent_right" INTEGER' % (self._table,))
cr.commit()
store_compute = True
@ -1418,15 +1438,13 @@ class orm(orm_template):
'write_date': 'TIMESTAMP'
}
for k in logs:
cr.execute(
"""
cr.execute("""
SELECT c.relname
FROM pg_class c, pg_attribute a
WHERE c.relname='%s' AND a.attname='%s' AND c.oid=a.attrelid
""" % (self._table, k))
FROM pg_class c, pg_attribute a
WHERE c.relname=%s AND a.attname=%s AND c.oid=a.attrelid
""", (self._table, k))
if not cr.rowcount:
cr.execute("ALTER TABLE \"%s\" ADD COLUMN \"%s\" %s" %
(self._table, k, logs[k]))
cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (self._table, k, logs[k]))
cr.commit()
# iterate on the database columns to drop the NOT NULL constraints
@ -1434,12 +1452,12 @@ class orm(orm_template):
cr.execute(
"SELECT a.attname, a.attnotnull "\
"FROM pg_class c, pg_attribute a "\
"WHERE c.oid=a.attrelid AND c.relname='%s'" % self._table)
"WHERE c.oid=a.attrelid AND c.relname=%s", (self._table,))
db_columns = cr.dictfetchall()
for column in db_columns:
if column['attname'] not in ('id', 'oid', 'tableoid', 'ctid', 'xmin', 'xmax', 'cmin', 'cmax'):
if column['attnotnull'] and column['attname'] not in self._columns:
cr.execute("ALTER TABLE \"%s\" ALTER COLUMN \"%s\" DROP NOT NULL" % (self._table, column['attname']))
cr.execute('ALTER TABLE "%s" ALTER COLUMN "%s" DROP NOT NULL' % (self._table, column['attname']))
# iterate on the "object columns"
todo_update_store = []
@ -1452,10 +1470,10 @@ class orm(orm_template):
if isinstance(f, fields.one2many):
cr.execute("SELECT relname FROM pg_class WHERE relkind='r' AND relname=%s", (f._obj,))
if cr.fetchone():
cr.execute("SELECT count(*) as c FROM pg_class c,pg_attribute a WHERE c.relname=%s AND a.attname=%s AND c.oid=a.attrelid", (f._obj, f._fields_id))
cr.execute("SELECT count(1) as c FROM pg_class c,pg_attribute a WHERE c.relname=%s AND a.attname=%s AND c.oid=a.attrelid", (f._obj, f._fields_id))
res = cr.fetchone()[0]
if not res:
cr.execute("ALTER TABLE \"%s\" ADD FOREIGN KEY (%s) REFERENCES \"%s\" ON DELETE SET NULL" % (self._obj, f._fields_id, f._table))
cr.execute('ALTER TABLE "%s" ADD FOREIGN KEY (%s) REFERENCES "%s" ON DELETE SET NULL' % (self._obj, f._fields_id, f._table))
elif isinstance(f, fields.many2many):
cr.execute("SELECT relname FROM pg_class WHERE relkind in ('r','v') AND relname=%s", (f._rel,))
if not cr.dictfetchall():
@ -1464,29 +1482,40 @@ class orm(orm_template):
ref = self.pool.get(f._obj)._table
except AttributeError:
ref = f._obj.replace('.', '_')
cr.execute("CREATE TABLE \"%s\" (\"%s\" INTEGER NOT NULL REFERENCES \"%s\" ON DELETE CASCADE, \"%s\" INTEGER NOT NULL REFERENCES \"%s\" ON DELETE CASCADE) WITH OIDS"%(f._rel, f._id1, self._table, f._id2, ref))
cr.execute("CREATE INDEX \"%s_%s_index\" ON \"%s\" (\"%s\")" % (f._rel, f._id1, f._rel, f._id1))
cr.execute("CREATE INDEX \"%s_%s_index\" ON \"%s\" (\"%s\")" % (f._rel, f._id2, f._rel, f._id2))
cr.execute('CREATE TABLE "%s" ("%s" INTEGER NOT NULL REFERENCES "%s" ON DELETE CASCADE, "%s" INTEGER NOT NULL REFERENCES "%s" ON DELETE CASCADE) WITH OIDS' % (f._rel, f._id1, self._table, f._id2, ref))
cr.execute('CREATE INDEX "%s_%s_index" ON "%s" ("%s")' % (f._rel, f._id1, f._rel, f._id1))
cr.execute('CREATE INDEX "%s_%s_index" ON "%s" ("%s")' % (f._rel, f._id2, f._rel, f._id2))
cr.commit()
else:
cr.execute("SELECT c.relname,a.attname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,t.typname,CASE WHEN a.attlen=-1 THEN a.atttypmod-4 ELSE a.attlen END as size FROM pg_class c,pg_attribute a,pg_type t WHERE c.relname=%s AND a.attname=%s AND c.oid=a.attrelid AND a.atttypid=t.oid", (self._table, k))
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]))
cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (self._table, k, get_pg_type(f)[1]))
# initialize it
if not create and k in self._defaults:
default = self._defaults[k](self, cr, 1, {})
if not default:
cr.execute("UPDATE \"%s\" SET \"%s\"=NULL" % (self._table, k))
else:
cr.execute("UPDATE \"%s\" SET \"%s\"='%s'" % (self._table, k, default))
ss = self._columns[k]._symbol_set
query = 'UPDATE "%s" SET "%s"=%s' % (self._table, k, ss[0])
cr.execute(query, (ss[1](default),))
cr.commit()
logger.notifyChannel('init', netsvc.LOG_DEBUG, 'setting default value of new column %s of table %s'% (k, self._table))
elif not create:
logger.notifyChannel('init', netsvc.LOG_DEBUG, 'creating new column %s of table %s'% (k, self._table))
if isinstance(f, fields.function):
todo_update_store.append((f,k))
order = 10
if f.store is not True:
order = f.store[f.store.keys()[0]][2]
todo_update_store.append((order, f,k))
# and add constraints if needed
if isinstance(f, fields.many2one):
@ -1497,14 +1526,14 @@ class orm(orm_template):
ref = f._obj.replace('.', '_')
# ir_actions is inherited so foreign key doesn't work on it
if ref != 'ir_actions':
cr.execute("ALTER TABLE \"%s\" ADD FOREIGN KEY (\"%s\") REFERENCES \"%s\" ON DELETE %s" % (self._table, k, ref, f.ondelete))
cr.execute('ALTER TABLE "%s" ADD FOREIGN KEY ("%s") REFERENCES "%s" ON DELETE %s' % (self._table, k, ref, f.ondelete))
if f.select:
cr.execute("CREATE INDEX \"%s_%s_index\" ON \"%s\" (\"%s\")" % (self._table, k, self._table, k))
cr.execute('CREATE INDEX "%s_%s_index" ON "%s" ("%s")' % (self._table, k, self._table, k))
if f.required:
cr.commit()
try:
cr.execute("ALTER TABLE \"%s\" ALTER COLUMN \"%s\" SET NOT NULL" % (self._table, k))
except:
cr.commit()
cr.execute('ALTER TABLE "%s" ALTER COLUMN "%s" SET NOT NULL' % (self._table, k))
except Exception, e:
logger.notifyChannel('init', netsvc.LOG_WARNING, 'WARNING: unable to set column %s of table %s not null !\nTry to re-run: openerp-server.py --update=module\nIf it doesn\'t work, update records and execute manually:\nALTER TABLE %s ALTER COLUMN %s SET NOT NULL' % (k, self._table, self._table, k))
cr.commit()
elif len(res)==1:
@ -1513,78 +1542,89 @@ class orm(orm_template):
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))
logger.notifyChannel('init', netsvc.LOG_INFO, 'column %s (%s) in table %s removed: converted to a function !\n' % (k, f.string, self._table))
cr.execute('ALTER TABLE %s DROP COLUMN %s'% (self._table, k))
cr.commit()
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))
ok = False
casts = [
('text', 'char', 'VARCHAR(%d)' % (f.size or 0,), '::VARCHAR(%d)'%(f.size or 0,)),
('varchar', 'text', 'TEXT', ''),
('int4', 'float', get_pg_type(f)[1], '::'+get_pg_type(f)[1]),
('date', 'datetime', 'TIMESTAMP', '::TIMESTAMP'),
]
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), DB size will be kept !" % (k, self._table, f_pg_size, f.size))
# If actual DB size is < than new
# We update varchar size, otherwise, we keep DB size
# to avoid truncated string...
if f_pg_size < f.size:
cr.execute("ALTER TABLE \"%s\" RENAME COLUMN \"%s\" TO temp_change_size" % (self._table, k))
cr.execute("ALTER TABLE \"%s\" ADD COLUMN \"%s\" VARCHAR(%d)" % (self._table, k, f.size))
cr.execute("UPDATE \"%s\" SET \"%s\"=temp_change_size::VARCHAR(%d)" % (self._table, k, f.size))
cr.execute("ALTER TABLE \"%s\" DROP COLUMN temp_change_size" % (self._table,))
cr.commit()
if f_pg_type == 'date' and f._type == 'datetime':
cr.execute("ALTER TABLE \"%s\" RENAME COLUMN \"%s\" TO temp_change_type" % (self._table, k))
cr.execute("ALTER TABLE \"%s\" ADD COLUMN \"%s\" TIMESTAMP " % (self._table, k))
cr.execute("UPDATE \"%s\" SET \"%s\"=temp_change_type::TIMESTAMP" % (self._table, k))
cr.execute("ALTER TABLE \"%s\" DROP COLUMN temp_change_type" % (self._table,))
cr.commit()
logger.notifyChannel('init', netsvc.LOG_INFO, "column '%s' in table '%s' changed size" % (k, self._table))
cr.execute('ALTER TABLE "%s" RENAME COLUMN "%s" TO temp_change_size' % (self._table, k))
cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" VARCHAR(%d)' % (self._table, k, f.size))
cr.execute('UPDATE "%s" SET "%s"=temp_change_size::VARCHAR(%d)' % (self._table, k, f.size))
cr.execute('ALTER TABLE "%s" DROP COLUMN temp_change_size' % (self._table,))
cr.commit()
for c in casts:
if (f_pg_type==c[0]) and (f._type==c[1]):
logger.notifyChannel('init', netsvc.LOG_INFO, "column '%s' in table '%s' changed type to %s." % (k, self._table, c[1]))
ok = True
cr.execute('ALTER TABLE "%s" RENAME COLUMN "%s" TO temp_change_size' % (self._table, k))
cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (self._table, k, c[2]))
cr.execute(('UPDATE "%s" SET "%s"=temp_change_size'+c[3]) % (self._table, k))
cr.execute('ALTER TABLE "%s" DROP COLUMN temp_change_size CASCADE' % (self._table,))
cr.commit()
if f_pg_type != f_obj_type:
if not ok:
logger.notifyChannel('init', netsvc.LOG_WARNING, "column '%s' in table '%s' has changed type (DB = %s, def = %s) but unable to migrate this change !" % (k, self._table, f_pg_type, f._type))
# if the field is required and hasn't got a NOT NULL constraint
if f.required and f_pg_notnull == 0:
# set the field to the default value if any
if k in self._defaults:
default = self._defaults[k](self, cr, 1, {})
if not (default is False):
cr.execute("UPDATE \"%s\" SET \"%s\"='%s' WHERE %s is NULL" % (self._table, k, default, k))
cr.commit()
if (default is not None):
ss = self._columns[k]._symbol_set
query = 'UPDATE "%s" SET "%s"=%s WHERE %s is NULL' % (self._table, k, ss[0], k)
cr.execute(query, (ss[1](default),))
# add the NOT NULL constraint
cr.commit()
try:
cr.execute("ALTER TABLE \"%s\" ALTER COLUMN \"%s\" SET NOT NULL" % (self._table, k))
cr.execute('ALTER TABLE "%s" ALTER COLUMN "%s" SET NOT NULL' % (self._table, k))
cr.commit()
except:
except Exception, e:
logger.notifyChannel('init', netsvc.LOG_WARNING, 'unable to set a NOT NULL constraint on column %s of the %s table !\nIf you want to have it, you should update the records and execute manually:\nALTER TABLE %s ALTER COLUMN %s SET NOT NULL' % (k, self._table, self._table, k))
cr.commit()
elif not f.required and f_pg_notnull == 1:
cr.execute("ALTER TABLE \"%s\" ALTER COLUMN \"%s\" DROP NOT NULL" % (self._table, k))
cr.execute('ALTER TABLE "%s" ALTER COLUMN "%s" DROP NOT NULL' % (self._table, k))
cr.commit()
cr.execute("SELECT indexname FROM pg_indexes WHERE indexname = '%s_%s_index' and tablename = '%s'" % (self._table, k, self._table))
indexname = '%s_%s_index' % (self._table, k)
cr.execute("SELECT indexname FROM pg_indexes WHERE indexname = %s and tablename = %s", (indexname, self._table))
res = cr.dictfetchall()
if not res and f.select:
cr.execute("CREATE INDEX \"%s_%s_index\" ON \"%s\" (\"%s\")" % (self._table, k, self._table, k))
cr.execute('CREATE INDEX "%s_%s_index" ON "%s" ("%s")' % (self._table, k, self._table, k))
cr.commit()
if res and not f.select:
cr.execute("DROP INDEX \"%s_%s_index\"" % (self._table, k))
cr.execute('DROP INDEX "%s_%s_index"' % (self._table, k))
cr.commit()
if isinstance(f, fields.many2one):
ref = self.pool.get(f._obj)._table
if ref != 'ir_actions':
cr.execute('SELECT confdeltype, conname FROM pg_constraint as con, pg_class as cl1, pg_class as cl2, ' \
'pg_attribute as att1, pg_attribute as att2 ' \
'WHERE con.conrelid = cl1.oid ' \
'AND cl1.relname = %s ' \
'AND con.confrelid = cl2.oid ' \
'AND cl2.relname = %s ' \
'AND array_lower(con.conkey, 1) = 1 ' \
'AND con.conkey[1] = att1.attnum ' \
'AND att1.attrelid = cl1.oid ' \
'AND att1.attname = %s ' \
'AND array_lower(con.confkey, 1) = 1 ' \
'AND con.confkey[1] = att2.attnum ' \
'AND att2.attrelid = cl2.oid ' \
'AND att2.attname = %s ' \
'AND con.contype = \'f\'', (self._table, ref, k, 'id'))
cr.execute('SELECT confdeltype, conname FROM pg_constraint as con, pg_class as cl1, pg_class as cl2, '
'pg_attribute as att1, pg_attribute as att2 '
'WHERE con.conrelid = cl1.oid '
'AND cl1.relname = %s '
'AND con.confrelid = cl2.oid '
'AND cl2.relname = %s '
'AND array_lower(con.conkey, 1) = 1 '
'AND con.conkey[1] = att1.attnum '
'AND att1.attrelid = cl1.oid '
'AND att1.attname = %s '
'AND array_lower(con.confkey, 1) = 1 '
'AND con.confkey[1] = att2.attnum '
'AND att2.attrelid = cl2.oid '
'AND att2.attname = %s '
"AND con.contype = 'f'", (self._table, ref, k, 'id'))
res = cr.dictfetchall()
if res:
confdeltype = {
@ -1599,31 +1639,21 @@ class orm(orm_template):
cr.execute('ALTER TABLE "' + self._table + '" ADD FOREIGN KEY ("' + k + '") REFERENCES "' + ref + '" ON DELETE ' + f.ondelete)
cr.commit()
else:
print "ERROR"
for f,k in todo_update_store:
cr.execute('select id from '+self._table)
ids_lst = map(lambda x: x[0], cr.fetchall())
while ids_lst:
iids = ids_lst[:40]
ids_lst = ids_lst[40:]
res = f.get(cr, self, iids, k, 1, {})
for key,val in res.items():
if f._multi:
val = val[k]
if (val<>False) or (type(val)<>bool):
cr.execute("UPDATE \"%s\" SET \"%s\"='%s' where id=%d"% (self._table, k, val, key))
#else:
# cr.execute("UPDATE \"%s\" SET \"%s\"=NULL where id=%d"% (self._table, k, key))
logger = netsvc.Logger()
logger.notifyChannel('orm', netsvc.LOG_ERROR, "Programming error !")
for order,f,k in todo_update_store:
todo_end.append((order, self._update_store, (f, k)))
else:
cr.execute("SELECT relname FROM pg_class WHERE relkind in ('r','v') AND relname='%s'" % self._table)
cr.execute("SELECT relname FROM pg_class WHERE relkind in ('r','v') AND relname=%s", (self._table,))
create = not bool(cr.fetchone())
for (key, con, _) in self._sql_constraints:
cr.execute("SELECT conname FROM pg_constraint where conname='%s_%s'" % (self._table, key))
conname = '%s_%s' % (self._table, key)
cr.execute("SELECT conname FROM pg_constraint where conname=%s", (conname,))
if not cr.dictfetchall():
try:
cr.execute('alter table \"%s\" add constraint \"%s_%s\" %s' % (self._table, self._table, key, con,))
cr.execute('alter table "%s" add constraint "%s_%s" %s' % (self._table, self._table, key, con,))
cr.commit()
except:
logger.notifyChannel('init', netsvc.LOG_WARNING, 'unable to add \'%s\' constraint on table %s !\n If you want to have it, you should update the records and execute manually:\nALTER table %s ADD CONSTRAINT %s_%s %s' % (con, self._table, self._table, self._table, key, con,))
@ -1637,6 +1667,7 @@ class orm(orm_template):
cr.commit()
if store_compute:
self._parent_store_compute(cr)
return todo_end
def __init__(self, cr):
super(orm, self).__init__(cr)
@ -1648,18 +1679,15 @@ class orm(orm_template):
if not f.store:
continue
if self._columns[store_field].store is True:
sm = {self._name:(lambda self,cr, uid, ids, c={}: ids, None)}
sm = {self._name:(lambda self,cr, uid, ids, c={}: ids, None, 10)}
else:
sm = self._columns[store_field].store
for object, aa in sm.items():
if len(aa)==2:
(fnct,fields2)=aa
order = 1
elif len(aa)==3:
if len(aa)==3:
(fnct,fields2,order)=aa
else:
raise except_orm(_('Error'),
_('Invalid function definition %s in object %s !' % (store_field, self._name)))
raise except_orm('Error',
('Invalid function definition %s in object %s !\nYou must use the definition: store={object:(fnct, fields, priority)}.' % (store_field, self._name)))
self.pool._store_function.setdefault(object, [])
ok = True
for x,y,z,e,f in self.pool._store_function[object]:
@ -1780,7 +1808,6 @@ class orm(orm_template):
value[key[8:]] = context[key]
return value
#
# Update objects that uses this one to update their _inherits fields
#
@ -1845,7 +1872,6 @@ class orm(orm_template):
if isinstance(self._columns[f], fields.binary) and context.get('bin_size', False):
return "length(%s) as %s" % (f,f)
return '"%s"' % (f,)
#fields_pre2 = map(lambda x: (x in ('create_date', 'write_date')) and ('date_trunc(\'second\', '+x+') as '+x) or '"'+x+'"', fields_pre)
fields_pre2 = map(convert_field, fields_pre)
for i in range(0, len(ids), cr.IN_MAX):
sub_ids = ids[i:i+cr.IN_MAX]
@ -1897,7 +1923,7 @@ class orm(orm_template):
# to get the _symbol_get in each occurence
for r in res:
for f in fields_post:
r[f] = self.columns[f]._symbol_get(r[f])
r[f] = self._columns[f]._symbol_get(r[f])
ids = map(lambda x: x['id'], res)
# all non inherited fields for which the attribute whose name is in load is False
@ -1995,12 +2021,7 @@ class orm(orm_template):
if isinstance(ids, (int, long)):
ids = [ids]
fn_list = []
for fnct in self.pool._store_function.get(self._name, []):
ids2 = filter(None, fnct[2](self,cr, uid, ids, context))
if ids2:
fn_list.append( (fnct[0], fnct[1], ids2) )
result_store = self._store_get_values(cr, uid, ids, None, context)
delta = context.get('read_delta', False)
if delta and self._log_access:
for i in range(0, len(ids), cr.IN_MAX):
@ -2031,7 +2052,7 @@ class orm(orm_template):
for i in range(0, len(ids), cr.IN_MAX):
sub_ids = ids[i:i+cr.IN_MAX]
str_d = string.join(('%d',)*len(sub_ids), ',')
str_d = string.join(('%s',)*len(sub_ids), ',')
if d1:
cr.execute('SELECT id FROM "'+self._table+'" ' \
'WHERE id IN ('+str_d+')'+d1, sub_ids+d2)
@ -2047,10 +2068,8 @@ class orm(orm_template):
cr.execute('delete from "'+self._table+'" ' \
'where id in ('+str_d+')', sub_ids)
for object,field,ids in fn_list:
ids = self.pool.get(object).search(cr, uid, [('id','in', ids)], context=context)
if ids:
self.pool.get(object)._store_set_values(cr, uid, ids, field, context)
for order, object, ids, fields in result_store:
self.pool.get(object)._store_set_values(cr, uid, ids, fields, context)
return True
#
@ -2148,7 +2167,7 @@ class orm(orm_template):
% (vals[field], field))
if self._log_access:
upd0.append('write_uid=%d')
upd0.append('write_uid=%s')
upd0.append('write_date=now()')
upd1.append(user)
@ -2214,14 +2233,14 @@ class orm(orm_template):
if self.pool._init:
self.pool._init_parent[self._name]=True
else:
cr.execute('select parent_left,parent_right from '+self._table+' where id=%d', (vals[self._parent_name],))
cr.execute('select parent_left,parent_right from '+self._table+' where id=%s', (vals[self._parent_name],))
res = cr.fetchone()
if res:
pleft,pright = res
else:
cr.execute('select max(parent_right),max(parent_right)+1 from '+self._table)
pleft,pright = cr.fetchone()
cr.execute('select parent_left,parent_right,id from '+self._table+' where id in ('+','.join(map(lambda x:'%d',ids))+')', ids)
cr.execute('select parent_left,parent_right,id from '+self._table+' where id in ('+','.join(map(lambda x:'%s',ids))+')', ids)
dest = pleft + 1
for cleft,cright,cid in cr.fetchall():
if cleft > pleft:
@ -2241,37 +2260,31 @@ class orm(orm_template):
cr.execute('UPDATE '+self._table+'''
SET
parent_left = CASE
WHEN parent_left BETWEEN %d AND %d THEN parent_left + %d
WHEN parent_left BETWEEN %d AND %d THEN parent_left + %d
WHEN parent_left BETWEEN %s AND %s THEN parent_left + %s
WHEN parent_left BETWEEN %s AND %s THEN parent_left + %s
ELSE parent_left
END,
parent_right = CASE
WHEN parent_right BETWEEN %d AND %d THEN parent_right + %d
WHEN parent_right BETWEEN %d AND %d THEN parent_right + %d
WHEN parent_right BETWEEN %s AND %s THEN parent_right + %s
WHEN parent_right BETWEEN %s AND %s THEN parent_right + %s
ELSE parent_right
END
WHERE
parent_left<%d OR parent_right>%d;
parent_left<%s OR parent_right>%s;
''', (leftbound,rightbound,cwidth,cleft,cright,treeshift,leftbound,rightbound,
cwidth,cleft,cright,treeshift,leftrange,rightrange))
if 'read_delta' in context:
del context['read_delta']
result = self._store_get_values(cr, user, ids, vals.keys(), context)
for order, object, ids, fields in result:
self.pool.get(object)._store_set_values(cr, user, ids, fields, context)
wf_service = netsvc.LocalService("workflow")
for id in ids:
wf_service.trg_write(user, self._name, id, cr)
for fnct in self.pool._store_function.get(self._name, []):
ok = False
for key in vals.keys():
if (not fnct[3]) or (key in fnct[3]):
ok = True
if ok:
ids2 = fnct[2](self,cr, user, ids, context)
ids2 = filter(None, ids2)
if ids2:
self.pool.get(fnct[0])._store_set_values(cr, user, ids2, fnct[1], context)
return True
#
@ -2322,7 +2335,7 @@ class orm(orm_template):
for table in tocreate:
id = self.pool.get(table).create(cr, user, tocreate[table])
upd0 += ','+self._inherits[table]
upd1 += ',%d'
upd1 += ',%s'
upd2.append(id)
for field in vals:
@ -2352,7 +2365,7 @@ class orm(orm_template):
% (vals[field], field))
if self._log_access:
upd0 += ',create_uid,create_date'
upd1 += ',%d,now()'
upd1 += ',%s,now()'
upd2.append(user)
cr.execute('insert into "'+self._table+'" (id'+upd0+") values ("+str(id_new)+upd1+')', tuple(upd2))
upd_todo.sort(lambda x, y: self._columns[x].priority-self._columns[y].priority)
@ -2367,43 +2380,83 @@ class orm(orm_template):
else:
parent = vals.get(self._parent_name, False)
if parent:
cr.execute('select parent_left from '+self._table+' where id=%d', (parent,))
cr.execute('select parent_left from '+self._table+' where id=%s', (parent,))
pleft = cr.fetchone()[0]
else:
cr.execute('select max(parent_right) from '+self._table)
pleft = cr.fetchone()[0] or 0
cr.execute('update '+self._table+' set parent_left=parent_left+2 where parent_left>%d', (pleft,))
cr.execute('update '+self._table+' set parent_right=parent_right+2 where parent_right>%d', (pleft,))
cr.execute('update '+self._table+' set parent_left=%d,parent_right=%d where id=%d', (pleft+1,pleft+2,id_new))
cr.execute('update '+self._table+' set parent_left=parent_left+2 where parent_left>%s', (pleft,))
cr.execute('update '+self._table+' set parent_right=parent_right+2 where parent_right>%s', (pleft,))
cr.execute('update '+self._table+' set parent_left=%s,parent_right=%s where id=%s', (pleft+1,pleft+2,id_new))
result = self._store_get_values(cr, user, [id_new], vals.keys(), context)
for order, object, ids, fields in result:
self.pool.get(object)._store_set_values(cr, user, ids, fields, context)
wf_service = netsvc.LocalService("workflow")
wf_service.trg_create(user, self._name, id_new, cr)
for fnct in self.pool._store_function.get(self._name, []):
ids2 = fnct[2](self,cr, user, [id_new], context)
ids2 = filter(None, ids2)
if ids2:
self.pool.get(fnct[0])._store_set_values(cr, user, ids2, fnct[1], context)
return id_new
def _store_set_values(self, cr, uid, ids, field, context):
args = {}
result = self._columns[field].get(cr, self, ids, field, uid, context=context)
for id,value in result.items():
upd0 = []
upd1 = []
if self._columns[field]._multi:
value = value[field]
if self._columns[field]._type in ('many2one', 'one2one'):
try:
value = value[0]
except:
pass
upd0.append('"'+field+'"='+self._columns[field]._symbol_set[0])
upd1.append(self._columns[field]._symbol_set[1](value))
upd1.append(id)
cr.execute('update "' + self._table + '" set ' + \
string.join(upd0, ',') + ' where id = %d', upd1)
def _store_get_values(self, cr, uid, ids, fields, context):
result = {}
fncts = self.pool._store_function.get(self._name, [])
for fnct in range(len(fncts)):
result.setdefault(fncts[fnct][0], {})
ids2 = fncts[fnct][2](self,cr, uid, ids, context)
for id in filter(None, ids2):
result[fncts[fnct][0]].setdefault(id, [])
result[fncts[fnct][0]][id].append(fnct)
result2 = []
for object in result:
k2 = {}
for id,fnct in result[object].items():
k2.setdefault(tuple(fnct), [])
k2[tuple(fnct)].append(id)
for fnct,id in k2.items():
result2.append((fncts[fnct[0]][4],object,id,map(lambda x: fncts[x][1], fnct)))
result2.sort()
return result2
def _store_set_values(self, cr, uid, ids, fields, context):
todo = {}
keys = []
for f in fields:
if self._columns[f]._multi not in keys:
keys.append(self._columns[f]._multi)
todo.setdefault(self._columns[f]._multi, [])
todo[self._columns[f]._multi].append(f)
for key in keys:
val = todo[key]
if key:
result = self._columns[val[0]].get(cr, self, ids, val, uid, context=context)
for id,value in result.items():
upd0 = []
upd1 = []
for v in value:
if v not in val:
continue
if self._columns[v]._type in ('many2one', 'one2one'):
try:
value[v] = value[v][0]
except:
pass
upd0.append('"'+v+'"='+self._columns[v]._symbol_set[0])
upd1.append(self._columns[v]._symbol_set[1](value[v]))
upd1.append(id)
cr.execute('update "' + self._table + '" set ' + \
string.join(upd0, ',') + ' where id = %s', upd1)
else:
for f in val:
result = self._columns[f].get(cr, self, ids, f, uid, context=context)
for id,value in result.items():
if self._columns[f]._type in ('many2one', 'one2one'):
try:
value = value[0]
except:
pass
cr.execute('update "' + self._table + '" set ' + \
'"'+f+'"='+self._columns[f]._symbol_set[0] + ' where id = %s', (self._columns[f]._symbol_set[1](value),id))
return True
#
@ -2501,7 +2554,7 @@ class orm(orm_template):
return []
if isinstance(ids, (int, long)):
ids = [ids]
return [(r['id'], str(r[self._rec_name])) for r in self.read(cr, user, ids,
return [(r['id'], tools.ustr(r[self._rec_name])) for r in self.read(cr, user, ids,
[self._rec_name], context, load='_classic_write')]
def name_search(self, cr, user, name='', args=None, operator='ilike', context=None, limit=None):

View File

@ -30,7 +30,7 @@ import pooler
import copy
import sys
import psycopg
from psycopg2 import IntegrityError
from netsvc import Logger, LOG_ERROR
from tools.misc import UpdateableDict
@ -87,7 +87,7 @@ class osv_pool(netsvc.Service):
self.abortResponse(1, inst.name, 'warning', inst.value)
except except_osv, inst:
self.abortResponse(1, inst.name, inst.exc_type, inst.value)
except psycopg.IntegrityError, inst:
except IntegrityError, inst:
for key in self._sql_error.keys():
if key in inst[0]:
self.abortResponse(1, 'Constraint Error', 'warning', self._sql_error[key])
@ -96,8 +96,7 @@ class osv_pool(netsvc.Service):
import traceback
tb_s = reduce(lambda x, y: x+y, traceback.format_exception( sys.exc_type, sys.exc_value, sys.exc_traceback))
logger = Logger()
for idx, s in enumerate(tb_s.split('\n')):
logger.notifyChannel("web-services", LOG_ERROR, '[%2d]: %s' % (idx, s,))
logger.notifyChannel('web-services', LOG_ERROR, tb_s)
raise
def execute(self, db, uid, obj, method, *args, **kw):
@ -185,7 +184,7 @@ class osv_memory(orm.orm_memory):
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 !'
raise 'Inherit not supported in osv_memory object !'
obj = object.__new__(cls)
obj.__init__(pool, cr)
return obj
@ -252,122 +251,3 @@ class osv(orm.orm):
self.pool = pool
orm.orm.__init__(self, cr)
class Cacheable(object):
_cache = UpdateableDict()
def add(self, key, value):
self._cache[key] = value
def invalidate(self, key):
del self._cache[key]
def get(self, key):
try:
w = self._cache[key]
return w
except KeyError:
return None
def clear(self):
self._cache.clear()
self._items = []
def filter_dict(d, fields):
res = {}
for f in fields + ['id']:
if f in d:
res[f] = d[f]
return res
class cacheable_osv(osv, Cacheable):
_relevant = ['lang']
def __init__(self):
super(cacheable_osv, self).__init__()
def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'):
if not fields:
fields = []
if not context:
context = {}
fields = fields or self._columns.keys()
ctx = [context.get(x, False) for x in self._relevant]
result, tofetch = [], []
for id in ids:
res = self.get(self._name, id, ctx)
if not res:
tofetch.append(id)
else:
result.append(filter_dict(res, fields))
# gen the list of "local" (ie not inherited) fields which are classic or many2one
nfields = filter(lambda x: x[1]._classic_write, self._columns.items())
# gen the list of inherited fields
inherits = map(lambda x: (x[0], x[1][2]), self._inherit_fields.items())
# complete the field list with the inherited fields which are classic or many2one
nfields += filter(lambda x: x[1]._classic_write, inherits)
nfields = [x[0] for x in nfields]
res = super(cacheable_osv, self).read(cr, user, tofetch, nfields, context, load)
for r in res:
self.add((self._name, r['id'], ctx), r)
result.append(filter_dict(r, fields))
# Appel de fonction si necessaire
tofetch = []
for f in fields:
if f not in nfields:
tofetch.append(f)
for f in tofetch:
fvals = self._columns[f].get(cr, self, ids, f, user, context=context)
for r in result:
r[f] = fvals[r['id']]
# TODO: tri par self._order !!
return result
def invalidate(self, key):
del self._cache[key[0]][key[1]]
def write(self, cr, user, ids, values, context=None):
if not context:
context = {}
for id in ids:
self.invalidate((self._name, id))
return super(cacheable_osv, self).write(cr, user, ids, values, context)
def unlink(self, cr, user, ids):
self.clear()
return super(cacheable_osv, self).unlink(cr, user, ids)
#cacheable_osv = osv
#class FakePool(object):
# def __init__(self, module):
# self.preferred_module = module
# def get(self, name):
# localpool = module_objects_dict.get(self.preferred_module, {'dict': {}})['dict']
# if name in localpool:
# obj = localpool[name]
# else:
# obj = pooler.get_pool(cr.dbname).get(name)
# return obj
# fake_pool = self
# class fake_class(obj.__class__):
# def __init__(self):
# super(fake_class, self).__init__()
# self.pool = fake_pool
# return fake_class()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -20,30 +20,19 @@
#
##############################################################################
import sql_db
import osv.osv
import tools
import addons
import netsvc
db_dic = {}
pool_dic = {}
def get_db_and_pool(db_name, force_demo=False, status=None, update_module=False):
if not status:
status={}
if db_name in db_dic:
db = db_dic[db_name]
else:
logger = netsvc.Logger()
logger.notifyChannel('pooler', netsvc.LOG_INFO, 'Connecting to %s' % (db_name.lower()))
db = sql_db.db_connect(db_name)
db_dic[db_name] = db
db = get_db_only(db_name)
if db_name in pool_dic:
pool = pool_dic[db_name]
else:
import addons
import osv.osv
pool = osv.osv.osv_pool()
pool_dic[db_name] = pool
addons.load_modules(db, force_demo, status, update_module)
@ -60,49 +49,28 @@ def get_db_and_pool(db_name, force_demo=False, status=None, update_module=False)
def restart_pool(db_name, force_demo=False, update_module=False):
# del db_dic[db_name]
del pool_dic[db_name]
return get_db_and_pool(db_name, force_demo, update_module=update_module)
def close_db(db_name):
if db_name in db_dic:
db_dic[db_name].truedb.close()
del db_dic[db_name]
if db_name in pool_dic:
del pool_dic[db_name]
def get_db_only(db_name):
if db_name in db_dic:
db = db_dic[db_name]
else:
db = sql_db.db_connect(db_name)
db_dic[db_name] = db
# ATTENTION:
# do not put this import outside this function
# sql_db must not be loaded before the logger is initialized.
# sql_db import psycopg2.tool which create a default logger if there is not.
# this resulting of having the logs outputed twice...
import sql_db
db = sql_db.db_connect(db_name)
return db
def get_db(db_name):
# print "get_db", db_name
return get_db_and_pool(db_name)[0]
def get_pool(db_name, force_demo=False, status=None, update_module=False):
# print "get_pool", db_name
pool = get_db_and_pool(db_name, force_demo, status, update_module)[1]
# addons.load_modules(db_name, False)
# if not pool.obj_list():
# pool.instanciate()
# print "pool", pool
return pool
# return get_db_and_pool(db_name)[1]
def init():
global db
# db = get_db_only(tools.config['db_name'])
sql_db.init()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -77,29 +77,22 @@ class report_rml(report_int):
self.xsl = xsl
self.bin_datas = {}
self.generators = {
'pdf': self.create_pdf,
'html': self.create_html,
'raw': self.create_raw,
'sxw': self.create_sxw,
'pdf': self.create_pdf,
'html': self.create_html,
'raw': self.create_raw,
'sxw': self.create_sxw,
'txt': self.create_txt,
}
}
def create(self, cr, uid, ids, datas, context):
xml = self.create_xml(cr, uid, ids, datas, context)
#file('/tmp/terp.xml','wb+').write(xml)
if datas.get('report_type', 'pdf') == 'raw':
return xml
rml = self.create_rml(cr, xml, uid, context)
#file('/tmp/terp.rml','wb+').write(rml)
pool = pooler.get_pool(cr.dbname)
ir_actions_report_xml_obj = pool.get('ir.actions.report.xml')
try:
report_xml_ids = ir_actions_report_xml_obj.search(cr, uid,
[('report_name', '=', self.name[7:])], context=context)
self.title = ir_actions_report_xml_obj.browse(cr,uid,report_xml_ids)[0].name
except:
print 'Report not Found !'
self.title = 'Unknown'
report_xml_ids = ir_actions_report_xml_obj.search(cr, uid, [('report_name', '=', self.name[7:])], context=context)
self.title = report_xml_ids and ir_actions_report_xml_obj.browse(cr,uid,report_xml_ids)[0].name or 'OpenERP Report'
report_type = datas.get('report_type', 'pdf')
create_doc = self.generators[report_type]
pdf = create_doc(rml, title=self.title)

View File

@ -78,17 +78,13 @@ class document(object):
fields = field_path.split('.')
if not len(fields):
print "WARNING: field name is empty!"
return ''
value = browser
for f in fields:
if isinstance(value, list):
if len(value)==0:
print "WARNING: empty list found!"
return ''
# elif len(value)>1:
# print "WARNING:", len(value), "possibilities for", value[0]._table_name , "picking first..."
value = value[0]
if isinstance(value, browse_null):
return ''
@ -128,12 +124,6 @@ class document(object):
# parent = the parent node in the xml data tree we are creating
if node.nodeType == node.ELEMENT_NODE:
# print '-'*60
# print "parse_node", node
# print "parent: ", parent
# print "ids:", ids
# print "model:", model
# print "datas:", datas
# convert the attributes of the node to a dictionary
@ -203,9 +193,6 @@ class document(object):
el.appendChild(el_txt)
elif attrs['type']=='eval':
#TODO: faire ca plus proprement
if isinstance(browser, list):
print "ERROR: EVAL!"
el = self.doc.createElement(node.localName)
parent.appendChild(el)
value = self.eval(browser, attrs['expr'])
@ -270,8 +257,6 @@ class document(object):
parent.appendChild(el)
atr = self.node_attrs_get(node)
if 'value' in atr:
#print "type=>",type(datas[atr['value']])
#print "value=>",datas[atr['value']]
if not isinstance(datas[atr['value']], (str, unicode)):
txt = self.doc.createTextNode(str(datas[atr['value']]))
else:

View File

@ -36,6 +36,7 @@ import copy
import StringIO
import zipfile
import os
import mx.DateTime
DT_FORMAT = '%Y-%m-%d'
DHM_FORMAT = '%Y-%m-%d %H:%M:%S'
@ -255,6 +256,7 @@ class rml_parse(object):
'format': self.format,
'formatLang': self.formatLang,
'logo' : user.company_id.logo,
'lang' : user.company_id.partner_id.lang,
}
self.localcontext.update(context)
self.rml_header = user.company_id.rml_header
@ -333,31 +335,61 @@ class rml_parse(object):
else:
obj._cache[table][id] = {'id': id}
def formatLang(self, value, digit=2, date=False):
def formatLang(self, value, digits=2, date=False,date_time=False, grouping=True, monetary=False, currency=None):
if not value:
return ''
lc, encoding = locale.getdefaultlocale()
if not encoding:
encoding = 'UTF-8'
if encoding == 'utf':
encoding = 'UTF-8'
if encoding == 'cp1252':
encoding= '1252'
pool_lang=self.pool.get('res.lang')
lang = self.localcontext.get('lang', 'en_US') or 'en_US'
try:
if os.name == 'nt':
locale.setlocale(locale.LC_ALL, _LOCALE2WIN32.get(lang, lang) + '.' + encoding)
lang_obj = pool_lang.browse(self.cr,self.uid,pool_lang.search(self.cr,self.uid,[('code','=',lang)])[0])
if date or date_time:
date_format = lang_obj.date_format
if date_time:
date_format = lang_obj.date_format + " " + lang_obj.time_format
if not isinstance(value, time.struct_time):
# assume string, parse it
if len(str(value)) == 10:
# length of date like 2001-01-01 is ten
# assume format '%Y-%m-%d'
date = mx.DateTime.strptime(str(value),DT_FORMAT)
else:
# assume format '%Y-%m-%d %H:%M:%S'
value = str(value)[:19]
date = mx.DateTime.strptime(str(value),DHM_FORMAT)
else:
locale.setlocale(locale.LC_ALL, lang + '.' + encoding)
except Exception:
netsvc.Logger().notifyChannel('report', netsvc.LOG_WARNING,
'report %s: unable to set locale "%s"' % (self.name,
self.localcontext.get('lang', 'en_US') or 'en_US'))
if date:
date = time.strptime(value, DT_FORMAT)
return time.strftime(locale.nl_langinfo(locale.D_FMT).replace('%y', '%Y'),
date)
return locale.format('%.' + str(digit) + 'f', value, True)
date = mx.DateTime.DateTime(*(value.timetuple()[:6]))
return date.strftime(date_format)
return lang_obj.format('%.' + str(digits) + 'f', value, grouping=grouping, monetary=monetary)
# def formatLang(self, value, digit=2, date=False):
# if not value:
# return ''
# lc, encoding = locale.getdefaultlocale()
# if not encoding:
# encoding = 'UTF-8'
# if encoding == 'utf':
# encoding = 'UTF-8'
# if encoding == 'cp1252':
# encoding= '1252'
# lang = self.localcontext.get('lang', 'en_US') or 'en_US'
# try:
# if os.name == 'nt':
# locale.setlocale(locale.LC_ALL, _LOCALE2WIN32.get(lang, lang) + '.' + encoding)
# else:
# locale.setlocale(locale.LC_ALL, lang + '.' + encoding)
# except Exception:
# netsvc.Logger().notifyChannel('report', netsvc.LOG_WARNING,
# 'report %s: unable to set locale "%s"' % (self.name,
# self.localcontext.get('lang', 'en_US') or 'en_US'))
# if date:
# date = time.strptime(value, DT_FORMAT)
# return time.strftime(locale.nl_langinfo(locale.D_FMT).replace('%y', '%Y'),
# date)
# return locale.format('%.' + str(digit) + 'f', value, True)
def repeatIn(self, lst, name, nodes_parent=False):
self._node.data = ''
@ -555,7 +587,7 @@ class report_sxw(report_rml):
def getObjects(self, cr, uid, ids, context):
table_obj = pooler.get_pool(cr.dbname).get(self.table)
return table_obj.browse(cr, uid, ids, list_class=browse_record_list, context=context, fields_process=_fields_process)
return table_obj.browse(cr, uid, ids, list_class=browse_record_list, context=context)
def create(self, cr, uid, ids, data, context=None):
logo = None

View File

@ -46,7 +46,7 @@ def check(db, uid, passwd):
return True
cr = pooler.get_db(db).cursor()
cr.execute('select count(*) from res_users where id=%d and password=%s', (int(uid), passwd))
cr.execute('select count(*) from res_users where id=%s and password=%s', (int(uid), passwd))
res = cr.fetchone()[0]
cr.close()
if not bool(res):

View File

@ -29,7 +29,6 @@ import logging
import threading, thread
import time
import base64
import addons
import sql_db
@ -65,8 +64,8 @@ class db(netsvc.Service):
self.actions[id] = {'clean': False}
db = sql_db.db_connect('template1', serialize=1)
db.truedb.autocommit()
cr = db.cursor()
cr.autocommit(True)
time.sleep(0.2)
cr.execute('CREATE DATABASE ' + db_name + ' ENCODING \'unicode\'')
cr.close()
@ -108,13 +107,12 @@ class db(netsvc.Service):
traceback.print_exc(file=e_str)
traceback_str = e_str.getvalue()
e_str.close()
print traceback_str
netsvc.Logger().notifyChannel('web-services', netsvc.LOG_ERROR, 'CREATE DATABASE\n%s' % (traceback_str))
serv.actions[id]['traceback'] = traceback_str
if cr:
cr.close()
logger = netsvc.Logger()
logger.notifyChannel("web-services", netsvc.LOG_INFO,
'CREATE DB: %s' % (db_name.lower()))
logger.notifyChannel("web-services", netsvc.LOG_INFO, 'CREATE DATABASE: %s' % (db_name.lower()))
dbi = DBInitialize()
create_thread = threading.Thread(target=dbi,
args=(self, id, db_name, demo, lang, user_password))
@ -140,19 +138,19 @@ class db(netsvc.Service):
def drop(self, password, db_name):
security.check_super(password)
pooler.close_db(db_name)
sql_db.close_db(db_name)
logger = netsvc.Logger()
db = sql_db.db_connect('template1', serialize=1)
db.truedb.autocommit()
cr = db.cursor()
cr.autocommit(True)
try:
try:
cr.execute('DROP DATABASE ' + db_name)
except:
except Exception, e:
logger.notifyChannel("web-services", netsvc.LOG_ERROR,
'DROP DB: %s failed' % (db_name,))
raise
'DROP DB: %s failed:\n%s' % (db_name, e))
raise Exception("Couldn't drop database %s: %s" % (db_name, e))
else:
logger.notifyChannel("web-services", netsvc.LOG_INFO,
'DROP DB: %s' % (db_name))
@ -195,8 +193,8 @@ class db(netsvc.Service):
raise Exception, "Database already exists"
db = sql_db.db_connect('template1', serialize=1)
db.truedb.autocommit()
cr = db.cursor()
cr.autocommit(True)
cr.execute('CREATE DATABASE ' + db_name + ' ENCODING \'unicode\'')
cr.close()
@ -231,7 +229,6 @@ class db(netsvc.Service):
def db_exist(self, db_name):
try:
db = sql_db.db_connect(db_name)
db.truedb.close()
return True
except:
return False
@ -256,7 +253,6 @@ class db(netsvc.Service):
cr.close()
except:
res = []
db.truedb.close()
res.sort()
return res
@ -285,6 +281,7 @@ class common(netsvc.Service):
self.exportMethod(self.ir_del)
self.exportMethod(self.about)
self.exportMethod(self.login)
self.exportMethod(self.logout)
self.exportMethod(self.timezone_get)
def ir_set(self, db, uid, password, keys, args, name, value, replace=True, isobject=False):
@ -319,9 +316,14 @@ class common(netsvc.Service):
res = security.login(db, login, password)
logger = netsvc.Logger()
msg = res and 'successful login' or 'bad login or password'
logger.notifyChannel("web-services", netsvc.LOG_INFO, "%s from '%s' using database '%s'" % (msg, login, db.lower()))
logger.notifyChannel("web-service", netsvc.LOG_INFO, "%s from '%s' using database '%s'" % (msg, login, db.lower()))
return res or False
def logout(self, db, login, password):
logger = netsvc.Logger()
logger.notifyChannel("web-service", netsvc.LOG_INFO,'Logout %s from database %s'%(login,db))
return True
def about(self, extended=False):
"""Return information about the OpenERP Server.

View File

@ -20,135 +20,218 @@
#
##############################################################################
import psycopg
import netsvc
from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT, ISOLATION_LEVEL_SERIALIZABLE
from psycopg2.pool import ThreadedConnectionPool
from psycopg2.psycopg1 import cursor as psycopg1cursor
import psycopg2.extensions
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
types_mapping = {
'date': (1082,),
'time': (1083,),
'datetime': (1114,),
}
def unbuffer(symb, cr):
if symb is None: return None
return str(symb)
def undecimalize(symb, cr):
if symb is None: return None
return float(symb)
for name, typeoid in types_mapping.items():
psycopg2.extensions.register_type(psycopg2.extensions.new_type(typeoid, name, lambda x, cr: x))
psycopg2.extensions.register_type(psycopg2.extensions.new_type((700, 701, 1700,), 'float', undecimalize))
import tools
import sys,os
#try:
# import decimal
#except ImportError:
# from tools import decimal
import re
from mx import DateTime as mdt
re_from = re.compile('.* from "?([a-zA-Z_0-9]+)"? .*$');
re_into = re.compile('.* into "?([a-zA-Z_0-9]+)"? .*$');
class fake_cursor:
def log(msg, lvl=netsvc.LOG_DEBUG):
logger = netsvc.Logger()
logger.notifyChannel('sql', lvl, msg)
class Cursor(object):
IN_MAX = 1000
nbr = 0
_tables = {}
sql_from_log = {}
sql_into_log = {}
sql_log = False
count = 0
def check(f):
from tools.func import wraps
def __init__(self, db, con, dbname):
self.db = db
self.obj = db.cursor()
self.con = con
self.dbname = dbname
@wraps(f)
def wrapper(self, *args, **kwargs):
if not hasattr(self, '_obj'):
raise psycopg2.ProgrammingError('Unable to use the cursor after having closing it')
return f(self, *args, **kwargs)
return wrapper
def execute(self, sql, params=None):
if not params:
def __init__(self, pool):
self._pool = pool
self._cnx = pool.getconn()
self._obj = self._cnx.cursor(cursor_factory=psycopg1cursor)
self.autocommit(False)
self.dbname = pool.dbname
def __del__(self):
if hasattr(self, '_obj'):
# Oops. 'self' has not been closed explicitly.
# The cursor will be deleted by the garbage collector,
# but the database connection is not put back into the connection
# pool, preventing some operation on the database like dropping it.
# This can also lead to a server overload.
log('Cursor not closed explicitly', netsvc.LOG_WARNING)
self.close()
@check
def execute(self, query, params=None):
if params is None:
params=()
if not isinstance(params, (tuple, list)):
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')
query = base_string(query)
if '%d' in query or '%f' in query:
#import traceback
#traceback.print_stack()
log(query, netsvc.LOG_WARNING)
log("SQL queries mustn't containt %d or %f anymore. Use only %s", netsvc.LOG_WARNING)
if p:
query = query.replace('%d', '%s').replace('%f', '%s')
if self.sql_log:
now = mdt.now()
print "SQL LOG query:", sql
print "SQL LOG params:", repr(p)
if p:
res = self.obj.execute(sql, p)
else:
res = self.obj.execute(sql)
res = self._obj.execute(query, p or None)
if self.sql_log:
log("query: %s" % self._obj.query)
self.count+=1
res_from = re_from.match(sql.lower())
res_from = re_from.match(query.lower())
if res_from:
self.sql_from_log.setdefault(res_from.group(1), [0, 0])
self.sql_from_log[res_from.group(1)][0] += 1
self.sql_from_log[res_from.group(1)][1] += mdt.now() - now
res_into = re_into.match(sql.lower())
res_into = re_into.match(query.lower())
if res_into:
self.sql_into_log.setdefault(res_into.group(1), [0, 0])
self.sql_into_log[res_into.group(1)][0] += 1
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 print_log(self):
def process(type):
sqllogs = {'from':self.sql_from_log, 'into':self.sql_into_log}
if not sqllogs[type]:
return
sqllogitems = sqllogs[type].items()
sqllogitems.sort(key=lambda k: k[1][1])
sum = 0
log("SQL LOG %s:" % (type,))
for r in sqllogitems:
log("table: %s: %s/%s" %(r[0], str(r[1][1]), r[1][0]))
sum+= r[1][1]
log("SUM:%s/%d" % (sum, self.count))
sqllogs[type].clear()
process('from')
process('into')
self.count = 0
@check
def close(self):
if self.sql_log:
self.print_log('from')
self.print_log('into')
self.obj.close()
self.print_log()
self._obj.close()
# This force the cursor to be freed, and thus, available again. It is
# important because otherwise we can overload the server very easily
# because of a cursor shortage (because cursors are not garbage
# collected as fast as they should). The problem is probably due in
# part because browse records keep a reference to the cursor.
del self.obj
del self._obj
self._pool.putconn(self._cnx)
@check
def autocommit(self, on):
self._cnx.set_isolation_level([ISOLATION_LEVEL_SERIALIZABLE, ISOLATION_LEVEL_AUTOCOMMIT][bool(on)])
@check
def commit(self):
return self._cnx.commit()
@check
def rollback(self):
return self._cnx.rollback()
@check
def __getattr__(self, name):
return getattr(self.obj, name)
return getattr(self._obj, name)
class fakedb:
def __init__(self, truedb, dbname):
self.truedb = truedb
class ConnectionPool(object):
def __init__(self, pool, dbname):
self.dbname = dbname
self._pool = pool
def cursor(self):
return fake_cursor(self.truedb, {}, self.dbname)
return Cursor(self)
def decimalize(symb):
if symb is None: return None
if isinstance(symb, float):
return decimal.Decimal('%f' % symb)
return decimal.Decimal(symb)
def __getattr__(self, name):
return getattr(self._pool, name)
class PoolManager(object):
_pools = {}
_dsn = None
maxconn = int(tools.config['db_maxconn']) or 64
def dsn(db_name):
if PoolManager._dsn is None:
PoolManager._dsn = ''
for p in ('host', 'port', 'user', 'password'):
cfg = tools.config['db_' + p]
if cfg:
PoolManager._dsn += '%s=%s ' % (p, cfg)
return '%s dbname=%s' % (PoolManager._dsn, db_name)
dsn = staticmethod(dsn)
def get(db_name):
if db_name not in PoolManager._pools:
logger = netsvc.Logger()
try:
logger.notifyChannel('dbpool', netsvc.LOG_INFO, 'Connecting to %s' % (db_name,))
PoolManager._pools[db_name] = ConnectionPool(ThreadedConnectionPool(0, PoolManager.maxconn, PoolManager.dsn(db_name)), db_name)
except Exception, e:
logger.notifyChannel('dbpool', netsvc.LOG_CRITICAL, 'Unable to connect to %s: %r' % (db_name, e))
raise
return PoolManager._pools[db_name]
get = staticmethod(get)
def close(db_name):
if db_name is PoolManager._pools:
logger.notifyChannel('dbpool', netsvc.LOG_INFO, 'Closing all connections to %s' % (db_name,))
PoolManager._pools[db_name].closeall()
del PoolManager._pools[db_name]
close = staticmethod(close)
def db_connect(db_name, serialize=0):
host = tools.config['db_host'] and "host=%s" % tools.config['db_host'] or ''
port = tools.config['db_port'] and "port=%s" % tools.config['db_port'] or ''
name = "dbname=%s" % db_name
user = tools.config['db_user'] and "user=%s" % tools.config['db_user'] or ''
password = tools.config['db_password'] and "password=%s" % tools.config['db_password'] or ''
maxconn = int(tools.config['db_maxconn']) or 64
tdb = psycopg.connect('%s %s %s %s %s' % (host, port, name, user, password),
serialize=serialize, maxconn=maxconn)
fdb = fakedb(tdb, db_name)
return fdb
def init():
#define DATEOID 1082, define TIMESTAMPOID 1114 see pgtypes.h
psycopg.register_type(psycopg.new_type((1082,), "date", lambda x:x))
psycopg.register_type(psycopg.new_type((1083,), "time", lambda x:x))
psycopg.register_type(psycopg.new_type((1114,), "datetime", lambda x:x))
#psycopg.register_type(psycopg.new_type((700, 701, 1700), 'decimal', decimalize))
psycopg.register_type(psycopg.new_type((1082,), "date", lambda x:x))
psycopg.register_type(psycopg.new_type((1083,), "time", lambda x:x))
psycopg.register_type(psycopg.new_type((1114,), "datetime", lambda x:x))
return PoolManager.get(db_name)
def close_db(db_name):
return PoolManager.close(db_name)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -116,15 +116,14 @@ def amount_to_text(nbr, lang='en', currency='euro'):
Example:
1654: thousands six cent cinquante-quatre.
"""
import netsvc
if nbr > 10000000:
#TODO: use logger
print "WARNING: number too large '%d', can't translate it!" % (nbr,)
netsvc.Logger().notifyChannel('translate', netsvc.LOG_WARNING, _("Number too large '%d', can not translate it"))
return str(nbr)
if not _translate_funcs.has_key(lang):
#TODO: use logger
print "WARNING: no translation function found for lang: '%s'" % (lang,)
#TODO: (default should be en) same as above
netsvc.Logger().notifyChannel('translate', netsvc.LOG_WARNING, _("no translation function found for lang: '%s'" % (lang,)))
#TODO: (default should be en) same as above
lang = 'en'
return _translate_funcs[lang](nbr, currency)

View File

@ -35,7 +35,7 @@ class configmanager(object):
'netport': '8070',
'db_host': False,
'db_port': False,
'db_name': 'terp',
'db_name': False,
'db_user': False,
'db_password': False,
'db_maxconn': 64,
@ -62,10 +62,11 @@ class configmanager(object):
'stop_after_init': False, # this will stop the server after initialization
'price_accuracy': 2,
'assert_exit_level': logging.WARNING, # level above which a failed assert will
'log_level': logging.INFO,
'assert_exit_level': logging.WARNING, # level above which a failed assert will be raise
}
assert_exit_levels = (netsvc.LOG_CRITICAL, netsvc.LOG_ERROR, netsvc.LOG_WARNING, netsvc.LOG_INFO, netsvc.LOG_DEBUG)
loglevels = dict([(getattr(netsvc, 'LOG_%s' % x), getattr(logging, x)) for x in ('CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG')])
version = "%s %s" % (release.description, release.version)
parser = optparse.OptionParser(version=version)
@ -89,7 +90,8 @@ class configmanager(object):
# stops the server from launching after initialization
parser.add_option("--stop-after-init", action="store_true", dest="stop_after_init", default=False, help="stop the server after it initializes")
parser.add_option('--debug', dest='debug_mode', action='store_true', default=False, help='enable debug mode')
parser.add_option("--assert-exit-level", dest='assert_exit_level', help="specify the level at which a failed assertion will stop the server " + str(assert_exit_levels))
parser.add_option('--log-level', dest='log_level', type='choice', choices=loglevels.keys(), help='specify the level of the logging. Accepted values: ' + str(loglevels.keys()))
parser.add_option("--assert-exit-level", dest='assert_exit_level', type="choice", choices=loglevels.keys(), help="specify the level at which a failed assertion will stop the server. Accepted values: " + str(loglevels.keys()))
parser.add_option("-S", "--secure", dest="secure", action="store_true", help="launch server over https instead of http", default=False)
parser.add_option('--email-from', dest='email_from', default='', help='specify the SMTP email address for sending email')
@ -163,8 +165,9 @@ class configmanager(object):
self.options[arg] = getattr(opt, arg)
if opt.assert_exit_level:
assert opt.assert_exit_level in assert_exit_levels, 'ERROR: The assert-exit-level must be one of those values: '+str(assert_exit_levels)
self.options['assert_exit_level'] = getattr(logging, opt.assert_exit_level.upper())
self.options['assert_exit_level'] = loglevels[opt.assert_exit_level]
if opt.log_level:
self.options['log_level'] = loglevels[opt.log_level]
if not self.options['root_path'] or self.options['root_path']=='None':
self.options['root_path'] = os.path.abspath(os.path.dirname(sys.argv[0]))

View File

@ -100,7 +100,7 @@ def _eval_xml(self,node, pool, cr, uid, idref, context=None):
import pytz
except:
logger = netsvc.Logger()
logger.notifyChannel("init", netsvc.LOG_INFO, 'could not find pytz library')
logger.notifyChannel("init", netsvc.LOG_WARNING, 'could not find pytz library')
class pytzclass(object):
all_timezones=[]
pytz=pytzclass()
@ -479,7 +479,7 @@ form: module.record_id""" % (xml_id,)
pid = False
for idx, menu_elem in enumerate(m_l):
if pid:
cr.execute('select id from ir_ui_menu where parent_id=%d and name=%s', (pid, menu_elem))
cr.execute('select id from ir_ui_menu where parent_id=%s and name=%s', (pid, menu_elem))
else:
cr.execute('select id from ir_ui_menu where parent_id is null and name=%s', (menu_elem,))
res = cr.fetchone()
@ -491,7 +491,7 @@ form: module.record_id""" % (xml_id,)
try:
npid = self.pool.get('ir.model.data')._update_dummy(cr, self.uid, 'ir.ui.menu', self.module, xml_id, idx==len(m_l)-1)
except:
print 'Menu Error', self.module, xml_id, idx==len(m_l)-1
self.logger.notifyChannel('init', netsvc.LOG_ERROR, "addon: %s xml_id: %s" % (self.module, xml_id))
else:
# the menuitem does't exist but we are in branch (not a leaf)
self.logger.notifyChannel("init", netsvc.LOG_WARNING, 'Warning no ID for submenu %s of menu %s !' % (menu_elem, str(m_l)))
@ -518,15 +518,15 @@ form: module.record_id""" % (xml_id,)
values['icon'] = icons.get(a_type,'STOCK_NEW')
if a_type=='act_window':
a_id = self.id_get(cr, 'ir.actions.%s'% a_type, a_action)
cr.execute('select view_type,view_mode,name,view_id,target from ir_act_window where id=%d', (int(a_id),))
cr.execute('select view_type,view_mode,name,view_id,target from ir_act_window where id=%s', (int(a_id),))
rrres = cr.fetchone()
assert rrres, "No window action defined for this id %s !\n" \
"Verify that this is a window action or add a type argument." % (a_action,)
action_type,action_mode,action_name,view_id,target = rrres
if view_id:
cr.execute('SELECT type FROM ir_ui_view WHERE id=%d', (int(view_id),))
cr.execute('SELECT type FROM ir_ui_view WHERE id=%s', (int(view_id),))
action_mode, = cr.fetchone()
cr.execute('SELECT view_mode FROM ir_act_window_view WHERE act_window_id=%d ORDER BY sequence LIMIT 1', (int(a_id),))
cr.execute('SELECT view_mode FROM ir_act_window_view WHERE act_window_id=%s ORDER BY sequence LIMIT 1', (int(a_id),))
if cr.rowcount:
action_mode, = cr.fetchone()
if action_type=='tree':
@ -543,7 +543,7 @@ form: module.record_id""" % (xml_id,)
values['name'] = action_name
elif a_type=='wizard':
a_id = self.id_get(cr, 'ir.actions.%s'% a_type, a_action)
cr.execute('select name from ir_act_wizard where id=%d', (int(a_id),))
cr.execute('select name from ir_act_wizard where id=%s', (int(a_id),))
resw = cr.fetchone()
if (not values.get('name', False)) and resw:
values['name'] = resw[0]
@ -612,7 +612,12 @@ form: module.record_id""" % (xml_id,)
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)) + ')' )
msg = 'assertion "%s" failed!\n' \
' Incorrect search count:\n' \
' expected count: %d\n' \
' obtained count: %d\n' \
% (rec_string, count, len(ids))
self.logger.notifyChannel('init', severity, msg)
sevval = getattr(logging, severity.upper())
if sevval >= config['assert_exit_level']:
# TODO: define a dedicated exception
@ -635,10 +640,16 @@ form: module.record_id""" % (xml_id,)
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
expected_value = _eval_xml(self, test, self.pool, cr, uid, self.idref, context=context) or True
expression_value = eval(f_expr, globals)
if expression_value != expected_value: # assertion failed
self.assert_report.record_assertion(False, severity)
self.logger.notifyChannel('init', severity, 'assertion "' + rec_string + '" failed ! (tag ' + test.toxml() + ')' )
msg = 'assertion "%s" failed!\n' \
' xmltag: %s\n' \
' expected value: %r\n' \
' obtained value: %r\n' \
% (rec_string, test.toxml(), expected_value, expression_value)
self.logger.notifyChannel('init', severity, msg)
sevval = getattr(logging, severity.upper())
if sevval >= config['assert_exit_level']:
# TODO: define a dedicated exception
@ -657,7 +668,7 @@ form: module.record_id""" % (xml_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':
if self.isnoupdate(data_node) and not self.mode in ('init','update'):
# 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)
@ -718,10 +729,11 @@ form: module.record_id""" % (xml_id,)
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('import_partial', False):
if config.get('i mport_partial', False):
cr.commit()
return rec_model, id
@ -743,7 +755,7 @@ form: module.record_id""" % (xml_id,)
raise Exception( "Mismatch xml format: only terp or openerp as root tag" )
if de.nodeName == 'terp':
self.logger.notifyChannel("init", netsvc.LOG_WARNING, "The tag <terp /> is deprecated, use <openerp/>")
self.logger.notifyChannel("init", netsvc.LOG_WARNING, "The tag <terp/> is deprecated, use <openerp/>")
for n in [i for i in de.childNodes if (i.nodeType == i.ELEMENT_NODE and i.nodeName=="data")]:
for rec in n.childNodes:
@ -752,7 +764,7 @@ form: module.record_id""" % (xml_id,)
try:
self._tags[rec.nodeName](self.cr, rec, n)
except:
self.logger.notifyChannel("init", netsvc.LOG_INFO, '\n'+rec.toxml())
self.logger.notifyChannel("init", netsvc.LOG_ERROR, '\n'+rec.toxml())
self.cr.rollback()
raise
return True
@ -824,9 +836,10 @@ def convert_csv_import(cr, module, fname, csvcontent, idref=None, mode='init',
if (not line) or not reduce(lambda x,y: x or y, line) :
continue
try:
datas.append( map(lambda x:x.decode('utf8').encode('utf8'), line))
datas.append(map(lambda x: misc.ustr(x), line))
except:
print "ERROR while importing the line: ", line
logger = netsvc.Logger()
logger.notifyChannel("init", netsvc.LOG_ERROR, "Can not import the line: %s" % line)
pool.get(model).import_data(cr, uid, fields, datas,mode, module,noupdate,filename=fname_partial)
if config.get('import_partial'):
data = pickle.load(file(config.get('import_partial')))

31
bin/tools/func.py Normal file
View File

@ -0,0 +1,31 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
try:
from functools import wraps
except ImportError:
# this module doesn't exist in python < 2.5
# we define a identity decorator
def wraps(f):
def identity(x):
return x
return identity

View File

@ -759,8 +759,6 @@ if __name__=='__main__':
g.process(starting_node)
g.scale(radius*3,radius*3, radius, radius)
print g
import Image
import ImageDraw
img = Image.new("RGB", (800, 600), "#ffffff")

View File

@ -27,10 +27,7 @@ Miscelleanous tools used by OpenERP.
import os, time, sys
import inspect
import psycopg
#import netsvc
from config import config
#import tools
import zipfile
import release
@ -71,7 +68,7 @@ def init_db(cr):
if p_id is not None:
cr.execute('select id \
from ir_module_category \
where name=%s and parent_id=%d', (categs[0], p_id))
where name=%s and parent_id=%s', (categs[0], p_id))
else:
cr.execute('select id \
from ir_module_category \
@ -82,7 +79,7 @@ def init_db(cr):
c_id = cr.fetchone()[0]
cr.execute('insert into ir_module_category \
(id, name, parent_id) \
values (%d, %s, %d)', (c_id, categs[0], p_id))
values (%s, %s, %s)', (c_id, categs[0], p_id))
else:
c_id = c_id[0]
p_id = c_id
@ -100,11 +97,10 @@ def init_db(cr):
cr.execute('select nextval(\'ir_module_module_id_seq\')')
id = cr.fetchone()[0]
cr.execute('insert into ir_module_module \
(id, author, latest_version, website, name, shortdesc, description, \
(id, author, website, name, shortdesc, description, \
category_id, state) \
values (%d, %s, %s, %s, %s, %s, %s, %d, %s)', (
values (%s, %s, %s, %s, %s, %s, %s, %s)', (
id, info.get('author', ''),
release.major_version + '.' + info.get('version', ''),
info.get('website', ''), i, info.get('name', False),
info.get('description', ''), p_id, state))
dependencies = info.get('depends', [])
@ -388,7 +384,7 @@ def sms_send(user, password, api_id, text, to):
params = urllib.urlencode({'user': user, 'password': password, 'api_id': api_id, 'text': text, 'to':to})
#f = urllib.urlopen("http://api.clickatell.com/http/sendmsg", params)
f = urllib.urlopen("http://196.7.150.220/http/sendmsg", params)
print f.read()
# FIXME: Use the logger if there is an error
return True
#---------------------------------------------------------
@ -540,29 +536,36 @@ def is_hashable(h):
# Timeout: 0 = no timeout, otherwise in seconds
#
class cache(object):
def __init__(self, timeout=10000, skiparg=2):
def __init__(self, timeout=10000, skiparg=2, multi=None):
self.timeout = timeout
self.skiparg = skiparg
self.multi = multi
self.cache = {}
def __call__(self, fn):
arg_names = inspect.getargspec(fn)[0][2:]
arg_names = inspect.getargspec(fn)[0][self.skiparg:]
def cached_result(self2, cr=None, *args, **kwargs):
if cr is None:
self.cache = {}
return True
if ('clear_keys' in kwargs):
if (kwargs['clear_keys'] in self.cache):
del self.cache[kwargs['clear_keys']]
return True
# Update named arguments with positional argument values
kwargs.update(dict(zip(arg_names, args)))
for k in kwargs:
if isinstance(kwargs[k], (list, dict, set)):
kwargs[k] = tuple(kwargs[k])
elif not is_hashable(kwargs[k]):
kwargs[k] = repr(kwargs[k])
kwargs = kwargs.items()
kwargs.sort()
kwargs2 = kwargs.copy()
kwargs2.update(dict(zip(arg_names, args)))
for k in kwargs2:
if isinstance(kwargs2[k], (list, dict, set)):
kwargs2[k] = tuple(kwargs2[k])
elif not is_hashable(kwargs2[k]):
kwargs2[k] = repr(kwargs2[k])
kwargs2 = kwargs2.items()
kwargs2.sort()
# Work out key as a tuple of ('argname', value) pairs
key = (('dbname', cr.dbname),) + tuple(kwargs)
key = (('dbname', cr.dbname),) + tuple(kwargs2)
# Check cache and return cached value if possible
if key in self.cache:
@ -574,7 +577,7 @@ class cache(object):
# Work out new value, cache it and return it
# FIXME Should copy() this value to avoid futur modifications of the cache ?
# FIXME What about exceptions ?
result = fn(self2,cr,**dict(kwargs))
result = fn(self2,cr,*args, **kwargs)
self.cache[key] = (result, time.time())
return result
@ -583,6 +586,28 @@ class cache(object):
def to_xml(s):
return s.replace('&','&amp;').replace('<','&lt;').replace('>','&gt;')
def ustr(value):
"""This method is similar to the builtin `str` method, except
it will return Unicode string.
@param value: the value to convert
@rtype: unicode
@return: unicode string
"""
if isinstance(value, unicode):
return value
if hasattr(value, '__unicode__'):
return unicode(value)
if not isinstance(value, str):
value = str(value)
return unicode(value, 'utf-8')
def get_languages():
languages={
'bg_BG': u'Bulgarian / български',
@ -633,7 +658,7 @@ def get_user_companies(cr, user):
res=[x[0] for x in cr.fetchall()]
res.extend(_get_company_children(cr, res))
return res
cr.execute('SELECT comp.id FROM res_company AS comp, res_users AS u WHERE u.id = %d AND comp.id = u.company_id' % (user,))
cr.execute('SELECT comp.id FROM res_company AS comp, res_users AS u WHERE u.id = %s AND comp.id = u.company_id' % (user,))
compids=[cr.fetchone()[0]]
compids.extend(_get_company_children(cr, compids))
return compids
@ -669,39 +694,30 @@ def human_size(sz):
i = i + 1
return "%0.2f %s" % (s, units[i])
def logged(when):
def log(f, res, *args, **kwargs):
vector = ['Call -> function: %s' % f]
def logged(f):
from tools.func import wraps
@wraps(f)
def wrapper(*args, **kwargs):
import netsvc
from pprint import pformat
vector = ['Call -> function: %r' % f]
for i, arg in enumerate(args):
vector.append( ' arg %02d: %r' % ( i, arg ) )
vector.append(' arg %02d: %s' % (i, pformat(arg)))
for key, value in kwargs.items():
vector.append( ' kwarg %10s: %r' % ( key, value ) )
vector.append( ' result: %r' % res )
print "\n".join(vector)
vector.append(' kwarg %10s: %s' % (key, pformat(value)))
def pre_logged(f):
def wrapper(*args, **kwargs):
res = f(*args, **kwargs)
log(f, res, *args, **kwargs)
return res
return wrapper
timeb4 = time.time()
res = f(*args, **kwargs)
vector.append(' result: %s' % pformat(res))
vector.append(' time delta: %s' % (time.time() - timeb4))
#netsvc.Logger().notifyChannel('logged', netsvc.LOG_DEBUG, '\n'.join(vector))
return res
def post_logged(f):
def wrapper(*args, **kwargs):
now = time.time()
res = None
try:
res = f(*args, **kwargs)
return res
finally:
log(f, res, *args, **kwargs)
print " time delta: %s" % (time.time() - now)
return wrapper
return wrapper
try:
return { "pre" : pre_logged, "post" : post_logged}[when]
except KeyError, e:
raise ValueError(e), "must to be 'pre' or 'post'"
icons = map(lambda x: (x,x), ['STOCK_ABOUT', 'STOCK_ADD', 'STOCK_APPLY', 'STOCK_BOLD',
'STOCK_CANCEL', 'STOCK_CDROM', 'STOCK_CLEAR', 'STOCK_CLOSE', 'STOCK_COLOR_PICKER',

View File

@ -34,7 +34,7 @@ def listdir(dir, recursive=False):
return os.listdir(dir)
res = []
for root, dirs, files in os.walk(dir):
for root, dirs, files in walksymlinks(dir):
root = root[len(dir)+1:]
res.extend([opj(root, f) for f in files])
return res

View File

@ -41,7 +41,7 @@ class UNIX_LINE_TERMINATOR(csv.excel):
csv.register_dialect("UNIX", UNIX_LINE_TERMINATOR)
#
# TODO: a caching method
# Warning: better use self.pool.get('ir.translation')._get_source if you can
#
def translate(cr, name, source_type, lang, source=None):
if source and name:
@ -64,8 +64,10 @@ class GettextAlias(object):
return source
except:
return source
return translate(cr, None, 'code', lang, source) or source
cr.execute('select value from ir_translation where lang=%s and type=%s and src=%s', (lang, 'code', source))
res_trans = cr.fetchone()
return res_trans and res_trans[0] or source
_ = GettextAlias()
@ -570,7 +572,6 @@ def trans_load_data(db_name, fileobj, fileformat, lang, strict=False, lang_name=
line += 1
# skip empty rows and rows where the translation field (=last fiefd) is empty
if (not row) or (not row[-1]):
#print "translate: skip %s" % repr(row)
continue
# dictionary which holds values for this line of the csv file

View File

@ -59,7 +59,7 @@ def upgrade():
for module_id,name,url in cr.fetchall():
print '\tremoving module %s' % name
remove(name)
cr.execute('update ir_module_module set state=%s where id=%d', ('uninstalled', module_id))
cr.execute('update ir_module_module set state=%s where id=%s', ('uninstalled', module_id))
cr.commit()
print 'Check for modules to upgrade...'
@ -68,7 +68,7 @@ def upgrade():
print '\tupgrading module %s' % name
remove(name)
install(name, url)
cr.execute('update ir_module_module set state=%s where id=%d', ('installed', module_id))
cr.execute('update ir_module_module set state=%s where id=%s', ('installed', module_id))
cr.commit()
toupdate.append(name)
@ -77,7 +77,7 @@ def upgrade():
for module_id,name,url in cr.fetchall():
print '\tinstalling module %s' % name
install(name, url)
cr.execute('update ir_module_module set state=%s where id=%d', ('installed', module_id))
cr.execute('update ir_module_module set state=%s where id=%s', ('installed', module_id))
cr.commit()
toinit.append(name)

View File

@ -54,7 +54,7 @@ class interface(netsvc.Service):
if node.hasAttribute('string') and node.getAttribute('string'):
trans = translate(cr, self.wiz_name+','+state, 'wizard_view', lang, node.getAttribute('string').encode('utf8'))
if trans:
node.setAttribute('string', trans.decode('utf8'))
node.setAttribute('string', trans)
for n in node.childNodes:
self.translate_view(cr, n, state, lang)

View File

@ -30,8 +30,8 @@ def create(cr, ident, wkf_id):
(uid,res_type,res_id) = ident
cr.execute("select nextval('wkf_instance_id_seq')")
id_new = cr.fetchone()[0]
cr.execute('insert into wkf_instance (id,res_type,res_id,uid,wkf_id) values (%d,%s,%s,%s,%s)', (id_new,res_type,res_id,uid,wkf_id))
cr.execute('select * from wkf_activity where flow_start=True and wkf_id=%d', (wkf_id,))
cr.execute('insert into wkf_instance (id,res_type,res_id,uid,wkf_id) values (%s,%s,%s,%s,%s)', (id_new,res_type,res_id,uid,wkf_id))
cr.execute('select * from wkf_activity where flow_start=True and wkf_id=%s', (wkf_id,))
res = cr.dictfetchall()
stack = []
workitem.create(cr, res, id_new, ident, stack=stack)
@ -40,10 +40,10 @@ def create(cr, ident, wkf_id):
def delete(cr, ident):
(uid,res_type,res_id) = ident
cr.execute('delete from wkf_instance where res_id=%d and res_type=%s', (res_id,res_type))
cr.execute('delete from wkf_instance where res_id=%s and res_type=%s', (res_id,res_type))
def validate(cr, inst_id, ident, signal, force_running=False):
cr.execute("select * from wkf_workitem where inst_id=%d", (inst_id,))
cr.execute("select * from wkf_workitem where inst_id=%s", (inst_id,))
for witem in cr.dictfetchall():
stack = []
workitem.process(cr, witem, ident, signal, force_running, stack=stack)
@ -52,27 +52,27 @@ def validate(cr, inst_id, ident, signal, force_running=False):
return stack and stack[0] or False
def update(cr, inst_id, ident):
cr.execute("select * from wkf_workitem where inst_id=%d", (inst_id,))
cr.execute("select * from wkf_workitem where inst_id=%s", (inst_id,))
for witem in cr.dictfetchall():
stack = []
workitem.process(cr, witem, ident, stack=stack)
return _update_end(cr, inst_id, ident)
def _update_end(cr, inst_id, ident):
cr.execute('select wkf_id from wkf_instance where id=%d', (inst_id,))
cr.execute('select wkf_id from wkf_instance where id=%s', (inst_id,))
wkf_id = cr.fetchone()[0]
cr.execute('select state,flow_stop from wkf_workitem w left join wkf_activity a on (a.id=w.act_id) where w.inst_id=%d', (inst_id,))
cr.execute('select state,flow_stop from wkf_workitem w left join wkf_activity a on (a.id=w.act_id) where w.inst_id=%s', (inst_id,))
ok=True
for r in cr.fetchall():
if (r[0]<>'complete') or not r[1]:
ok=False
break
if ok:
cr.execute('select distinct a.name from wkf_activity a left join wkf_workitem w on (a.id=w.act_id) where w.inst_id=%d', (inst_id,))
cr.execute('select distinct a.name from wkf_activity a left join wkf_workitem w on (a.id=w.act_id) where w.inst_id=%s', (inst_id,))
act_names = cr.fetchall()
cr.execute("update wkf_instance set state='complete' where id=%d", (inst_id,))
cr.execute("update wkf_workitem set state='complete' where subflow_id=%d", (inst_id,))
cr.execute("select i.id,w.osv,i.res_id from wkf_instance i left join wkf w on (i.wkf_id=w.id) where i.id in (select inst_id from wkf_workitem where subflow_id=%d)", (inst_id,))
cr.execute("update wkf_instance set state='complete' where id=%s", (inst_id,))
cr.execute("update wkf_workitem set state='complete' where subflow_id=%s", (inst_id,))
cr.execute("select i.id,w.osv,i.res_id from wkf_instance i left join wkf w on (i.wkf_id=w.id) where i.id in (select inst_id from wkf_workitem where subflow_id=%s)", (inst_id,))
for i in cr.fetchall():
for act_name in act_names:
validate(cr, i[0], (ident[0],i[1],i[2]), 'subflow.'+act_name[0])

View File

@ -66,7 +66,7 @@ def _eval_expr(cr, ident, workitem, action):
ret=False
assert action, 'You used a NULL action in a workflow, use dummy node instead.'
for line in action.split('\n'):
line = line.replace(chr(13),'')
line = line.strip()
uid=ident[0]
model=ident[1]
ids=[ident[2]]

View File

@ -23,10 +23,19 @@
#
# May be uncommented to logs workflows modifications
#
import netsvc
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))
msg = """
res_type: %r
res_id: %d
uid: %d
act_id: %d
info: %s
""" % (ident[1], ident[2], ident[0], act_id, info)
netsvc.Logger().notifyChannel('wkf_log', netsvc.LOG_DEBUG, msg)
#cr.execute('insert into wkf_logs (res_type, res_id, uid, act_id, time, info) values (%s,%s,%s,%s,current_time,%s)', (ident[1],int(ident[2]),int(ident[0]),int(act_id),info))
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -44,15 +44,15 @@ class workflow_service(netsvc.Service):
def trg_write(self, uid, res_type, res_id, cr):
ident = (uid,res_type,res_id)
cr.execute('select id from wkf_instance where res_id=%d and res_type=%s and state=%s', (res_id,res_type, 'active'))
cr.execute('select id from wkf_instance where res_id=%s and res_type=%s and state=%s', (res_id or None,res_type or None, 'active'))
for (id,) in cr.fetchall():
instance.update(cr, id, ident)
def trg_trigger(self, uid, res_type, res_id, cr):
cr.execute('select instance_id from wkf_triggers where res_id=%d and model=%s', (res_id,res_type))
cr.execute('select instance_id from wkf_triggers where res_id=%s and model=%s', (res_id,res_type))
res = cr.fetchall()
for (instance_id,) in res:
cr.execute('select uid,res_type,res_id from wkf_instance where id=%d', (instance_id,))
cr.execute('select uid,res_type,res_id from wkf_instance where id=%s', (instance_id,))
ident = cr.fetchone()
instance.update(cr, instance_id, ident)
@ -76,7 +76,7 @@ class workflow_service(netsvc.Service):
result = False
ident = (uid,res_type,res_id)
# ids of all active workflow instances for a corresponding resource (id, model_nam)
cr.execute('select id from wkf_instance where res_id=%d and res_type=%s and state=%s', (res_id, res_type, 'active'))
cr.execute('select id from wkf_instance where res_id=%s and res_type=%s and state=%s', (res_id, res_type, 'active'))
for (id,) in cr.fetchall():
res2 = instance.validate(cr, id, ident, signal)
result = result or res2
@ -88,21 +88,21 @@ class workflow_service(netsvc.Service):
def trg_redirect(self, uid, res_type, res_id, new_rid, cr):
# get ids of wkf instances for the old resource (res_id)
#CHECKME: shouldn't we get only active instances?
cr.execute('select id, wkf_id from wkf_instance where res_id=%d and res_type=%s', (res_id, res_type))
cr.execute('select id, wkf_id from wkf_instance where res_id=%s and res_type=%s', (res_id, res_type))
for old_inst_id, wkf_id in cr.fetchall():
# first active instance for new resource (new_rid), using same wkf
cr.execute(
'SELECT id '\
'FROM wkf_instance '\
'WHERE res_id=%d AND res_type=%s AND wkf_id=%d AND state=%s',
'WHERE res_id=%s AND res_type=%s AND wkf_id=%s AND state=%s',
(new_rid, res_type, wkf_id, 'active'))
new_id = cr.fetchone()
if new_id:
# select all workitems which "wait" for the old instance
cr.execute('select id from wkf_workitem where subflow_id=%d', (old_inst_id,))
cr.execute('select id from wkf_workitem where subflow_id=%s', (old_inst_id,))
for (item_id,) in cr.fetchall():
# redirect all those workitems to the wkf instance of the new resource
cr.execute('update wkf_workitem set subflow_id=%d where id=%d', (new_id[0], item_id))
cr.execute('update wkf_workitem set subflow_id=%s where id=%s', (new_id[0], item_id))
workflow_service()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -22,7 +22,7 @@
#
# TODO:
# cr.execute('delete from wkf_triggers where model=%s and res_id=%d', (res_type,res_id))
# cr.execute('delete from wkf_triggers where model=%s and res_id=%s', (res_type,res_id))
#
import netsvc
@ -35,8 +35,8 @@ def create(cr, act_datas, inst_id, ident, stack):
for act in act_datas:
cr.execute("select nextval('wkf_workitem_id_seq')")
id_new = cr.fetchone()[0]
cr.execute("insert into wkf_workitem (id,act_id,inst_id,state) values (%d,%s,%s,'active')", (id_new, act['id'], inst_id))
cr.execute('select * from wkf_workitem where id=%d',(id_new,))
cr.execute("insert into wkf_workitem (id,act_id,inst_id,state) values (%s,%s,%s,'active')", (id_new, act['id'], inst_id))
cr.execute('select * from wkf_workitem where id=%s',(id_new,))
res = cr.dictfetchone()
wkf_logs.log(cr,ident,act['id'],'active')
process(cr, res, ident, stack=stack)
@ -45,7 +45,7 @@ def process(cr, workitem, ident, signal=None, force_running=False, stack=None):
if stack is None:
raise 'Error !!!'
result = True
cr.execute('select * from wkf_activity where id=%d', (workitem['act_id'],))
cr.execute('select * from wkf_activity where id=%s', (workitem['act_id'],))
activity = cr.dictfetchone()
triggers = False
@ -63,7 +63,7 @@ def process(cr, workitem, ident, signal=None, force_running=False, stack=None):
triggers = triggers and not ok
if triggers:
cr.execute('select * from wkf_transition where act_from=%d', (workitem['act_id'],))
cr.execute('select * from wkf_transition where act_from=%s', (workitem['act_id'],))
alltrans = cr.dictfetchall()
for trans in alltrans:
if trans['trigger_model']:
@ -71,7 +71,7 @@ def process(cr, workitem, ident, signal=None, force_running=False, stack=None):
for res_id in ids:
cr.execute('select nextval(\'wkf_triggers_id_seq\')')
id =cr.fetchone()[0]
cr.execute('insert into wkf_triggers (model,res_id,instance_id,workitem_id,id) values (%s,%d,%d,%d,%d)', (trans['trigger_model'],res_id,workitem['inst_id'], workitem['id'], id))
cr.execute('insert into wkf_triggers (model,res_id,instance_id,workitem_id,id) values (%s,%s,%s,%s,%s)', (trans['trigger_model'],res_id,workitem['inst_id'], workitem['id'], id))
return result
@ -79,7 +79,7 @@ def process(cr, workitem, ident, signal=None, force_running=False, stack=None):
# ---------------------- PRIVATE FUNCS --------------------------------
def _state_set(cr, workitem, activity, state, ident):
cr.execute('update wkf_workitem set state=%s where id=%d', (state,workitem['id']))
cr.execute('update wkf_workitem set state=%s where id=%s', (state,workitem['id']))
workitem['state'] = state
wkf_logs.log(cr,ident,activity['id'],state)
@ -89,7 +89,7 @@ def _execute(cr, workitem, activity, ident, stack):
# send a signal to parent workflow (signal: subflow.signal_name)
#
if (workitem['state']=='active') and activity['signal_send']:
cr.execute("select i.id,w.osv,i.res_id from wkf_instance i left join wkf w on (i.wkf_id=w.id) where i.id in (select inst_id from wkf_workitem where subflow_id=%d)", (workitem['inst_id'],))
cr.execute("select i.id,w.osv,i.res_id from wkf_instance i left join wkf w on (i.wkf_id=w.id) where i.id in (select inst_id from wkf_workitem where subflow_id=%s)", (workitem['inst_id'],))
for i in cr.fetchall():
instance.validate(cr, i[0], (ident[0],i[1],i[2]), activity['signal_send'], force_running=True)
@ -97,7 +97,6 @@ def _execute(cr, workitem, activity, ident, stack):
if workitem['state']=='active':
_state_set(cr, workitem, activity, 'complete', ident)
if activity['action_id']:
print 'ICI'
res2 = wkf_expr.execute_action(cr, ident, workitem, activity)
if res2:
stack.append(res2)
@ -116,7 +115,7 @@ def _execute(cr, workitem, activity, ident, stack):
elif activity['kind']=='stopall':
if workitem['state']=='active':
_state_set(cr, workitem, activity, 'running', ident)
cr.execute('delete from wkf_workitem where inst_id=%d and id<>%d', (workitem['inst_id'], workitem['id']))
cr.execute('delete from wkf_workitem where inst_id=%s and id<>%s', (workitem['inst_id'], workitem['id']))
if activity['action']:
wkf_expr.execute(cr, ident, workitem, activity)
_state_set(cr, workitem, activity, 'complete', ident)
@ -129,14 +128,14 @@ def _execute(cr, workitem, activity, ident, stack):
cr.execute('delete from wkf_workitem where id=%s', (workitem['id'],))
return False
assert type(id_new)==type(1) or type(id_new)==type(1L), 'Wrong return value: '+str(id_new)+' '+str(type(id_new))
cr.execute('select id from wkf_instance where res_id=%d and wkf_id=%d', (id_new,activity['subflow_id']))
cr.execute('select id from wkf_instance where res_id=%s and wkf_id=%s', (id_new,activity['subflow_id']))
id_new = cr.fetchone()[0]
else:
id_new = instance.create(cr, ident, activity['subflow_id'])
cr.execute('update wkf_workitem set subflow_id=%d where id=%s', (id_new, workitem['id']))
cr.execute('update wkf_workitem set subflow_id=%s where id=%s', (id_new, workitem['id']))
workitem['subflow_id'] = id_new
if workitem['state']=='running':
cr.execute("select state from wkf_instance where id=%d", (workitem['subflow_id'],))
cr.execute("select state from wkf_instance where id=%s", (workitem['subflow_id'],))
state= cr.fetchone()[0]
if state=='complete':
_state_set(cr, workitem, activity, 'complete', ident)
@ -145,7 +144,7 @@ def _execute(cr, workitem, activity, ident, stack):
def _split_test(cr, workitem, split_mode, ident, signal=None, stack=None):
if stack is None:
raise 'Error !!!'
cr.execute('select * from wkf_transition where act_from=%d', (workitem['act_id'],))
cr.execute('select * from wkf_transition where act_from=%s', (workitem['act_id'],))
test = False
transitions = []
alltrans = cr.dictfetchall()
@ -162,36 +161,36 @@ def _split_test(cr, workitem, split_mode, ident, signal=None, stack=None):
if not wkf_expr.check(cr, workitem, ident, transition,signal):
test = False
break
cr.execute('select count(*) from wkf_witm_trans where trans_id=%d and inst_id=%d', (transition['id'], workitem['inst_id']))
cr.execute('select count(*) from wkf_witm_trans where trans_id=%s and inst_id=%s', (transition['id'], workitem['inst_id']))
if not cr.fetchone()[0]:
transitions.append((transition['id'], workitem['inst_id']))
if test and len(transitions):
cr.executemany('insert into wkf_witm_trans (trans_id,inst_id) values (%d,%d)', transitions)
cr.execute('delete from wkf_workitem where id=%d', (workitem['id'],))
cr.executemany('insert into wkf_witm_trans (trans_id,inst_id) values (%s,%s)', transitions)
cr.execute('delete from wkf_workitem where id=%s', (workitem['id'],))
for t in transitions:
_join_test(cr, t[0], t[1], ident, stack)
return True
return False
def _join_test(cr, trans_id, inst_id, ident, stack):
cr.execute('select * from wkf_activity where id=(select act_to from wkf_transition where id=%d)', (trans_id,))
cr.execute('select * from wkf_activity where id=(select act_to from wkf_transition where id=%s)', (trans_id,))
activity = cr.dictfetchone()
if activity['join_mode']=='XOR':
create(cr,[activity], inst_id, ident, stack)
cr.execute('delete from wkf_witm_trans where inst_id=%d and trans_id=%d', (inst_id,trans_id))
cr.execute('delete from wkf_witm_trans where inst_id=%s and trans_id=%s', (inst_id,trans_id))
else:
cr.execute('select id from wkf_transition where act_to=%d', (activity['id'],))
cr.execute('select id from wkf_transition where act_to=%s', (activity['id'],))
trans_ids = cr.fetchall()
ok = True
for (id,) in trans_ids:
cr.execute('select count(*) from wkf_witm_trans where trans_id=%d and inst_id=%d', (id,inst_id))
cr.execute('select count(*) from wkf_witm_trans where trans_id=%s and inst_id=%s', (id,inst_id))
res = cr.fetchone()[0]
if not res:
ok = False
break
if ok:
for (id,) in trans_ids:
cr.execute('delete from wkf_witm_trans where trans_id=%d and inst_id=%d', (id,inst_id))
cr.execute('delete from wkf_witm_trans where trans_id=%s and inst_id=%s', (id,inst_id))
create(cr, [activity], inst_id, ident, stack)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -54,7 +54,7 @@ execfile(opj('bin', 'release.py'))
py_short_version = '%s.%s' % sys.version_info[:2]
required_modules = [
('psycopg', 'PostgreSQL module'),
('psycopg2', 'PostgreSQL module'),
('xml', 'XML Tools for python'),
('libxml2', 'libxml2 python bindings'),
('libxslt', 'libxslt python bindings'),