1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ##############################################################################
22 import openerp.netsvc as netsvc
23 from openerp.tools import copy
24 from openerp.tools.misc import UpdateableStr, UpdateableDict
25 from openerp.tools.translate import translate
26 from lxml import etree
28 import openerp.pooler as pooler
30 from openerp.osv.osv import except_osv
31 from openerp.osv.orm import except_orm
32 from openerp.netsvc import Logger, LOG_ERROR
36 class except_wizard(Exception):
37 def __init__(self, name, value):
40 self.args = (name, value)
42 class interface(netsvc.Service):
44 This is the base class used to implement Wizards. This class is deprecated
45 and `openerp.osv.TransientModel` must be used instead.
49 def __init__(self, name):
50 assert not self.exists('wizard.'+name), 'The wizard "%s" already exists!' % (name,)
52 "The wizard %s uses the deprecated openerp.wizard.interface class.\n"
53 "It must use the openerp.osv.TransientModel class instead." % \
54 name, DeprecationWarning, stacklevel=3)
55 super(interface, self).__init__('wizard.'+name)
58 def translate_view(self, cr, node, state, lang):
59 if node.get('string'):
60 trans = translate(cr, self.wiz_name+','+state, 'wizard_view', lang, node.get('string').encode('utf8'))
62 node.set('string', trans)
64 self.translate_view(cr, n, state, lang)
66 def execute_cr(self, cr, uid, data, state='init', context=None):
71 state_def = self.states[state]
73 result_def = state_def.get('result', {})
76 # iterate through the list of actions defined for this state
77 for action in state_def.get('actions', []):
79 action_res = action(self, cr, uid, data, context)
80 assert isinstance(action_res, dict), 'The return value of wizard actions should be a dictionary'
81 actions_res.update(action_res)
83 res = copy.copy(result_def)
84 res['datas'] = actions_res
86 lang = context.get('lang', False)
87 if result_def['type'] == 'action':
88 res['action'] = result_def['action'](self, cr, uid, data, context)
89 elif result_def['type'] == 'form':
90 fields = copy.deepcopy(result_def['fields'])
91 arch = copy.copy(result_def['arch'])
92 button_list = copy.copy(result_def['state'])
94 if isinstance(fields, UpdateableDict):
96 if isinstance(arch, UpdateableStr):
99 # fetch user-set defaut values for the field... shouldn't we pass it the uid?
100 ir_values_obj = pooler.get_pool(cr.dbname).get('ir.values')
101 defaults = ir_values_obj.get(cr, uid, 'default', False, [('wizard.'+self.wiz_name, False)])
102 default_values = dict([(x[1], x[2]) for x in defaults])
103 for val in fields.keys():
104 if 'default' in fields[val]:
105 # execute default method for this field
106 if callable(fields[val]['default']):
107 fields[val]['value'] = fields[val]['default'](uid, data, state)
109 fields[val]['value'] = fields[val]['default']
110 del fields[val]['default']
112 # if user has set a default value for the field, use it
113 if val in default_values:
114 fields[val]['value'] = default_values[val]
115 if 'selection' in fields[val]:
116 if not isinstance(fields[val]['selection'], (tuple, list)):
117 fields[val] = copy.copy(fields[val])
118 fields[val]['selection'] = fields[val]['selection'](self, cr, uid, context)
120 res_name = "%s,%s,%s" % (self.wiz_name, state, val)
121 trans = lambda x: translate(cr, res_name, 'selection', lang, x) or x
122 for idx, (key, val2) in enumerate(fields[val]['selection']):
123 fields[val]['selection'][idx] = (key, trans(val2))
128 res_name = "%s,%s,%s" % (self.wiz_name, state, field)
130 trans = translate(cr, res_name, 'wizard_field', lang)
132 fields[field]['string'] = trans
134 if 'help' in fields[field]:
135 t = translate(cr, res_name, 'help', lang, fields[field]['help'])
137 fields[field]['help'] = t
140 if not isinstance(arch, UpdateableStr):
141 doc = etree.XML(arch)
142 self.translate_view(cr, doc, state, lang)
143 arch = etree.tostring(doc)
146 button_list = list(button_list)
147 for i, aa in enumerate(button_list):
149 trans = translate(cr, self.wiz_name+','+state+','+button_name, 'wizard_button', lang)
155 res['fields'] = fields
157 res['state'] = button_list
159 elif result_def['type'] == 'choice':
160 next_state = result_def['next_state'](self, cr, uid, data, context)
161 return self.execute_cr(cr, uid, data, next_state, context)
164 if isinstance(e, except_wizard) \
165 or isinstance(e, except_osv) \
166 or isinstance(e, except_orm):
167 netsvc.abort_response(2, e.name, 'warning', e.value)
170 tb_s = reduce(lambda x, y: x+y, traceback.format_exception(
171 sys.exc_type, sys.exc_value, sys.exc_traceback))
173 logger.notifyChannel("web-services", LOG_ERROR,
174 'Exception in call: ' + tb_s)
179 def execute(self, db, uid, data, state='init', context=None):
182 cr = pooler.get_db(db).cursor()
185 res = self.execute_cr(cr, uid, data, state, context)
194 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: