Files
tryton/trytond/wizard/wizard.py
T

343 lines
12 KiB
Python

#This file is part of Tryton. The COPYRIGHT file at the top level of this repository contains the full copyright notices and license terms.
"Wizard"
from trytond.netsvc import Service, service_exist, Logger, LOG_ERROR
from trytond import pooler
import copy
from xml import dom
from trytond.osv import OSV
from trytond.config import CONFIG
import sys
from trytond.sql_db import IntegrityError
import traceback
MODULE_LIST = []
MODULE_CLASS_LIST = {}
CLASS_POOL = {}
class WizardService(Service):
def __init__(self):
self.object_name_pool = {}
self.module_obj_list = {}
Service.__init__(self, 'wizard_proxy')
Service.join_group(self, 'web-service')
Service.export_method(self, self.execute)
def execute_cr(self, cursor, user, wizard_name, data, state='init',
context=None):
try:
wizard = pooler.get_pool_wizard(cursor.dbname).get(wizard_name)
if not wizard:
raise Exception('Error',
'Wizard %s doesn\'t exist' % str(wizard_name))
res = wizard.execute(cursor, user, data, state, context)
return res
except Exception, exception:
if CONFIG['verbose']:
tb_s = reduce(lambda x, y: x+y,
traceback.format_exception(*sys.exc_info()))
Logger().notify_channel("web-service", LOG_ERROR,
'Exception in call: ' + tb_s)
if isinstance(exception, IntegrityError):
pool = pooler.get_pool(cursor.dbname)
for key in pool._sql_errors.keys():
if key in exception[0]:
msg = pool._sql_errors[key]
cursor2 = pooler.get_db(cursor.dbname).cursor()
if context is None:
context = {}
try:
cursor2.execute('SELECT value ' \
'FROM ir_translation ' \
'WHERE lang=%s ' \
'AND type=%s ' \
'AND src=%s',
(context.get('language', 'en_US'), 'error',
msg))
if cursor2.rowcount:
res = cursor2.fetchone()[0]
if res:
msg = res
finally:
cursor2.close()
raise Exception('UserError', 'Constraint Error',
msg)
raise
def execute(self, dbname, user, wizard_name, data, state='init',
context=None):
cursor = pooler.get_db(dbname).cursor()
pool = pooler.get_pool_wizard(dbname)
try:
try:
res = pool.execute_cr(cursor, user, wizard_name, data, state,
context)
cursor.commit()
except Exception:
cursor.rollback()
raise
finally:
cursor.close()
return res
def add(self, name, object_name_inst):
"""
adds a new obj instance to the obj pool.
if it already existed, the instance is replaced
"""
if self.object_name_pool.has_key(name):
del self.object_name_pool[name]
self.object_name_pool[name] = object_name_inst
module = str(object_name_inst.__class__)[6:]
module = module[:len(module)-1]
module = module.split('.')[0][2:]
self.module_obj_list.setdefault(module, []).append(object_name_inst)
def get(self, name):
return self.object_name_pool.get(name, None)
def instanciate(self, module, pool_obj):
res = []
class_list = MODULE_CLASS_LIST.get(module, [])
for klass in class_list:
res.append(klass.create_instance(self, module, pool_obj))
return res
class Wizard(object):
_name = ""
states = {}
def __new__(cls):
for module in cls.__module__.split('.'):
if module != 'trytond' and module != 'modules':
break
if not hasattr(cls, '_module'):
cls._module = module
MODULE_CLASS_LIST.setdefault(cls._module, []).append(cls)
CLASS_POOL[cls._name] = cls
if module not in MODULE_LIST:
MODULE_LIST.append(cls._module)
return None
def create_instance(cls, pool, module, pool_obj):
"""
try to apply inheritancy at the instanciation level and
put objs in the pool var
"""
if pool.get(cls._name):
parent_class = pool.get(cls._name).__class__
cls = type(cls._name, (cls, parent_class), {})
obj = object.__new__(cls)
pool.add(obj._name, obj)
obj.pool = pool_obj
obj.__init__()
return obj
create_instance = classmethod(create_instance)
def __init__(self):
super(Wizard, self).__init__()
self._error_messages = {}
def auto_init(self, cursor, module_name):
for state in self.states.keys():
if self.states[state]['result']['type'] == 'form':
for i, button in enumerate(
self.states[state]['result']['state']):
button_name = button[0]
button_value = button[1]
cursor.execute('SELECT id, name, src ' \
'FROM ir_translation ' \
'WHERE module = %s ' \
'AND lang = %s ' \
'AND type = %s ' \
'AND name = %s',
(module_name, 'en_US', 'wizard_button',
self._name + ',' + state + ',' + button_name))
res = cursor.dictfetchall()
if not res:
cursor.execute('INSERT INTO ir_translation ' \
'(name, lang, type, src, value, module, fuzzy) ' \
'VALUES (%s, %s, %s, %s, %s, %s, false)',
(self._name + ',' + state + ',' + button_name,
'en_US', 'wizard_button', button_value,
'', module_name))
elif res[0]['src'] != button_value:
cursor.execute('UPDATE ir_translation ' \
'SET src = %s, ' \
'fuzzy = True '
'WHERE id = %s', (button_value, res[0]['id']))
cursor.execute('SELECT id, src FROM ir_translation ' \
'WHERE lang = %s ' \
'AND type = %s ' \
'AND name = %s',
('en_US', 'error', self._name))
trans_error = {}
for trans in cursor.dictfetchall():
trans_error[trans['src']] = trans
for error in self._error_messages.values():
if error not in trans_error:
cursor.execute('INSERT INTO ir_translation ' \
'(name, lang, type, src, value, module, fuzzy) ' \
'VALUES (%s, %s, %s, %s, %s, %s, false)',
(self._name, 'en_US', 'error', error, '', module_name))
def raise_user_error(self, cursor, error, error_args=None,
error_description='', error_description_args=None, context=None):
translation_obj = self.pool.get('ir.translation')
if context is None:
context = {}
error = self._error_messages.get(error, error)
res = translation_obj._get_source(cursor, self._name, 'error',
context.get('language', 'en_US'), error)
if res:
error = res
if error_args:
error = error % error_args
if error_description:
error_description = self._error_messages.get(error_description,
error_description)
res = translation_obj._get_source(cursor, self._name, 'error',
context.get('language', 'en_US'), error_description)
if res:
error_description = res
if error_description_args:
error_description = error_description % error_description_args
raise Exception('UserError', error, error_description)
raise Exception('UserError', error)
def execute(self, cursor, user, data, state='init', context=None):
if context is None:
context = {}
res = {}
translation_obj = self.pool.get('ir.translation')
state_def = self.states[state]
result_def = state_def.get('result', {})
actions_res = {}
# iterate through the list of actions defined for this state
for action in state_def.get('actions', []):
# execute them
action_res = getattr(self, action)(cursor, user, data, context)
assert isinstance(action_res, dict), \
'The return value of wizard actions ' \
'should be a dictionary'
actions_res.update(action_res)
res = copy.copy(result_def)
if state_def.get('actions'):
res['datas'] = actions_res
lang = context.get('language', 'en_US')
if result_def['type'] == 'action':
res['action'] = getattr(self, result_def['action'])(cursor, user,
data, context)
elif result_def['type'] == 'form':
obj = self.pool.get(result_def['object'])
view = obj.fields_view_get(cursor, user, view_type='form',
context=context, toolbar=False)
fields = view['fields']
arch = view['arch']
button_list = copy.copy(result_def['state'])
default_values = obj.default_get(cursor, user, fields.keys(),
context=context)
for field in default_values.keys():
fields[field]['value'] = default_values[field]
# translate buttons
for i, button in enumerate(button_list):
button_name = button[0]
res_trans = translation_obj._get_source(cursor, user,
self._name + ',' + state + ',' + button_name,
'wizard_button', lang)
if res_trans:
button = list(button)
button[1] = res_trans
button_list[i] = tuple(button)
res['fields'] = fields
res['arch'] = arch
res['state'] = button_list
elif result_def['type'] == 'choice':
next_state = getattr(self, result_def['next_state'])(cursor, user,
data, context)
if next_state == 'end':
return {'type': 'state', 'state': 'end'}
return self.execute(cursor, user, data, next_state, context)
return res
class WizardOSV(OSV):
"""
Object to use for wizard state
"""
_protected = [
'default_get',
'fields_get',
'fields_view_get',
]
_auto = False
def auto_init(self, cursor, module_name):
pass
def init(self, cursor):
pass
def browse(self, cursor, user, select, context=None):
pass
def export_data(self, cursor, user, ids, fields_name, context=None):
pass
def import_data(self, cursor, fields_names, datas, mode='init',
current_module=None, noupdate=False, context=None):
pass
def read(self, cursor, ids, fields_names=None, context=None,
load='_classic_read'):
pass
def delete(self, cursor, user, ids, context=None):
pass
def write(self, cursor, user, ids, vals, context=None):
pass
def create(self, cursor, user, vals, context=None):
pass
def search_count(self, cursor, user, args, context=None):
pass
def search(self, cursor, user, args, offset=0, limit=None, order=None,
context=None, count=False, query_string=False):
pass
def name_get(self, cursor, user, ids, context=None):
pass
def name_search(self, cursor, user, name='', args=None, operator='ilike',
context=None, limit=80):
pass
def copy(self, cursor, user, object_id, default=None, context=None):
pass