[FIX] base_gengo: remove sandbox flag, improve inconsistent labels on gengo wizard...
[odoo/odoo.git] / openerp / wizard / __init__.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #    
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
6 #
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.
11 #
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.
16 #
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/>.     
19 #
20 ##############################################################################
21
22 import copy
23 import logging
24
25 import openerp.netsvc as netsvc
26 from openerp.tools.misc import UpdateableStr, UpdateableDict
27 from openerp.tools.translate import translate
28 from lxml import etree
29
30 import openerp.pooler as pooler
31
32 from openerp.osv.osv import except_osv
33 from openerp.osv.orm import except_orm
34
35 _logger = logging.getLogger(__name__)
36
37 class except_wizard(Exception):
38     def __init__(self, name, value):
39         self.name = name
40         self.value = value
41         self.args = (name, value)
42
43 class interface(netsvc.Service):
44     """
45     This is the base class used to implement Wizards. This class is deprecated
46     and `openerp.osv.TransientModel` must be used instead.
47     """
48     states = {}
49
50     def __init__(self, name):
51         assert not self.exists('wizard.'+name), 'The wizard "%s" already exists!' % (name,)
52         _logger.warning(
53             "The wizard %s uses the deprecated openerp.wizard.interface class.\n"
54             "It must use the openerp.osv.TransientModel class instead." % \
55             name)
56         super(interface, self).__init__('wizard.'+name)
57         self.wiz_name = name
58
59     def translate_view(self, cr, node, state, lang):
60         if node.get('string'):
61             trans = translate(cr, self.wiz_name+','+state, 'wizard_view', lang, node.get('string').encode('utf8'))
62             if trans:
63                 node.set('string', trans)
64         for n in node:
65             self.translate_view(cr, n, state, lang)
66
67     def execute_cr(self, cr, uid, data, state='init', context=None):
68         if not context:
69             context={}
70         res = {}
71         try:
72             state_def = self.states[state]
73
74             result_def = state_def.get('result', {})
75             
76             actions_res = {}
77             # iterate through the list of actions defined for this state
78             for action in state_def.get('actions', []):
79                 # execute them
80                 action_res = action(self, cr, uid, data, context)
81                 assert isinstance(action_res, dict), 'The return value of wizard actions should be a dictionary'
82                 actions_res.update(action_res)
83                 
84             res = copy.copy(result_def)
85             res['datas'] = actions_res
86             
87             lang = context.get('lang', False)
88             if result_def['type'] == 'action':
89                 res['action'] = result_def['action'](self, cr, uid, data, context)
90             elif result_def['type'] == 'form':
91                 fields = copy.deepcopy(result_def['fields'])
92                 arch = copy.copy(result_def['arch'])
93                 button_list = copy.copy(result_def['state'])
94
95                 if isinstance(fields, UpdateableDict):
96                     fields = fields.dict
97                 if isinstance(arch, UpdateableStr):
98                     arch = arch.string
99
100                 # fetch user-set defaut values for the field... shouldn't we pass it the uid?
101                 ir_values_obj = pooler.get_pool(cr.dbname).get('ir.values')
102                 defaults = ir_values_obj.get(cr, uid, 'default', False, [('wizard.'+self.wiz_name, False)])
103                 default_values = dict([(x[1], x[2]) for x in defaults])
104                 for val in fields.keys():
105                     if 'default' in fields[val]:
106                         # execute default method for this field
107                         if callable(fields[val]['default']):
108                             fields[val]['value'] = fields[val]['default'](uid, data, state)
109                         else:
110                             fields[val]['value'] = fields[val]['default']
111                         del fields[val]['default']
112                     else:
113                         # if user has set a default value for the field, use it
114                         if val in default_values:
115                             fields[val]['value'] = default_values[val]
116                     if 'selection' in fields[val]:
117                         if not isinstance(fields[val]['selection'], (tuple, list)):
118                             fields[val] = copy.copy(fields[val])
119                             fields[val]['selection'] = fields[val]['selection'](self, cr, uid, context)
120                         elif lang:
121                             res_name = "%s,%s,%s" % (self.wiz_name, state, val)
122                             trans = lambda x: translate(cr, res_name, 'selection', lang, x) or x
123                             for idx, (key, val2) in enumerate(fields[val]['selection']):
124                                 fields[val]['selection'][idx] = (key, trans(val2))
125
126                 if lang:
127                     # translate fields
128                     for field in fields:
129                         res_name = "%s,%s,%s" % (self.wiz_name, state, field)
130
131                         trans = translate(cr, res_name, 'wizard_field', lang)
132                         if trans:
133                             fields[field]['string'] = trans
134
135                         if 'help' in fields[field]:
136                             t = translate(cr, res_name, 'help', lang, fields[field]['help']) 
137                             if t:
138                                 fields[field]['help'] = t
139
140                     # translate arch
141                     if not isinstance(arch, UpdateableStr):
142                         doc = etree.XML(arch)
143                         self.translate_view(cr, doc, state, lang)
144                         arch = etree.tostring(doc)
145
146                     # translate buttons
147                     button_list = list(button_list)
148                     for i, aa  in enumerate(button_list):
149                         button_name = aa[0]
150                         trans = translate(cr, self.wiz_name+','+state+','+button_name, 'wizard_button', lang)
151                         if trans:
152                             aa = list(aa)
153                             aa[1] = trans
154                             button_list[i] = aa
155                     
156                 res['fields'] = fields
157                 res['arch'] = arch
158                 res['state'] = button_list
159
160             elif result_def['type'] == 'choice':
161                 next_state = result_def['next_state'](self, cr, uid, data, context)
162                 return self.execute_cr(cr, uid, data, next_state, context)
163         
164         except Exception, e:
165             if isinstance(e, except_wizard) \
166                 or isinstance(e, except_osv) \
167                 or isinstance(e, except_orm):
168                 netsvc.abort_response(2, e.name, 'warning', e.value)
169             else:
170                 _logger.exception('Exception in call:')
171                 raise
172
173         return res
174
175     def execute(self, db, uid, data, state='init', context=None):
176         if not context:
177             context={}
178         cr = pooler.get_db(db).cursor()
179         try:
180             try:
181                 res = self.execute_cr(cr, uid, data, state, context)
182                 cr.commit()
183             except Exception:
184                 cr.rollback()
185                 raise
186         finally:
187             cr.close()
188         return res
189
190 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
191