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([
123 ], string='Type', required=True),
124 'groups_id': fields.many2many('res.groups', 'res_groups_report_rel', 'uid', 'gid', 'Groups'),
125 '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.'),
126 '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.')
129 'type': lambda *a: 'ir.actions.report.xml',
130 'multi': lambda *a: False,
131 'auto': lambda *a: True,
132 'header': lambda *a: True,
133 'report_sxw_content': lambda *a: False,
134 'report_type': lambda *a: 'pdf',
135 'attachment': lambda *a: False,
140 class act_window(osv.osv):
141 _name = 'ir.actions.act_window'
142 _table = 'ir_act_window'
143 _sequence = 'ir_actions_id_seq'
145 # def search(self, cr, uid, args, offset=0, limit=2000, order=None,
146 # context=None, count=False):
147 # if context is None:
149 # ids = osv.orm.orm.search(self, cr, uid, args, offset, limit, order,
153 # user_groups = self.pool.get('res.users').read(cr, uid, [uid])[0]['groups_id']
155 # for act in self.browse(cr, uid, ids):
156 # if not len(act.groups_id):
157 # result.append(act.id)
159 # for g in act.groups_id:
160 # if g.id in user_groups:
161 # result.append(act.id)
165 def _views_get_fnc(self, cr, uid, ids, name, arg, context={}):
167 for act in self.browse(cr, uid, ids):
168 res[act.id]=[(view.view_id.id, view.view_mode) for view in act.view_ids]
169 modes = act.view_mode.split(',')
170 if len(modes)>len(act.view_ids):
173 res[act.id].append((act.view_id.id, act.view_id.type))
174 for t in modes[len(act.view_ids):]:
175 if act.view_id and (t == act.view_id.type) and not find:
178 res[act.id].append((False, t))
182 'name': fields.char('Action Name', size=64, translate=True),
183 'type': fields.char('Action Type', size=32, required=True),
184 'view_id': fields.many2one('ir.ui.view', 'View Ref.', ondelete='cascade'),
185 'domain': fields.char('Domain Value', size=250),
186 'context': fields.char('Context Value', size=250),
187 'res_model': fields.char('Object', size=64),
188 'src_model': fields.char('Source Object', size=64),
189 'target': fields.selection([('current','Current Window'),('new','New Window')], 'Target Window'),
190 'view_type': fields.selection((('tree','Tree'),('form','Form')),string='Type of view'),
191 'view_mode': fields.char('Mode of view', size=250),
192 'usage': fields.char('Action Usage', size=32),
193 'view_ids': fields.one2many('ir.actions.act_window.view', 'act_window_id', 'Views'),
194 'views': fields.function(_views_get_fnc, method=True, type='binary', string='Views'),
195 'limit': fields.integer('Limit', help='Default limit for the list view'),
196 'auto_refresh': fields.integer('Auto-Refresh',
197 help='Add an auto-refresh on the view'),
198 'groups_id': fields.many2many('res.groups', 'ir_act_window_group_rel',
199 'act_id', 'gid', 'Groups'),
202 'type': lambda *a: 'ir.actions.act_window',
203 'view_type': lambda *a: 'form',
204 'view_mode': lambda *a: 'tree,form',
205 'context': lambda *a: '{}',
206 'limit': lambda *a: 80,
207 'target': lambda *a: 'current',
208 'auto_refresh': lambda *a: 0,
212 class act_window_view(osv.osv):
213 _name = 'ir.actions.act_window.view'
214 _table = 'ir_act_window_view'
215 _rec_name = 'view_id'
217 'sequence': fields.integer('Sequence'),
218 'view_id': fields.many2one('ir.ui.view', 'View'),
219 'view_mode': fields.selection((
223 ('calendar', 'Calendar'),
224 ('gantt', 'Gantt')), string='Type of view', required=True),
225 'act_window_id': fields.many2one('ir.actions.act_window', 'Action', ondelete='cascade'),
226 'multi': fields.boolean('On multiple doc.',
227 help="If set to true, the action will not be displayed on the right toolbar of a form views."),
230 'multi': lambda *a: False,
235 class act_wizard(osv.osv):
236 _name = 'ir.actions.wizard'
237 _table = 'ir_act_wizard'
238 _sequence = 'ir_actions_id_seq'
240 'name': fields.char('Wizard info', size=64, required=True, translate=True),
241 'type': fields.char('Action type', size=32, required=True),
242 'wiz_name': fields.char('Wizard name', size=64, required=True),
243 '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."),
244 'groups_id': fields.many2many('res.groups', 'res_groups_wizard_rel', 'uid', 'gid', 'Groups'),
245 'model': fields.char('Object', size=64),
248 'type': lambda *a: 'ir.actions.wizard',
249 'multi': lambda *a: False,
253 class act_url(osv.osv):
254 _name = 'ir.actions.url'
255 _table = 'ir_act_url'
256 _sequence = 'ir_actions_id_seq'
258 'name': fields.char('Action Name', size=64, translate=True),
259 'type': fields.char('Action Type', size=32, required=True),
260 'url': fields.text('Action Url',required=True),
261 'target': fields.selection((
262 ('new', 'New Window'),
263 ('self', 'This Window')),
264 'Action Target', required=True
268 'type': lambda *a: 'ir.actions.act_url',
269 'target': lambda *a: 'new'
273 def model_get(self, cr, uid, context={}):
274 wkf_pool = self.pool.get('workflow')
275 ids = wkf_pool.search(cr, uid, [])
276 osvs = wkf_pool.read(cr, uid, ids, ['osv'])
279 mpool = self.pool.get('ir.model')
281 model = osv.get('osv')
282 id = mpool.search(cr, uid, [('model','=',model)])
283 name = mpool.read(cr, uid, id)[0]['name']
284 res.append((model, name))
288 class ir_model_fields(osv.osv):
289 _inherit = 'ir.model.fields'
290 _rec_name = 'field_description'
292 'complete_name': fields.char('Complete Name', size=64, select=1),
295 def name_search(self, cr, uid, name, args=None, operator='ilike', context=None, limit=800):
296 def get_fields(cr, uid, field, rel):
298 mobj = self.pool.get('ir.model')
299 id = mobj.search(cr, uid, [('model','=',rel)])
301 obj = self.pool.get('ir.model.fields')
302 ids = obj.search(cr, uid, [('model_id','in',id)])
303 records = obj.read(cr, uid, ids)
304 for record in records:
306 fld = field + '/' + record['name']
308 result.append((id, fld))
315 return super(ir_model_fields, self).name_search(cr, uid, name, args, operator, context, limit)
317 if context.get('key') != 'server_action':
318 return super(ir_model_fields, self).name_search(cr, uid, name, args, operator, context, limit)
321 obj = self.pool.get('ir.model.fields')
322 ids = obj.search(cr, uid, args)
323 records = obj.read(cr, uid, ids)
324 for record in records:
326 field = record['name']
328 if record['ttype'] == 'many2one':
329 rel = record['relation']
330 res = get_fields(cr, uid, field, record['relation'])
334 result.append((id, field))
337 obj.write(cr, uid, [rs[0]], {'complete_name':rs[1]})
343 result = super(ir_model_fields, self).name_search(cr, uid, name, [('complete_name','ilike',name), ('id','in',iids)], operator, context, limit)
349 class server_object_lines(osv.osv):
350 _name = 'ir.server.object.lines'
351 _sequence = 'ir_actions_id_seq'
353 'server_id': fields.many2one('ir.actions.server', 'Object Mapping'),
354 'col1': fields.many2one('ir.model.fields', 'Destination', required=True),
355 'value': fields.text('Value', required=True),
356 'type': fields.selection([
358 ('equation','Formula')
359 ], 'Type', required=True, size=32, change_default=True),
362 'type': lambda *a: 'equation',
364 server_object_lines()
367 # Actions that are run on the server side
369 class actions_server(osv.osv):
371 def _select_signals(self, cr, uid, context={}):
372 cr.execute("select distinct t.signal as key, t.signal || ' - [ ' || w.osv || ' ] ' as val from wkf w, wkf_activity a, wkf_transition t "\
373 " where w.id = a.wkf_id " \
374 " and t.act_from = a.wkf_id " \
375 " or t.act_to = a.wkf_id and t.signal not in (null, NULL)")
376 result = cr.fetchall() or []
379 if not rs[0] == None and not rs[1] == None:
383 _name = 'ir.actions.server'
384 _table = 'ir_act_server'
385 _sequence = 'ir_actions_id_seq'
388 'name': fields.char('Action Name', required=True, size=64, help="Easy to Refer action by name i.e. One Sales Order -> Many Invoice"),
389 '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"),
390 'state': fields.selection([
391 ('client_action','Client Action'),
393 ('loop','Iteration'),
394 ('code','Python Code'),
395 ('trigger','Trigger'),
398 ('object_create','Create Object'),
399 ('object_write','Write Object'),
400 ('other','Multi Actions'),
401 ], 'Action Type', required=True, size=32, help="Type of the Action that is to be execute"),
402 'code':fields.text('Python Code', help="python code to be execute"),
403 '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"),
404 'model_id': fields.many2one('ir.model', 'Object', required=True, help="select the obect on which the action will work (read, write, create)"),
405 'action_id': fields.many2one('ir.actions.actions', 'Client Action', help="Select the Ation Window, Report, Wizard to be execute"),
406 'trigger_name': fields.selection(_select_signals, string='Trigger Name', size=128, help="Select the Signal name that is to be "),
407 'wkf_model_id': fields.many2one('ir.model', 'Workflow on', help="Workflow to be execute on which model"),
408 'trigger_obj_id': fields.many2one('ir.model.fields','Trigger On', help="select the object from the model on which the workflow will execute"),
409 '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"),
410 '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 ]]`"),
411 'message': fields.text('Message', translate=True, help="Specify the Message, you can use the fields from the object. like `Dear [[ object.partner_id.name ]]`"),
412 '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"),
413 'sms': fields.char('SMS', size=160, translate=True),
414 'child_ids': fields.many2many('ir.actions.server', 'rel_server_actions', 'server_id', 'action_id', 'Others Actions'),
415 'usage': fields.char('Action Usage', size=32),
416 'type': fields.char('Action Type', size=32, required=True),
417 '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"),
418 'fields_lines': fields.one2many('ir.server.object.lines', 'server_id', 'Fields Mapping'),
419 '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"),
420 '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"),
421 '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"),
422 '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`"),
425 'state': lambda *a: 'dummy',
426 'condition': lambda *a: 'True',
427 'type': lambda *a: 'ir.actions.server',
428 'sequence': lambda *a: 5,
429 'code': lambda *a: """# You can use the following variables
436 # If you plan to return an action, assign: action = {...}
440 def get_email(self, cr, uid, action, context):
441 logger = netsvc.Logger()
442 obj_pool = self.pool.get(action.model_id.model)
443 id = context.get('active_id')
444 obj = obj_pool.browse(cr, uid, id)
448 if '/' in action.email.complete_name:
449 fields = action.email.complete_name.split('/')
450 elif '.' in action.email.complete_name:
451 fields = action.email.complete_name.split('.')
455 obj = getattr(obj, field)
457 logger.notifyChannel('Workflow', netsvc.LOG_ERROR, 'Failed to parse : %s' % (field))
461 def get_mobile(self, cr, uid, action, context):
462 logger = netsvc.Logger()
463 obj_pool = self.pool.get(action.model_id.model)
464 id = context.get('active_id')
465 obj = obj_pool.browse(cr, uid, id)
469 if '/' in action.mobile.complete_name:
470 fields = action.mobile.complete_name.split('/')
471 elif '.' in action.mobile.complete_name:
472 fields = action.mobile.complete_name.split('.')
476 obj = getattr(obj, field)
478 logger.notifyChannel('Workflow', netsvc.LOG_ERROR, 'Failed to parse : %s' % (field))
482 def merge_message(self, cr, uid, keystr, action, context):
483 logger = netsvc.Logger()
485 obj_pool = self.pool.get(action.model_id.model)
486 id = context.get('active_id')
487 obj = obj_pool.browse(cr, uid, id)
488 exp = str(match.group()[2:-2]).strip()
489 result = eval(exp, {'object':obj, 'context': context,'time':time})
490 if result in (None, False):
491 return str("--------")
494 com = re.compile('(\[\[.+?\]\])')
495 message = com.sub(merge, keystr)
499 # Context should contains:
501 # id : current id of the object
503 # False : Finnished correctly
504 # ACTION_ID : Action to launch
506 def run(self, cr, uid, ids, context={}):
507 logger = netsvc.Logger()
509 for action in self.browse(cr, uid, ids, context):
510 obj_pool = self.pool.get(action.model_id.model)
511 obj = obj_pool.browse(cr, uid, context['active_id'], context=context)
520 expr = eval(str(action.condition), cxt)
524 if action.state=='client_action':
525 if not action.action_id:
526 raise osv.except_osv(_('Error'), _("Please specify an action to launch !"))
527 result = self.pool.get(action.action_id.type).read(cr, uid, action.action_id.id, context=context)
530 if action.state=='python':
532 'self': self.pool.get(action.model_id.model),
539 exec action.code in localdict
540 if 'action' in localdict:
541 return localdict['action']
543 if action.state == 'email':
544 user = config['email_from']
545 address = str(action.email)
547 address = eval(str(action.email), cxt)
552 raise osv.except_osv(_('Error'), _("Please specify the Partner Email address !"))
554 raise osv.except_osv(_('Error'), _("Please specify server option --smtp-from !"))
556 subject = self.merge_message(cr, uid, str(action.subject), action, context)
557 body = self.merge_message(cr, uid, str(action.message), action, context)
559 if tools.email_send(user, [address], subject, body, debug=False, subtype='html') == True:
560 logger.notifyChannel('email', netsvc.LOG_INFO, 'Email successfully send to : %s' % (address))
562 logger.notifyChannel('email', netsvc.LOG_ERROR, 'Failed to send email to : %s' % (address))
564 if action.state == 'trigger':
565 wf_service = netsvc.LocalService("workflow")
566 model = action.wkf_model_id.model
567 obj_pool = self.pool.get(action.model_id.model)
568 res_id = self.pool.get(action.model_id.model).read(cr, uid, [context.get('active_id')], [action.trigger_obj_id.name])
569 id = res_id [0][action.trigger_obj_id.name]
570 wf_service.trg_validate(uid, model, int(id), action.trigger_name, cr)
572 if action.state == 'sms':
573 #TODO: set the user and password from the system
574 # for the sms gateway user / password
577 to = self.get_mobile(cr, uid, action, context)
578 #TODO: Apply message mearge with the field
579 if tools.sms_send(user, password, api_id, text, to) == True:
580 logger.notifyChannel('sms', netsvc.LOG_INFO, 'SMS successfully send to : %s' % (action.address))
582 logger.notifyChannel('sms', netsvc.LOG_ERROR, 'Failed to send SMS to : %s' % (action.address))
584 if action.state == 'other':
586 for act in action.child_ids:
587 context['active_id'] = context['active_ids'][0]
588 result = self.run(cr, uid, [act.id], context)
594 if action.state == 'loop':
595 obj_pool = self.pool.get(action.model_id.model)
596 obj = obj_pool.browse(cr, uid, context['active_id'], context=context)
605 expr = eval(str(action.expression), cxt)
606 context['object'] = obj
608 context['active_id'] = i.id
609 result = self.run(cr, uid, [action.loop_action.id], context)
611 if action.state == 'object_write':
613 for exp in action.fields_lines:
615 if exp.type == 'equation':
616 obj_pool = self.pool.get(action.model_id.model)
617 obj = obj_pool.browse(cr, uid, context['active_id'], context=context)
618 cxt = {'context':context, 'object': obj, 'time':time}
619 expr = eval(euq, cxt)
622 res[exp.col1.name] = expr
624 if not action.write_id:
625 if not action.srcmodel_id:
626 obj_pool = self.pool.get(action.model_id.model)
627 obj_pool.write(cr, uid, [context.get('active_id')], res)
629 write_id = context.get('active_id')
630 obj_pool = self.pool.get(action.srcmodel_id.model)
631 obj_pool.write(cr, uid, [write_id], res)
633 elif action.write_id:
634 obj_pool = self.pool.get(action.srcmodel_id.model)
635 rec = self.pool.get(action.model_id.model).browse(cr, uid, context.get('active_id'))
636 id = eval(action.write_id, {'object': rec})
640 raise osv.except_osv(_('Error'), _("Problem in configuration `Record Id` in Server Action!"))
642 if type(id) != type(1):
643 raise osv.except_osv(_('Error'), _("Problem in configuration `Record Id` in Server Action!"))
645 obj_pool.write(cr, uid, [write_id], res)
647 if action.state == 'object_create':
649 for exp in action.fields_lines:
651 if exp.type == 'equation':
652 obj_pool = self.pool.get(action.model_id.model)
653 obj = obj_pool.browse(cr, uid, context['active_id'], context=context)
654 expr = eval(euq, {'context':context, 'object': obj, 'time':time})
657 res[exp.col1.name] = expr
661 obj_pool = self.pool.get(action.srcmodel_id.model)
662 res_id = obj_pool.create(cr, uid, res)
665 self.pool.get(action.model_id.model).write(cr, uid, [context.get('active_id')], {action.record_id.name:res_id})
671 class act_window_close(osv.osv):
672 _name = 'ir.actions.act_window_close'
673 _table = 'ir_actions'
674 _sequence = 'ir_actions_id_seq'
676 'name': fields.char('Action Name', size=64, translate=True),
677 'type': fields.char('Action Type', size=32, required=True),
680 'type': lambda *a: 'ir.actions.act_window_close',
684 # This model use to register action services.
685 # if action type is 'configure', it will be start on configuration wizard.
686 # if action type is 'service',
687 # - if start_type= 'at once', it will be start at one time on start date
688 # - if start_type='auto', it will be start on auto starting from start date, and stop on stop date
689 # - if start_type="manual", it will start and stop on manually
690 class ir_actions_todo(osv.osv):
691 _name = 'ir.actions.todo'
693 'name':fields.char('Name',size=64,required=True, select=True),
694 'note':fields.text('Text', translate=True),
695 'start_date': fields.datetime('Start Date'),
696 'end_date': fields.datetime('End Date'),
697 'action_id':fields.many2one('ir.actions.act_window', 'Action', select=True,required=True, ondelete='cascade'),
698 'sequence':fields.integer('Sequence'),
699 'active': fields.boolean('Active'),
700 'type':fields.selection([('configure', 'Configure'),('service', 'Service'),('other','Other')], string='Type', required=True),
701 'start_on':fields.selection([('at_once', 'At Once'),('auto', 'Auto'),('manual','Manual')], string='Start On'),
702 'groups_id': fields.many2many('res.groups', 'res_groups_act_todo_rel', 'act_todo_id', 'group_id', 'Groups'),
703 'users_id': fields.many2many('res.users', 'res_users_act_todo_rel', 'act_todo_id', 'user_id', 'Users'),
704 'state':fields.selection([('open', 'Not Started'),('done', 'Done'),('skip','Skipped'),('cancel','Cancel')], string='State', required=True)
707 'state': lambda *a: 'open',
708 'sequence': lambda *a: 10,
709 'active':lambda *a:True,
710 'type':lambda *a:'configure'
715 # This model to use run all configuration actions
716 class ir_actions_configuration_wizard(osv.osv_memory):
717 _name='ir.actions.configuration.wizard'
718 def next_configuration_action(self,cr,uid,context={}):
719 item_obj = self.pool.get('ir.actions.todo')
720 item_ids = item_obj.search(cr, uid, [('type','=','configure'),('state', '=', 'open'),('active','=',True)], limit=1, context=context)
721 if item_ids and len(item_ids):
722 item = item_obj.browse(cr, uid, item_ids[0], context=context)
725 def _get_action_name(self, cr, uid, context={}):
726 next_action=self.next_configuration_action(cr,uid,context=context)
728 return next_action.note
730 return "Your database is now fully configured.\n\nClick 'Continue' and enjoy your OpenERP experience..."
733 def _get_action(self, cr, uid, context={}):
734 next_action=self.next_configuration_action(cr,uid,context=context)
736 return next_action.id
739 def _progress_get(self,cr,uid, context={}):
740 total = self.pool.get('ir.actions.todo').search_count(cr, uid, [], context)
741 todo = self.pool.get('ir.actions.todo').search_count(cr, uid, [('type','=','configure'),('active','=',True),('state','<>','open')], context)
742 return max(5.0,round(todo*100/total))
745 'name': fields.text('Next Wizard',readonly=True),
746 'progress': fields.float('Configuration Progress', readonly=True),
747 'item_id':fields.many2one('ir.actions.todo', 'Next Configuration Wizard',invisible=True, readonly=True),
750 'progress': _progress_get,
751 'item_id':_get_action,
752 'name':_get_action_name,
754 def button_next(self,cr,uid,ids,context=None):
755 user_action=self.pool.get('res.users').browse(cr,uid,uid)
756 act_obj=self.pool.get(user_action.menu_id.type)
757 action_ids=act_obj.search(cr,uid,[('name','=',user_action.menu_id.name)])
758 action_open=act_obj.browse(cr,uid,action_ids)[0]
759 if context.get('menu',False):
761 'view_type': action_open.view_type,
762 'view_id':action_open.view_id and [action_open.view_id.id] or False,
763 'res_model': action_open.res_model,
764 'type': action_open.type,
765 'domain':action_open.domain
767 return {'type':'ir.actions.act_window_close'}
769 def button_skip(self,cr,uid,ids,context=None):
770 item_obj = self.pool.get('ir.actions.todo')
771 item_id=self.read(cr,uid,ids)[0]['item_id']
773 item = item_obj.browse(cr, uid, item_id, context=context)
774 item_obj.write(cr, uid, item.id, {
780 'res_model': 'ir.actions.configuration.wizard',
781 'type': 'ir.actions.act_window',
784 return self.button_next(cr, uid, ids, context)
786 def button_continue(self, cr, uid, ids, context=None):
787 item_obj = self.pool.get('ir.actions.todo')
788 item_id=self.read(cr,uid,ids)[0]['item_id']
790 item = item_obj.browse(cr, uid, item_id, context=context)
791 item_obj.write(cr, uid, item.id, {
795 'view_mode': item.action_id.view_mode,
796 'view_type': item.action_id.view_type,
797 'view_id':item.action_id.view_id and [item.action_id.view_id.id] or False,
798 'res_model': item.action_id.res_model,
799 'type': item.action_id.type,
800 'target':item.action_id.target,
802 return self.button_next(cr, uid, ids, context)
803 ir_actions_configuration_wizard()
805 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: