1 # -*- encoding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 ##############################################################################
23 from osv import fields,osv
26 from tools.config import config
30 class actions(osv.osv):
31 _name = 'ir.actions.actions'
34 'name': fields.char('Action Name', required=True, size=64),
35 'type': fields.char('Action Type', required=True, size=32),
36 'usage': fields.char('Action Usage', size=32),
39 'usage': lambda *a: False,
43 class report_custom(osv.osv):
44 _name = 'ir.actions.report.custom'
45 _table = 'ir_act_report_custom'
46 _sequence = 'ir_actions_id_seq'
48 'name': fields.char('Report Name', size=64, required=True, translate=True),
49 'type': fields.char('Report Type', size=32, required=True),
50 'model':fields.char('Object', size=64, required=True),
51 'report_id': fields.integer('Report Ref.', required=True),
52 'usage': fields.char('Action Usage', size=32),
53 'multi': fields.boolean('On multiple doc.', help="If set to true, the action will not be displayed on the right toolbar of a form views.")
56 'multi': lambda *a: False,
57 'type': lambda *a: 'ir.actions.report.custom',
61 class report_xml(osv.osv):
63 def _report_content(self, cursor, user, ids, name, arg, context=None):
65 for report in self.browse(cursor, user, ids, context=context):
66 data = report[name + '_data']
67 if not data and report[name[:-8]]:
69 fp = tools.file_open(report[name[:-8]], mode='rb')
76 def _report_content_inv(self, cursor, user, id, name, value, arg, context=None):
77 self.write(cursor, user, id, {name+'_data': value}, context=context)
79 def _report_sxw(self, cursor, user, ids, name, arg, context=None):
81 for report in self.browse(cursor, user, ids, context=context):
83 res[report.id] = report.report_rml.replace('.rml', '.sxw')
85 res[report.id] = False
88 _name = 'ir.actions.report.xml'
89 _table = 'ir_act_report_xml'
90 _sequence = 'ir_actions_id_seq'
92 'name': fields.char('Name', size=64, required=True, translate=True),
93 'type': fields.char('Report Type', size=32, required=True),
94 'model': fields.char('Object', size=64, required=True),
95 'report_name': fields.char('Internal Name', size=64, required=True),
96 'report_xsl': fields.char('XSL path', size=256),
97 'report_xml': fields.char('XML path', size=256),
98 'report_rml': fields.char('RML path', size=256,
99 help="The .rml path of the file or NULL if the content is in report_rml_content"),
100 'report_sxw': fields.function(_report_sxw, method=True, type='char',
102 'report_sxw_content_data': fields.binary('SXW content'),
103 'report_rml_content_data': fields.binary('RML content'),
104 'report_sxw_content': fields.function(_report_content,
105 fnct_inv=_report_content_inv, method=True,
106 type='binary', string='SXW content',),
107 'report_rml_content': fields.function(_report_content,
108 fnct_inv=_report_content_inv, method=True,
109 type='binary', string='RML content'),
110 'auto': fields.boolean('Automatic XSL:RML', required=True),
111 'usage': fields.char('Action Usage', size=32),
112 'header': fields.boolean('Add RML header',
113 help="Add or not the coporate RML header"),
114 'multi': fields.boolean('On multiple doc.',
115 help="If set to true, the action will not be displayed on the right toolbar of a form views."),
116 'report_type': fields.selection([
122 ], string='Type', required=True),
123 'groups_id': fields.many2many('res.groups', 'res_groups_report_rel', 'uid', 'gid', 'Groups'),
124 'attachment': fields.char('Save As Attachment Prefix', size=128, help='This is the filename of the attachment to store the printing result. Keep empty to not save the printed reports. You can use python expression using the object and time variables.'),
125 'attachment_use': fields.boolean('Reload from Attachment', help='If you check this, the second time the user print with same attachment name, it returns the previour report.')
128 'type': lambda *a: 'ir.actions.report.xml',
129 'multi': lambda *a: False,
130 'auto': lambda *a: True,
131 'header': lambda *a: True,
132 'report_sxw_content': lambda *a: False,
133 'report_type': lambda *a: 'pdf',
134 'attachment': lambda *a: False,
139 class act_window(osv.osv):
140 _name = 'ir.actions.act_window'
141 _table = 'ir_act_window'
142 _sequence = 'ir_actions_id_seq'
144 # def search(self, cr, uid, args, offset=0, limit=2000, order=None,
145 # context=None, count=False):
146 # if context is None:
148 # ids = osv.orm.orm.search(self, cr, uid, args, offset, limit, order,
152 # user_groups = self.pool.get('res.users').read(cr, uid, [uid])[0]['groups_id']
154 # for act in self.browse(cr, uid, ids):
155 # if not len(act.groups_id):
156 # result.append(act.id)
158 # for g in act.groups_id:
159 # if g.id in user_groups:
160 # result.append(act.id)
164 def _views_get_fnc(self, cr, uid, ids, name, arg, context={}):
166 for act in self.browse(cr, uid, ids):
167 res[act.id]=[(view.view_id.id, view.view_mode) for view in act.view_ids]
168 modes = act.view_mode.split(',')
169 if len(modes)>len(act.view_ids):
172 res[act.id].append((act.view_id.id, act.view_id.type))
173 for t in modes[len(act.view_ids):]:
174 if act.view_id and (t == act.view_id.type) and not find:
177 res[act.id].append((False, t))
181 'name': fields.char('Action Name', size=64, translate=True),
182 'type': fields.char('Action Type', size=32, required=True),
183 'view_id': fields.many2one('ir.ui.view', 'View Ref.', ondelete='cascade'),
184 'domain': fields.char('Domain Value', size=250),
185 'context': fields.char('Context Value', size=250),
186 'res_model': fields.char('Object', size=64),
187 'src_model': fields.char('Source Object', size=64),
188 'target': fields.selection([('current','Current Window'),('new','New Window')], 'Target Window'),
189 'view_type': fields.selection((('tree','Tree'),('form','Form')),string='Type of view'),
190 'view_mode': fields.char('Mode of view', size=250),
191 'usage': fields.char('Action Usage', size=32),
192 'view_ids': fields.one2many('ir.actions.act_window.view', 'act_window_id', 'Views'),
193 'views': fields.function(_views_get_fnc, method=True, type='binary', string='Views'),
194 'limit': fields.integer('Limit', help='Default limit for the list view'),
195 'auto_refresh': fields.integer('Auto-Refresh',
196 help='Add an auto-refresh on the view'),
197 'groups_id': fields.many2many('res.groups', 'ir_act_window_group_rel',
198 'act_id', 'gid', 'Groups'),
201 'type': lambda *a: 'ir.actions.act_window',
202 'view_type': lambda *a: 'form',
203 'view_mode': lambda *a: 'tree,form',
204 'context': lambda *a: '{}',
205 'limit': lambda *a: 80,
206 'target': lambda *a: 'current',
207 'auto_refresh': lambda *a: 0,
211 class act_window_view(osv.osv):
212 _name = 'ir.actions.act_window.view'
213 _table = 'ir_act_window_view'
214 _rec_name = 'view_id'
216 'sequence': fields.integer('Sequence'),
217 'view_id': fields.many2one('ir.ui.view', 'View'),
218 'view_mode': fields.selection((
222 ('calendar', 'Calendar'),
223 ('gantt', 'Gantt')), string='Type of view', required=True),
224 'act_window_id': fields.many2one('ir.actions.act_window', 'Action', ondelete='cascade'),
225 'multi': fields.boolean('On multiple doc.',
226 help="If set to true, the action will not be displayed on the right toolbar of a form views."),
229 'multi': lambda *a: False,
234 class act_wizard(osv.osv):
235 _name = 'ir.actions.wizard'
236 _table = 'ir_act_wizard'
237 _sequence = 'ir_actions_id_seq'
239 'name': fields.char('Wizard info', size=64, required=True, translate=True),
240 'type': fields.char('Action type', size=32, required=True),
241 'wiz_name': fields.char('Wizard name', size=64, required=True),
242 'multi': fields.boolean('Action on multiple doc.', help="If set to true, the wizard will not be displayed on the right toolbar of a form views."),
243 'groups_id': fields.many2many('res.groups', 'res_groups_wizard_rel', 'uid', 'gid', 'Groups'),
244 'model': fields.char('Object', size=64),
247 'type': lambda *a: 'ir.actions.wizard',
248 'multi': lambda *a: False,
252 class act_url(osv.osv):
253 _name = 'ir.actions.url'
254 _table = 'ir_act_url'
255 _sequence = 'ir_actions_id_seq'
257 'name': fields.char('Action Name', size=64, translate=True),
258 'type': fields.char('Action Type', size=32, required=True),
259 'url': fields.text('Action Url',required=True),
260 'target': fields.selection((
261 ('new', 'New Window'),
262 ('self', 'This Window')),
263 'Action Target', required=True
267 'type': lambda *a: 'ir.actions.act_url',
268 'target': lambda *a: 'new'
272 def model_get(self, cr, uid, context={}):
273 wkf_pool = self.pool.get('workflow')
274 ids = wkf_pool.search(cr, uid, [])
275 osvs = wkf_pool.read(cr, uid, ids, ['osv'])
278 mpool = self.pool.get('ir.model')
280 model = osv.get('osv')
281 id = mpool.search(cr, uid, [('model','=',model)])
282 name = mpool.read(cr, uid, id)[0]['name']
283 res.append((model, name))
287 class ir_model_fields(osv.osv):
288 _inherit = 'ir.model.fields'
289 _rec_name = 'field_description'
291 'complete_name': fields.char('Complete Name', size=64, select=1),
294 def name_search(self, cr, uid, name, args=None, operator='ilike', context=None, limit=800):
295 def get_fields(cr, uid, field, rel):
297 mobj = self.pool.get('ir.model')
298 id = mobj.search(cr, uid, [('model','=',rel)])
300 obj = self.pool.get('ir.model.fields')
301 ids = obj.search(cr, uid, [('model_id','in',id)])
302 records = obj.read(cr, uid, ids)
303 for record in records:
305 fld = field + '/' + record['name']
307 result.append((id, fld))
314 return super(ir_model_fields, self).name_search(cr, uid, name, args, operator, context, limit)
316 if context.get('key') != 'server_action':
317 return super(ir_model_fields, self).name_search(cr, uid, name, args, operator, context, limit)
320 obj = self.pool.get('ir.model.fields')
321 ids = obj.search(cr, uid, args)
322 records = obj.read(cr, uid, ids)
323 for record in records:
325 field = record['name']
327 if record['ttype'] == 'many2one':
328 rel = record['relation']
329 res = get_fields(cr, uid, field, record['relation'])
333 result.append((id, field))
336 obj.write(cr, uid, [rs[0]], {'complete_name':rs[1]})
342 result = super(ir_model_fields, self).name_search(cr, uid, name, [('complete_name','ilike',name), ('id','in',iids)], operator, context, limit)
348 class server_object_lines(osv.osv):
349 _name = 'ir.server.object.lines'
350 _sequence = 'ir_actions_id_seq'
352 'server_id': fields.many2one('ir.actions.server', 'Object Mapping'),
353 'col1': fields.many2one('ir.model.fields', 'Destination', required=True),
354 'value': fields.text('Value', required=True),
355 'type': fields.selection([
357 ('equation','Formula')
358 ], 'Type', required=True, size=32, change_default=True),
361 'type': lambda *a: 'equation',
363 server_object_lines()
366 # Actions that are run on the server side
368 class actions_server(osv.osv):
370 def _select_signals(self, cr, uid, context={}):
371 cr.execute("select distinct t.signal as key, t.signal || ' - [ ' || w.osv || ' ] ' as val from wkf w, wkf_activity a, wkf_transition t "\
372 " where w.id = a.wkf_id " \
373 " and t.act_from = a.wkf_id " \
374 " or t.act_to = a.wkf_id and t.signal not in (null, NULL)")
375 result = cr.fetchall() or []
378 if not rs[0] == None and not rs[1] == None:
382 _name = 'ir.actions.server'
383 _table = 'ir_act_server'
384 _sequence = 'ir_actions_id_seq'
387 'name': fields.char('Action Name', required=True, size=64, help="Easy to Refer action by name i.e. One Sales Order -> Many Invoice"),
388 'condition' : fields.char('Condition', size=256, required=True, help="Condition that is to be test before execute action, i.e : object.list_price > object.cost_price"),
389 'state': fields.selection([
390 ('client_action','Client Action'),
392 ('loop','Iteration'),
393 ('code','Python Code'),
394 ('trigger','Trigger'),
397 ('object_create','Create Object'),
398 ('object_write','Write Object'),
399 ('other','Multi Actions'),
400 ], 'Action Type', required=True, size=32, help="Type of the Action that is to be execute"),
401 'code':fields.text('Python Code', help="python code to be execute"),
402 'sequence': fields.integer('Sequence', help="Important when you deal with the multi action, the execution order will be decided based on this, low number higher priority"),
403 'model_id': fields.many2one('ir.model', 'Object', required=True, help="select the obect on which the action will work (read, write, create)"),
404 'action_id': fields.many2one('ir.actions.actions', 'Client Action', help="Select the Ation Window, Report, Wizard to be execute"),
405 'trigger_name': fields.selection(_select_signals, string='Trigger Name', size=128, help="Select the Signal name that is to be "),
406 'wkf_model_id': fields.many2one('ir.model', 'Workflow on', help="Workflow to be execute on which model"),
407 'trigger_obj_id': fields.many2one('ir.model.fields','Trigger On', help="select the object from the model on which the workflow will execute"),
408 'email': fields.char('Email Address', size=512, help="provides the fiels that will refer to the tiny to fetch the email address, i.e. you select the invoice, then `object.invoice_address_id.email` is the field which give the correct address"),
409 'subject': fields.char('Subject', size=1024, translate=True, help="Specify the subject, you can use the fields from the object. like `Hello [[ object.partner_id.name ]]`"),
410 'message': fields.text('Message', translate=True, help="Specify the Message, you can use the fields from the object. like `Dear [[ object.partner_id.name ]]`"),
411 'mobile': fields.char('Mobile No', size=512, help="provides the fiels that will refer to the tiny to fetch the mobile number, i.e. you select the invoice, then `object.invoice_address_id.mobile` is the field which give the correct mobile number"),
412 'sms': fields.char('SMS', size=160, translate=True),
413 'child_ids': fields.many2many('ir.actions.server', 'rel_server_actions', 'server_id', 'action_id', 'Others Actions'),
414 'usage': fields.char('Action Usage', size=32),
415 'type': fields.char('Action Type', size=32, required=True),
416 '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"),
417 'fields_lines': fields.one2many('ir.server.object.lines', 'server_id', 'Fields Mapping'),
418 'record_id':fields.many2one('ir.model.fields', 'Create Id', help="Provide the field name from where the record id stores after the create operations, if its empty, you can not track the new record"),
419 'write_id':fields.char('Write Id', size=256, help="Provide the field name from where the record id refer for the write operation, if its empty it will refer to the active id of the object"),
420 'loop_action':fields.many2one('ir.actions.server', 'Loop Action', help="select the action, which will be executes. Loop action will not be avaliable inside loop"),
421 'expression':fields.char('Loop Expression', size=512, help="enter the field/expression that will return the list, i.e. select the sale order in Object, and we can have loop on sales order line. Expression = `object.order_line`"),
424 'state': lambda *a: 'dummy',
425 'condition': lambda *a: 'True',
426 'type': lambda *a: 'ir.actions.server',
427 'sequence': lambda *a: 5,
428 'code': lambda *a: """# You can use the following variables
435 # If you plan to return an action, assign: action = {...}
439 def get_email(self, cr, uid, action, context):
440 logger = netsvc.Logger()
441 obj_pool = self.pool.get(action.model_id.model)
442 id = context.get('active_id')
443 obj = obj_pool.browse(cr, uid, id)
447 if '/' in action.email.complete_name:
448 fields = action.email.complete_name.split('/')
449 elif '.' in action.email.complete_name:
450 fields = action.email.complete_name.split('.')
454 obj = getattr(obj, field)
456 logger.notifyChannel('Workflow', netsvc.LOG_ERROR, 'Failed to parse : %s' % (field))
460 def get_mobile(self, cr, uid, action, context):
461 logger = netsvc.Logger()
462 obj_pool = self.pool.get(action.model_id.model)
463 id = context.get('active_id')
464 obj = obj_pool.browse(cr, uid, id)
468 if '/' in action.mobile.complete_name:
469 fields = action.mobile.complete_name.split('/')
470 elif '.' in action.mobile.complete_name:
471 fields = action.mobile.complete_name.split('.')
475 obj = getattr(obj, field)
477 logger.notifyChannel('Workflow', netsvc.LOG_ERROR, 'Failed to parse : %s' % (field))
481 def merge_message(self, cr, uid, keystr, action, context):
482 logger = netsvc.Logger()
484 obj_pool = self.pool.get(action.model_id.model)
485 id = context.get('active_id')
486 obj = obj_pool.browse(cr, uid, id)
487 exp = str(match.group()[2:-2]).strip()
488 result = eval(exp, {'object':obj, 'context': context,'time':time})
489 if result in (None, False):
490 return str("--------")
493 com = re.compile('(\[\[.+?\]\])')
494 message = com.sub(merge, keystr)
498 # Context should contains:
500 # id : current id of the object
502 # False : Finnished correctly
503 # ACTION_ID : Action to launch
505 def run(self, cr, uid, ids, context={}):
506 logger = netsvc.Logger()
508 for action in self.browse(cr, uid, ids, context):
509 obj_pool = self.pool.get(action.model_id.model)
510 obj = obj_pool.browse(cr, uid, context['active_id'], context=context)
519 expr = eval(str(action.condition), cxt)
523 if action.state=='client_action':
524 if not action.action_id:
525 raise osv.except_osv(_('Error'), _("Please specify an action to launch !"))
526 result = self.pool.get(action.action_id.type).read(cr, uid, action.action_id.id, context=context)
529 if action.state=='python':
531 'self': self.pool.get(action.model_id.model),
538 exec action.code in localdict
539 if 'action' in localdict:
540 return localdict['action']
542 if action.state == 'email':
543 user = config['email_from']
544 address = str(action.email)
546 address = eval(str(action.email), cxt)
551 raise osv.except_osv(_('Error'), _("Please specify the Partner Email address !"))
553 raise osv.except_osv(_('Error'), _("Please specify server option --smtp-from !"))
555 subject = self.merge_message(cr, uid, str(action.subject), action, context)
556 body = self.merge_message(cr, uid, str(action.message), action, context)
558 if tools.email_send(user, [address], subject, body, debug=False, subtype='html') == True:
559 logger.notifyChannel('email', netsvc.LOG_INFO, 'Email successfully send to : %s' % (address))
561 logger.notifyChannel('email', netsvc.LOG_ERROR, 'Failed to send email to : %s' % (address))
563 if action.state == 'trigger':
564 wf_service = netsvc.LocalService("workflow")
565 model = action.wkf_model_id.model
566 obj_pool = self.pool.get(action.model_id.model)
567 res_id = self.pool.get(action.model_id.model).read(cr, uid, [context.get('active_id')], [action.trigger_obj_id.name])
568 id = res_id [0][action.trigger_obj_id.name]
569 wf_service.trg_validate(uid, model, int(id), action.trigger_name, cr)
571 if action.state == 'sms':
572 #TODO: set the user and password from the system
573 # for the sms gateway user / password
576 to = self.get_mobile(cr, uid, action, context)
577 #TODO: Apply message mearge with the field
578 if tools.sms_send(user, password, api_id, text, to) == True:
579 logger.notifyChannel('sms', netsvc.LOG_INFO, 'SMS successfully send to : %s' % (action.address))
581 logger.notifyChannel('sms', netsvc.LOG_ERROR, 'Failed to send SMS to : %s' % (action.address))
583 if action.state == 'other':
585 for act in action.child_ids:
586 context['active_id'] = context['active_ids'][0]
587 result = self.run(cr, uid, [act.id], context)
593 if action.state == 'loop':
594 obj_pool = self.pool.get(action.model_id.model)
595 obj = obj_pool.browse(cr, uid, context['active_id'], context=context)
604 expr = eval(str(action.expression), cxt)
605 context['object'] = obj
607 context['active_id'] = i.id
608 result = self.run(cr, uid, [action.loop_action.id], context)
610 if action.state == 'object_write':
612 for exp in action.fields_lines:
614 if exp.type == 'equation':
615 obj_pool = self.pool.get(action.model_id.model)
616 obj = obj_pool.browse(cr, uid, context['active_id'], context=context)
617 cxt = {'context':context, 'object': obj, 'time':time}
618 expr = eval(euq, cxt)
621 res[exp.col1.name] = expr
623 if not action.write_id:
624 if not action.srcmodel_id:
625 obj_pool = self.pool.get(action.model_id.model)
626 obj_pool.write(cr, uid, [context.get('active_id')], res)
628 write_id = context.get('active_id')
629 obj_pool = self.pool.get(action.srcmodel_id.model)
630 obj_pool.write(cr, uid, [write_id], res)
632 elif action.write_id:
633 obj_pool = self.pool.get(action.srcmodel_id.model)
634 rec = self.pool.get(action.model_id.model).browse(cr, uid, context.get('active_id'))
635 id = eval(action.write_id, {'object': rec})
639 raise osv.except_osv(_('Error'), _("Problem in configuration `Record Id` in Server Action!"))
641 if type(id) != type(1):
642 raise osv.except_osv(_('Error'), _("Problem in configuration `Record Id` in Server Action!"))
644 obj_pool.write(cr, uid, [write_id], res)
646 if action.state == 'object_create':
648 for exp in action.fields_lines:
650 if exp.type == 'equation':
651 obj_pool = self.pool.get(action.model_id.model)
652 obj = obj_pool.browse(cr, uid, context['active_id'], context=context)
653 expr = eval(euq, {'context':context, 'object': obj, 'time':time})
656 res[exp.col1.name] = expr
660 obj_pool = self.pool.get(action.srcmodel_id.model)
661 res_id = obj_pool.create(cr, uid, res)
664 self.pool.get(action.model_id.model).write(cr, uid, [context.get('active_id')], {action.record_id.name:res_id})
670 class act_window_close(osv.osv):
671 _name = 'ir.actions.act_window_close'
672 _table = 'ir_actions'
673 _sequence = 'ir_actions_id_seq'
675 'name': fields.char('Action Name', size=64, translate=True),
676 'type': fields.char('Action Type', size=32, required=True),
679 'type': lambda *a: 'ir.actions.act_window_close',
683 # This model use to register action services.
684 # if action type is 'configure', it will be start on configuration wizard.
685 # if action type is 'service',
686 # - if start_type= 'at once', it will be start at one time on start date
687 # - if start_type='auto', it will be start on auto starting from start date, and stop on stop date
688 # - if start_type="manual", it will start and stop on manually
689 class ir_actions_todo(osv.osv):
690 _name = 'ir.actions.todo'
692 'name':fields.char('Name',size=64,required=True, select=True),
693 'note':fields.text('Text', translate=True),
694 'start_date': fields.datetime('Start Date'),
695 'end_date': fields.datetime('End Date'),
696 'action_id':fields.many2one('ir.actions.act_window', 'Action', select=True,required=True, ondelete='cascade'),
697 'sequence':fields.integer('Sequence'),
698 'active': fields.boolean('Active'),
699 'type':fields.selection([('configure', 'Configure'),('service', 'Service'),('other','Other')], string='Type', required=True),
700 'start_on':fields.selection([('at_once', 'At Once'),('auto', 'Auto'),('manual','Manual')], string='Start On'),
701 'groups_id': fields.many2many('res.groups', 'res_groups_act_todo_rel', 'act_todo_id', 'group_id', 'Groups'),
702 'users_id': fields.many2many('res.users', 'res_users_act_todo_rel', 'act_todo_id', 'user_id', 'Users'),
703 'state':fields.selection([('open', 'Not Started'),('done', 'Done'),('skip','Skipped'),('cancel','Cancel')], string='State', required=True)
706 'state': lambda *a: 'open',
707 'sequence': lambda *a: 10,
708 'active':lambda *a:True,
709 'type':lambda *a:'configure'
714 # This model to use run all configuration actions
715 class ir_actions_configuration_wizard(osv.osv_memory):
716 _name='ir.actions.configuration.wizard'
717 def next_configuration_action(self,cr,uid,context={}):
718 item_obj = self.pool.get('ir.actions.todo')
719 item_ids = item_obj.search(cr, uid, [('type','=','configure'),('state', '=', 'open'),('active','=',True)], limit=1, context=context)
720 if item_ids and len(item_ids):
721 item = item_obj.browse(cr, uid, item_ids[0], context=context)
724 def _get_action_name(self, cr, uid, context={}):
725 next_action=self.next_configuration_action(cr,uid,context=context)
727 return next_action.note
729 return "Your database is now fully configured.\n\nClick 'Continue' and enjoy your OpenERP experience..."
732 def _get_action(self, cr, uid, context={}):
733 next_action=self.next_configuration_action(cr,uid,context=context)
735 return next_action.id
738 def _progress_get(self,cr,uid, context={}):
739 total = self.pool.get('ir.actions.todo').search_count(cr, uid, [], context)
740 todo = self.pool.get('ir.actions.todo').search_count(cr, uid, [('type','=','configure'),('active','=',True),('state','<>','open')], context)
741 return max(5.0,round(todo*100/total))
744 'name': fields.text('Next Wizard',readonly=True),
745 'progress': fields.float('Configuration Progress', readonly=True),
746 'item_id':fields.many2one('ir.actions.todo', 'Next Configuration Wizard',invisible=True, readonly=True),
749 'progress': _progress_get,
750 'item_id':_get_action,
751 'name':_get_action_name,
753 def button_next(self,cr,uid,ids,context=None):
754 user_action=self.pool.get('res.users').browse(cr,uid,uid)
755 act_obj=self.pool.get(user_action.menu_id.type)
756 action_ids=act_obj.search(cr,uid,[('name','=',user_action.menu_id.name)])
757 action_open=act_obj.browse(cr,uid,action_ids)[0]
758 if context.get('menu',False):
760 'view_type': action_open.view_type,
761 'view_id':action_open.view_id and [action_open.view_id.id] or False,
762 'res_model': action_open.res_model,
763 'type': action_open.type,
764 'domain':action_open.domain
766 return {'type':'ir.actions.act_window_close'}
768 def button_skip(self,cr,uid,ids,context=None):
769 item_obj = self.pool.get('ir.actions.todo')
770 item_id=self.read(cr,uid,ids)[0]['item_id']
772 item = item_obj.browse(cr, uid, item_id, context=context)
773 item_obj.write(cr, uid, item.id, {
779 'res_model': 'ir.actions.configuration.wizard',
780 'type': 'ir.actions.act_window',
783 return self.button_next(cr, uid, ids, context)
785 def button_continue(self, cr, uid, ids, context=None):
786 item_obj = self.pool.get('ir.actions.todo')
787 item_id=self.read(cr,uid,ids)[0]['item_id']
789 item = item_obj.browse(cr, uid, item_id, context=context)
790 item_obj.write(cr, uid, item.id, {
794 'view_mode': item.action_id.view_mode,
795 'view_type': item.action_id.view_type,
796 'view_id':item.action_id.view_id and [item.action_id.view_id.id] or False,
797 'res_model': item.action_id.res_model,
798 'type': item.action_id.type,
799 'target':item.action_id.target,
801 return self.button_next(cr, uid, ids, context)
802 ir_actions_configuration_wizard()
804 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: