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,17 +246,24 @@ 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()
#
@ -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
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, 'addon object %s (%s) has no access rules!' % (model,name))
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')
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])
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)
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['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,17 +589,13 @@ 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
#
while True:
cr.execute('''delete from
ir_ui_menu
where
@ -582,10 +604,14 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
(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
}
if action.state == 'other':
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,8 +573,18 @@ class actions_server(osv.osv):
else:
expr = exp.value
res[exp.col1.name] = expr
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 = {}
@ -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':
res_id = False
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 = 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,19 +25,15 @@ 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):
@ -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),
@ -232,7 +234,25 @@ class ir_model_fields(osv.osv):
#
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,12 +82,56 @@ 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"
_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()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

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" />
<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" />
<newline />
<label string="" /><button name="validate_cb" type="object" string="Validate" />
<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] = ''
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

@ -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">
<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="P7">[[ repeatIn(findflds(object.model), 'field') ]] <i>[[ field[0] ]]</i></para>
<para style="terp_default_9">[[ field[0] ]]</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>
<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="Standard">
<para style="terp_default_1">
<font color="white"> </font>
</para>
</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>
</section>
</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

@ -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>
@ -135,6 +179,7 @@
<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,6 +321,7 @@
<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" />
@ -271,6 +330,7 @@
<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"/>
@ -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

@ -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))
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,))
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()
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,))
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
try:
cr.execute("ALTER TABLE \"%s\" ALTER COLUMN \"%s\" SET NOT NULL" % (self._table, k))
cr.commit()
except:
try:
cr.execute('ALTER TABLE "%s" ALTER COLUMN "%s" SET NOT NULL' % (self._table, k))
cr.commit()
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)
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 = []
if self._columns[field]._multi:
value = value[field]
if self._columns[field]._type in ('many2one', 'one2one'):
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
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)
'"'+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:
# 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)
db_dic[db_name] = db
return db
def get_db(db_name):
# print "get_db", db_name
return get_db_and_pool(db_name)[0]
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

@ -86,20 +86,13 @@ class report_rml(report_int):
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:
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)
# assume format '%Y-%m-%d %H:%M:%S'
value = str(value)[:19]
date = mx.DateTime.strptime(str(value),DHM_FORMAT)
else:
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 __init__(self, db, con, dbname):
self.db = db
self.obj = db.cursor()
self.con = con
self.dbname = dbname
def check(f):
from tools.func import wraps
def execute(self, sql, params=None):
if not params:
@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 __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]
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]
print "SUM:%s/%d"% (sum, self.count)
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):
timeb4 = time.time()
res = f(*args, **kwargs)
log(f, res, *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
return wrapper
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
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'),