Merge lp:~unifield-team/unifield-server/uf-1267 into lp:unifield-server

Proposed by jftempo
Status: Merged
Merged at revision: 3410
Proposed branch: lp:~unifield-team/unifield-server/uf-1267
Merge into: lp:unifield-server
Diff against target: 494 lines (+126/-64)
3 files modified
bin/addons/base/ir/ir_actions.py (+56/-50)
bin/addons/base/res/res_config.py (+65/-13)
bin/addons/base/res/res_config.xml (+5/-1)
To merge this branch: bzr merge lp:~unifield-team/unifield-server/uf-1267
Reviewer Review Type Date Requested Status
UniField Dev Team Pending
Review via email: mp+123583@code.launchpad.net
To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/addons/base/ir/ir_actions.py'
2--- bin/addons/base/ir/ir_actions.py 2012-08-09 14:11:55 +0000
3+++ bin/addons/base/ir/ir_actions.py 2012-09-10 15:46:26 +0000
4@@ -19,7 +19,7 @@
5 #
6 ##############################################################################
7
8-from osv import fields,osv
9+from osv import fields, osv
10 from tools.safe_eval import safe_eval as eval
11 import tools
12 import time
13@@ -39,7 +39,7 @@
14 _order = 'name'
15 _columns = {
16 'name': fields.char('Action Name', required=True, size=64),
17- 'type': fields.char('Action Type', required=True, size=32,readonly=True),
18+ 'type': fields.char('Action Type', required=True, size=32, readonly=True),
19 'usage': fields.char('Action Usage', size=32),
20 }
21 _defaults = {
22@@ -68,7 +68,7 @@
23 return res
24
25 def _report_content_inv(self, cursor, user, id, name, value, arg, context=None):
26- self.write(cursor, user, id, {name+'_data': value}, context=context)
27+ self.write(cursor, user, id, {name + '_data': value}, context=context)
28
29 def _report_sxw(self, cursor, user, ids, name, arg, context=None):
30 res = {}
31@@ -90,15 +90,15 @@
32 result = cr.dictfetchall()
33 svcs = netsvc.Service._services
34 for r in result:
35- if svcs.has_key('report.'+r['report_name']):
36+ if svcs.has_key('report.' + r['report_name']):
37 continue
38 if r['report_rml'] or r['report_rml_content_data']:
39- report_sxw('report.'+r['report_name'], r['model'],
40- opj('addons',r['report_rml'] or '/'), header=r['header'])
41+ report_sxw('report.' + r['report_name'], r['model'],
42+ opj('addons', r['report_rml'] or '/'), header=r['header'])
43 if r['report_xsl']:
44- report_rml('report.'+r['report_name'], r['model'],
45- opj('addons',r['report_xml']),
46- r['report_xsl'] and opj('addons',r['report_xsl']))
47+ report_rml('report.' + r['report_name'], r['model'],
48+ opj('addons', r['report_xml']),
49+ r['report_xsl'] and opj('addons', r['report_xsl']))
50
51 _name = 'ir.actions.report.xml'
52 _table = 'ir_act_report_xml'
53@@ -164,15 +164,15 @@
54 return _('Invalid model name in the action definition.')
55
56 _constraints = [
57- (_check_model, _invalid_model_msg, ['res_model','src_model'])
58+ (_check_model, _invalid_model_msg, ['res_model', 'src_model'])
59 ]
60
61 def _views_get_fnc(self, cr, uid, ids, name, arg, context=None):
62- res={}
63+ res = {}
64 for act in self.browse(cr, uid, ids):
65- res[act.id]=[(view.view_id.id, view.view_mode) for view in act.view_ids]
66+ res[act.id] = [(view.view_id.id, view.view_mode) for view in act.view_ids]
67 modes = act.view_mode.split(',')
68- if len(modes)>len(act.view_ids):
69+ if len(modes) > len(act.view_ids):
70 find = False
71 if act.view_id:
72 res[act.id].append((act.view_id.id, act.view_id.type))
73@@ -195,9 +195,9 @@
74 if act.search_view_id:
75 search_view_id = act.search_view_id.id
76 else:
77- res_view = self.pool.get('ir.ui.view').search(cr, uid,
78- [('model','=',act.res_model),('type','=','search'),
79- ('inherit_id','=',False)], context=context)
80+ res_view = self.pool.get('ir.ui.view').search(cr, uid,
81+ [('model', '=', act.res_model), ('type', '=', 'search'),
82+ ('inherit_id', '=', False)], context=context)
83 if res_view:
84 search_view_id = res_view[0]
85 if search_view_id:
86@@ -209,8 +209,8 @@
87 else:
88 def process_child(node, new_node, doc):
89 for child in node.childNodes:
90- if child.localName=='field' and child.hasAttribute('select') \
91- and child.getAttribute('select')=='1':
92+ if child.localName == 'field' and child.hasAttribute('select') \
93+ and child.getAttribute('select') == '1':
94 if child.childNodes:
95 fld = doc.createElement('field')
96 for attr in child.attributes.keys():
97@@ -218,7 +218,7 @@
98 new_node.appendChild(fld)
99 else:
100 new_node.appendChild(child)
101- elif child.localName in ('page','group','notebook'):
102+ elif child.localName in ('page', 'group', 'notebook'):
103 process_child(child, new_node, doc)
104
105 form_arch = self.pool.get(act.res_model).fields_view_get(cr, uid, False, 'form', context)
106@@ -227,7 +227,7 @@
107 for child_node in new_node.childNodes[0].childNodes:
108 if child_node.nodeType == child_node.ELEMENT_NODE:
109 new_node.childNodes[0].removeChild(child_node)
110- process_child(dom_arc.childNodes[0],new_node.childNodes[0],dom_arc)
111+ process_child(dom_arc.childNodes[0], new_node.childNodes[0], dom_arc)
112
113 form_arch['arch'] = new_node.toxml()
114 form_arch['fields'].update(fields_from_fields_get)
115@@ -250,8 +250,8 @@
116 help="Model name of the object to open in the view window"),
117 'src_model': fields.char('Source Object', size=64,
118 help="Optional model name of the objects on which this action should be visible"),
119- 'target': fields.selection([('current','Current Window'),('new','New Window')], 'Target Window'),
120- 'view_type': fields.selection((('tree','Tree'),('form','Form')), string='View Type', required=True,
121+ 'target': fields.selection([('current', 'Current Window'), ('new', 'New Window')], 'Target Window'),
122+ 'view_type': fields.selection((('tree', 'Tree'), ('form', 'Form')), string='View Type', required=True,
123 help="View type: set to 'tree' for a hierarchical tree view, or 'form' for other views"),
124 'view_mode': fields.char('View Mode', size=250, required=True,
125 help="Comma-separated list of allowed view modes, such as 'form', 'tree', 'calendar', etc. (Default: tree,form)"),
126@@ -356,7 +356,7 @@
127 _columns = {
128 'name': fields.char('Action Name', size=64, translate=True),
129 'type': fields.char('Action Type', size=32, required=True),
130- 'url': fields.text('Action URL',required=True),
131+ 'url': fields.text('Action URL', required=True),
132 'target': fields.selection((
133 ('new', 'New Window'),
134 ('self', 'This Window')),
135@@ -378,7 +378,7 @@
136 mpool = self.pool.get('ir.model')
137 for osv in osvs:
138 model = osv.get('osv')
139- id = mpool.search(cr, uid, [('model','=',model)])
140+ id = mpool.search(cr, uid, [('model', '=', model)])
141 name = mpool.read(cr, uid, id)[0]['name']
142 res.append((model, name))
143
144@@ -400,8 +400,8 @@
145 'col1': fields.many2one('ir.model.fields', 'Destination', required=True),
146 'value': fields.text('Value', required=True),
147 'type': fields.selection([
148- ('value','Value'),
149- ('equation','Formula')
150+ ('value', 'Value'),
151+ ('equation', 'Formula')
152 ], 'Type', required=True, size=32, change_default=True),
153 }
154 _defaults = {
155@@ -428,15 +428,15 @@
156
157 def _select_objects(self, cr, uid, context=None):
158 model_pool = self.pool.get('ir.model')
159- ids = model_pool.search(cr, uid, [('name','not ilike','.')])
160+ ids = model_pool.search(cr, uid, [('name', 'not ilike', '.')])
161 res = model_pool.read(cr, uid, ids, ['model', 'name'])
162- return [(r['model'], r['name']) for r in res] + [('','')]
163+ return [(r['model'], r['name']) for r in res] + [('', '')]
164
165 def change_object(self, cr, uid, ids, copy_object, state, context=None):
166 if state == 'object_copy':
167 model_pool = self.pool.get('ir.model')
168 model = copy_object.split(',')[0]
169- mid = model_pool.search(cr, uid, [('model','=',model)])
170+ mid = model_pool.search(cr, uid, [('model', '=', model)])
171 return {
172 'value':{'srcmodel_id':mid[0]},
173 'context':context
174@@ -452,17 +452,17 @@
175 'name': fields.char('Action Name', required=True, size=64, help="Easy to Refer action by name e.g. One Sales Order -> Many Invoices", translate=True),
176 'condition' : fields.char('Condition', size=256, required=True, help="Condition that is to be tested before action is executed, e.g. object.list_price > object.cost_price"),
177 'state': fields.selection([
178- ('client_action','Client Action'),
179- ('dummy','Dummy'),
180- ('loop','Iteration'),
181- ('code','Python Code'),
182- ('trigger','Trigger'),
183- ('email','Email'),
184- ('sms','SMS'),
185- ('object_create','Create Object'),
186- ('object_copy','Copy Object'),
187- ('object_write','Write Object'),
188- ('other','Multi Actions'),
189+ ('client_action', 'Client Action'),
190+ ('dummy', 'Dummy'),
191+ ('loop', 'Iteration'),
192+ ('code', 'Python Code'),
193+ ('trigger', 'Trigger'),
194+ ('email', 'Email'),
195+ ('sms', 'SMS'),
196+ ('object_create', 'Create Object'),
197+ ('object_copy', 'Copy Object'),
198+ ('object_write', 'Write Object'),
199+ ('other', 'Multi Actions'),
200 ], 'Action Type', required=True, size=32, help="Type of the Action that is to be executed"),
201 'code':fields.text('Python Code', help="Python code to be executed"),
202 'sequence': fields.integer('Sequence', help="Important when you deal with multiple actions, the execution order will be decided based on this, low number is higher priority."),
203@@ -470,7 +470,7 @@
204 'action_id': fields.many2one('ir.actions.actions', 'Client Action', help="Select the Action Window, Report, Wizard to be executed."),
205 'trigger_name': fields.selection(_select_signals, string='Trigger Name', size=128, help="Select the Signal name that is to be used as the trigger."),
206 'wkf_model_id': fields.many2one('ir.model', 'Workflow On', help="Workflow to be executed on this model."),
207- 'trigger_obj_id': fields.many2one('ir.model.fields','Trigger On', help="Select the object from the model on which the workflow will executed."),
208+ 'trigger_obj_id': fields.many2one('ir.model.fields', 'Trigger On', help="Select the object from the model on which the workflow will executed."),
209 'email': fields.char('Email Address', size=512, help="Provides the fields that will be used to fetch the email address, e.g. when you select the invoice, then `object.invoice_address_id.email` is the field which gives the correct address"),
210 'subject': fields.char('Subject', size=1024, translate=True, help="Specify the subject. You can use fields from the object, e.g. `Hello [[ object.partner_id.name ]]`"),
211 'message': fields.text('Message', translate=True, help="Specify the message. You can use the fields from the object. e.g. `Dear [[ object.partner_id.name ]]`"),
212@@ -594,13 +594,13 @@
213 if not expr:
214 continue
215
216- if action.state=='client_action':
217+ if action.state == 'client_action':
218 if not action.action_id:
219 raise osv.except_osv(_('Error'), _("Please specify an action to launch !"))
220 return self.pool.get(action.action_id.type)\
221 .read(cr, uid, action.action_id.id, context=context)
222
223- if action.state=='code':
224+ if action.state == 'code':
225 localdict = {
226 'self': self.pool.get(action.model_id.model),
227 'context': dict(context), # copy context to prevent side-effects of eval
228@@ -619,7 +619,7 @@
229 user = config['email_from']
230 address = str(action.email)
231 try:
232- address = eval(str(action.email), cxt)
233+ address = eval(str(action.email), cxt)
234 except:
235 pass
236
237@@ -784,33 +784,39 @@
238 # This model use to register action services.
239 TODO_STATES = [('open', 'To Do'),
240 ('done', 'Done'),
241- ('skip','Skipped'),
242- ('cancel','Cancelled')]
243+ ('skip', 'Skipped'),
244+ ('cancel', 'Cancelled')]
245
246 class ir_actions_todo(osv.osv):
247 _name = 'ir.actions.todo'
248- _columns={
249+ _columns = {
250 'action_id': fields.many2one(
251 'ir.actions.act_window', 'Action', select=True, required=True,
252 ondelete='cascade'),
253 'sequence': fields.integer('Sequence'),
254 'state': fields.selection(TODO_STATES, string='State', required=True),
255 'name':fields.char('Name', size=64),
256- 'restart': fields.selection([('onskip','On Skip'),('always','Always'),('never','Never')],'Restart',required=True),
257+ 'restart': fields.selection([('onskip', 'On Skip'), ('always', 'Always'), ('never', 'Never')], 'Restart', required=True),
258 'groups_id':fields.many2many('res.groups', 'res_groups_action_rel', 'uid', 'gid', 'Groups'),
259 'note':fields.text('Text', translate=True),
260+ 'previous': fields.many2one('ir.actions.todo', string='Previous'),
261 }
262- _defaults={
263+ _defaults = {
264 'state': 'open',
265 'sequence': 10,
266 'restart': 'onskip',
267 }
268- _order="sequence,name,id"
269+ _order = "sequence,name,id"
270+
271+ def del_previous(self, cr, uid):
272+ ids = self.search(cr, uid, [])
273+ self.write(cr, uid, ids, {'previous': False})
274
275 def action_launch(self, cr, uid, ids, context=None):
276 """ Launch Action of Wizard"""
277 if context is None:
278 context = {}
279+ self.del_previous(cr, uid)
280 wizard_id = ids and ids[0] or False
281 wizard = self.browse(cr, uid, wizard_id, context=context)
282 res = self.pool.get('ir.actions.act_window').read(cr, uid, wizard.action_id.id, ['name', 'view_type', 'view_mode', 'res_model', 'context', 'views', 'type'], context=context)
283
284=== modified file 'bin/addons/base/res/res_config.py'
285--- bin/addons/base/res/res_config.py 2011-01-20 16:27:37 +0000
286+++ bin/addons/base/res/res_config.py 2012-09-10 15:46:26 +0000
287@@ -45,35 +45,35 @@
288 a tuple of (non_open_todos:int, total_todos: int)
289 '''
290 return (self.pool.get('ir.actions.todo')\
291- .search_count(cr, uid, [('state','<>','open')], context),
292+ .search_count(cr, uid, [('state', '<>', 'open')], context),
293 self.pool.get('ir.actions.todo')\
294 .search_count(cr, uid, [], context))
295
296 def _progress(self, cr, uid, context=None):
297 closed, total = self.get_current_progress(cr, uid, context=context)
298 if total:
299- return round(closed*100./total)
300+ return round(closed * 100. / total)
301 return 100.
302
303 _columns = dict(
304- progress = fields.float('Configuration Progress', readonly=True),
305+ progress=fields.float('Configuration Progress', readonly=True),
306 )
307
308 _defaults = dict(
309- progress = _progress,
310+ progress=_progress,
311 )
312
313 def _next_action(self, cr, uid, context=None):
314 todos = self.pool.get('ir.actions.todo')
315 self.__logger.info('getting next %s', todos)
316- active_todos = todos.search(cr, uid, [('state','=','open')],
317+ active_todos = todos.search(cr, uid, [('state', '=', 'open')],
318 limit=1)
319 if active_todos:
320 todo_obj = todos.browse(cr, uid, active_todos[0], context=None)
321 todo_groups = map(lambda x:x.id, todo_obj.groups_id)
322 dont_skip_todo = True
323 if todo_groups:
324- cr.execute("select 1 from res_groups_users_rel where uid=%s and gid IN %s",(uid, tuple(todo_groups),))
325+ cr.execute("select 1 from res_groups_users_rel where uid=%s and gid IN %s", (uid, tuple(todo_groups),))
326 dont_skip_todo = bool(cr.fetchone())
327 if dont_skip_todo:
328 return todos.browse(cr, uid, active_todos[0], context=None)
329@@ -89,18 +89,29 @@
330 # this is ultra brittle, but apart from storing the todo id
331 # into the res.config view, I'm not sure how to get the
332 # "previous" todo
333+ if not context:
334+ context = {}
335 previous_todo = self._next_action(cr, uid, context=context)
336 if not previous_todo:
337 self.__logger.warn(_("Couldn't find previous ir.actions.todo"))
338 return
339 previous_todo.write({'state':state})
340+ if not context.get('no_update_previous', False):
341+ next_action = self._next_action(cr, uid, context=context)
342+ previous_todo.write({'previous': next_action and next_action.id or False})
343
344 def _next(self, cr, uid, context=None):
345+ if not context:
346+ context = {}
347 self.__logger.info('getting next operation')
348 next = self._next_action(cr, uid)
349 self.__logger.info('next action is %s', next)
350 if next:
351 action = next.action_id
352+ if context.get('no_update_previous', False):
353+ c = {'previous_id': next.id}
354+ else:
355+ c = {}
356 return {
357 'view_mode': action.view_mode,
358 'view_type': action.view_type,
359@@ -108,6 +119,7 @@
360 'res_model': action.res_model,
361 'type': action.type,
362 'target': action.target,
363+ 'context': c,
364 }
365 self.__logger.info('all configuration actions have been executed')
366
367@@ -119,8 +131,9 @@
368
369 def start(self, cr, uid, ids, context=None):
370 ids2 = self.pool.get('ir.actions.todo').search(cr, uid, [], context=context)
371+ self.pool.get('ir.actions.todo').write(cr, uid, ids2, {'previous': False})
372 for todo in self.pool.get('ir.actions.todo').browse(cr, uid, ids2, context=context):
373- if (todo.restart=='always') or (todo.restart=='onskip' and (todo.state in ('skip','cancel'))):
374+ if (todo.restart == 'always') or (todo.restart == 'onskip' and (todo.state in ('skip', 'cancel'))):
375 todo.write({'state':'open'})
376 return self.next(cr, uid, ids, context)
377
378@@ -167,6 +180,45 @@
379 next = self.execute(cr, uid, ids, context=None)
380 if next: return next
381 return self.next(cr, uid, ids, context=context)
382+
383+ def action_previous(self, cr, uid, ids, context=None):
384+ if not context:
385+ context = {}
386+
387+ context.update({'no_update_previous': True})
388+
389+ previous = self.next(cr, uid, ids, context=context)
390+ if previous.get('context', {}).get('previous_id', False):
391+ previous_id = self.pool.get('ir.actions.todo').search(cr, uid, [('previous', '=', previous['context']['previous_id'])])
392+ if previous_id:
393+ self.pool.get('ir.actions.todo').write(cr, uid, previous_id[0], {'state': 'open'})
394+ action = self.pool.get('ir.actions.todo').browse(cr, uid, previous_id[0]).action_id
395+ return {
396+ 'view_mode': action.view_mode,
397+ 'view_type': action.view_type,
398+ 'view_id': action.view_id and [action.view_id.id] or False,
399+ 'res_model': action.res_model,
400+ 'type': action.type,
401+ 'target': action.target,
402+ }
403+ else:
404+ raise osv.except_osv(_('Error'), _('No previous wizard found !'))
405+ else:
406+ raise osv.except_osv(_('Error'), _('No previous wizard found !'))
407+
408+ current_user_menu = self.pool.get('res.users')\
409+ .browse(cr, uid, uid).menu_id
410+ # return the action associated with the menu
411+ return self.pool.get(current_user_menu.type)\
412+ .read(cr, uid, current_user_menu.id)
413+
414+ def action_finish(self, cr, uid, ids, context=None):
415+ self.action_next(cr, uid, ids, context=context)
416+ open_todo_ids = self.pool.get('ir.actions.todo').search(cr, uid, [('state', '=', 'open')])
417+ self.pool.get('ir.actions.todo').write(cr, uid, open_todo_ids, {'state': 'done'})
418+
419+ return self.next(cr, uid, ids, context=context)
420+
421
422 def action_skip(self, cr, uid, ids, context=None):
423 """ Action handler for the ``skip`` event.
424@@ -309,8 +361,8 @@
425 return modules.browse(
426 cr, uid,
427 modules.search(cr, uid,
428- [('name','in',selectable),
429- ('state','in',['to install', 'installed', 'to upgrade'])],
430+ [('name', 'in', selectable),
431+ ('state', 'in', ['to install', 'installed', 'to upgrade'])],
432 context=context),
433 context=context)
434
435@@ -342,7 +394,7 @@
436
437 hooks_results = set()
438 for module in base:
439- hook = getattr(self, '_if_%s'%(module), None)
440+ hook = getattr(self, '_if_%s' % (module), None)
441 if hook:
442 hooks_results.update(hook(cr, uid, ids, context=None) or set())
443
444@@ -380,7 +432,7 @@
445 continue
446 fields[module.name].update(
447 readonly=True,
448- help= ustr(fields[module.name].get('help', '')) +
449+ help=ustr(fields[module.name].get('help', '')) +
450 _('\n\nThis addon is already installed on your system'))
451 return fields
452
453@@ -391,7 +443,7 @@
454 self.__logger.info('Selecting addons %s to install', to_install)
455 modules.state_update(
456 cr, uid,
457- modules.search(cr, uid, [('name','in',to_install)]),
458+ modules.search(cr, uid, [('name', 'in', to_install)]),
459 'to install', ['uninstalled'], context=context)
460 cr.commit() #TOFIX: after remove this statement, installation wizard is fail
461 new_db, self.pool = pooler.restart_pool(cr.dbname, update_module=True)
462@@ -408,7 +460,7 @@
463 not to break existing but not-yet-migrated addons, the old wizard was
464 reintegrated and gutted.
465 '''
466- _name='ir.actions.configuration.wizard'
467+ _name = 'ir.actions.configuration.wizard'
468 _inherit = 'res.config'
469 __logger = logging.getLogger(_name)
470
471
472=== modified file 'bin/addons/base/res/res_config.xml'
473--- bin/addons/base/res/res_config.xml 2010-12-29 20:12:50 +0000
474+++ bin/addons/base/res/res_config.xml 2012-09-10 15:46:26 +0000
475@@ -19,14 +19,18 @@
476 </group>
477 </group>
478 <group colspan="8" col="8">
479- <separator string="" colspan="6"/>
480+ <separator string="" colspan="8"/>
481 <group colspan="4" width="220">
482 <field name="progress" widget="progressbar" nolabel="1" colspan="2"/>
483 </group>
484+ <button name="action_previous" icon="terp-gtk-go-back-ltr"
485+ type="object" string="Previous" colspan="1" />
486 <button name="action_skip" icon="gtk-jump-to" special="cancel"
487 type="object" string="Skip" colspan="1"/>
488 <button name="action_next" icon="gtk-go-forward"
489 type="object" string="Next" colspan="1"/>
490+ <button name="action_finish" icon="gtk-quit"
491+ type="object" string="Finish" colspan="1" />
492 </group>
493 </form>
494 </field>

Subscribers

People subscribed via source and target branches

to all changes: