diff --git a/openerp/addons/base/ir/ir_actions.py b/openerp/addons/base/ir/ir_actions.py index 6193e2f862c..26c361d661e 100644 --- a/openerp/addons/base/ir/ir_actions.py +++ b/openerp/addons/base/ir/ir_actions.py @@ -417,7 +417,10 @@ class server_object_lines(osv.osv): _columns = { 'server_id': fields.many2one('ir.actions.server', 'Object Mapping'), 'col1': fields.many2one('ir.model.fields', 'Destination', required=True), - 'value': fields.text('Value', required=True), + 'value': fields.text('Value', required=True, help="Expression containing a value specification. \n" + "When Formula type is selected, this field may be a Python expression " + " that can use the same values as for the condition field on the server action.\n" + "If Value type is selected, the value will be used directly without evaluation."), 'type': fields.selection([ ('value','Value'), ('equation','Formula') @@ -468,8 +471,19 @@ class actions_server(osv.osv): _sequence = 'ir_actions_id_seq' _order = 'sequence,name' _columns = { - '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), - '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"), + 'name': fields.char('Action Name', required=True, size=64, translate=True), + 'condition' : fields.char('Condition', size=256, required=True, + help="Condition that is tested before the action is executed, " + "and prevent execution if it is not verified.\n" + "Example: object.list_price > 5000\n" + "It is a Python expression that can use the following values:\n" + " - self: ORM model of the record on which the action is triggered\n" + " - object or obj: browse_record of the record on which the action is triggered\n" + " - pool: ORM model pool (i.e. self.pool)\n" + " - time: Python time module\n" + " - cr: database cursor\n" + " - uid: current user id\n" + " - context: current context"), 'state': fields.selection([ ('client_action','Client Action'), ('dummy','Dummy'), @@ -483,16 +497,20 @@ class actions_server(osv.osv): ('object_write','Write Object'), ('other','Multi Actions'), ], 'Action Type', required=True, size=32, help="Type of the Action that is to be executed"), - 'code':fields.text('Python Code', help="Python code to be executed"), + 'code':fields.text('Python Code', help="Python code to be executed if condition is met.\n" + "It is a Python block that can use the same values as for the condition field"), '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."), 'model_id': fields.many2one('ir.model', 'Object', required=True, help="Select the object on which the action will work (read, write, create)."), 'action_id': fields.many2one('ir.actions.actions', 'Client Action', help="Select the Action Window, Report, Wizard to be executed."), 'trigger_name': fields.selection(_select_signals, string='Trigger Name', size=128, help="Select the Signal name that is to be used as the trigger."), 'wkf_model_id': fields.many2one('ir.model', 'Workflow On', help="Workflow to be executed on this model."), 'trigger_obj_id': fields.many2one('ir.model.fields','Trigger On', help="Select the object from the model on which the workflow will executed."), - '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"), - '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 ]]`"), - '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 ]]`"), + 'email': fields.char('Email Address', size=512, help="Expression that returns the email address to send to. Can be based on the same values as for the condition field.\n" + "Example: object.invoice_address_id.email, or 'me@example.com'"), + 'subject': fields.char('Subject', size=1024, translate=True, help="Email subject, may contain expressions enclosed in double brackets based on the same values as those " + "available in the condition field, e.g. `Hello [[ object.partner_id.name ]]`"), + 'message': fields.text('Message', translate=True, help="Email contents, may contain expressions enclosed in double brackets based on the same values as those " + "available in the condition field, e.g. `Dear [[ object.partner_id.name ]]`"), 'mobile': fields.char('Mobile No', size=512, help="Provides fields that be used to fetch the mobile number, e.g. you select the invoice, then `object.invoice_address_id.mobile` is the field which gives the correct mobile number"), 'sms': fields.char('SMS', size=160, translate=True), 'child_ids': fields.many2many('ir.actions.server', 'rel_server_actions', 'server_id', 'action_id', 'Other Actions'), @@ -511,12 +529,14 @@ class actions_server(osv.osv): 'condition': lambda *a: 'True', 'type': lambda *a: 'ir.actions.server', 'sequence': lambda *a: 5, - 'code': lambda *a: """# You can use the following variables -# - object or obj -# - time -# - cr -# - uid -# - ids + 'code': lambda *a: """# You can use the following variables: +# - self: ORM model of the record on which the action is triggered +# - object or obj: browse_record of the record on which the action is triggered +# - pool: ORM model pool (i.e. self.pool) +# - time: Python time module +# - cr: database cursor +# - uid: current user id +# - context: current context # If you plan to return an action, assign: action = {...} """, } @@ -602,12 +622,14 @@ class actions_server(osv.osv): obj_pool = self.pool.get(action.model_id.model) obj = obj_pool.browse(cr, uid, context['active_id'], context=context) cxt = { - 'context': dict(context), # copy context to prevent side-effects of eval + 'self': obj_pool, 'object': obj, - 'time':time, - 'cr': cr, + 'obj': obj, 'pool' : self.pool, - 'uid' : uid + 'cr': cr, + 'uid' : uid, + 'time':time, + 'context': dict(context), # copy context to prevent side-effects of eval } expr = eval(str(action.condition), cxt) if not expr: @@ -620,17 +642,7 @@ class actions_server(osv.osv): .read(cr, uid, action.action_id.id, context=context) if action.state=='code': - localdict = { - 'self': self.pool.get(action.model_id.model), - 'context': dict(context), # copy context to prevent side-effects of eval - 'time': time, - 'ids': ids, - 'cr': cr, - 'uid': uid, - 'object':obj, - 'obj': obj, - } - eval(action.code, localdict, mode="exec", nocopy=True) # nocopy allows to return 'action' + eval(action.code, cxt, mode="exec", nocopy=True) # nocopy allows to return 'action' if 'action' in localdict: return localdict['action'] @@ -643,17 +655,14 @@ class actions_server(osv.osv): pass if not address: - logger.info('Partner Email address not Specified!') + logger.info('Recipient email address is mandatory') continue - if not user: - logger.info('Email-From address not Specified at server!') - raise osv.except_osv(_('Error'), _("Please specify server option --email-from !")) subject = self.merge_message(cr, uid, action.subject, action, context) body = self.merge_message(cr, uid, action.message, action, context) ir_mail_server = self.pool.get('ir.mail_server') - msg = ir_mail_server.build_message(user, [address], subject, body, subtype='html') + msg = ir_mail_server.build_email(user, [address], subject, body) res_email = ir_mail_server.send_email(cr, uid, msg) if res_email: logger.info('Email successfully sent to: %s', address) @@ -663,8 +672,7 @@ class actions_server(osv.osv): if action.state == 'trigger': wf_service = netsvc.LocalService("workflow") model = action.wkf_model_id.model - obj_pool = self.pool.get(action.model_id.model) - res_id = self.pool.get(action.model_id.model).read(cr, uid, [context.get('active_id')], [action.trigger_obj_id.name]) + res_id = obj_pool.read(cr, uid, [context.get('active_id')], [action.trigger_obj_id.name]) id = res_id [0][action.trigger_obj_id.name] wf_service.trg_validate(uid, model, int(id), action.trigger_name, cr) @@ -681,20 +689,9 @@ class actions_server(osv.osv): result = self.run(cr, uid, [act.id], context) if result: res.append(result) - return res if action.state == 'loop': - obj_pool = self.pool.get(action.model_id.model) - obj = obj_pool.browse(cr, uid, context['active_id'], context=context) - cxt = { - 'context': dict(context), # copy context to prevent side-effects of eval - 'object': obj, - 'time': time, - 'cr': cr, - 'pool' : self.pool, - 'uid' : uid - } expr = eval(str(action.expression), cxt) context['object'] = obj for i in expr: @@ -706,13 +703,6 @@ class actions_server(osv.osv): for exp in action.fields_lines: euq = exp.value if exp.type == 'equation': - obj_pool = self.pool.get(action.model_id.model) - obj = obj_pool.browse(cr, uid, context['active_id'], context=context) - cxt = { - 'context': dict(context), # copy context to prevent side-effects of eval - 'object': obj, - 'time': time, - } expr = eval(euq, cxt) else: expr = exp.value @@ -746,14 +736,7 @@ class actions_server(osv.osv): for exp in action.fields_lines: euq = exp.value if exp.type == 'equation': - obj_pool = self.pool.get(action.model_id.model) - obj = obj_pool.browse(cr, uid, context['active_id'], context=context) - expr = eval(euq, - { - 'context': dict(context), # copy context to prevent side-effects of eval - 'object': obj, - 'time': time, - }) + expr = eval(euq, cxt) else: expr = exp.value res[exp.col1.name] = expr @@ -770,21 +753,11 @@ class actions_server(osv.osv): for exp in action.fields_lines: euq = exp.value if exp.type == 'equation': - obj_pool = self.pool.get(action.model_id.model) - obj = obj_pool.browse(cr, uid, context['active_id'], context=context) - expr = eval(euq, - { - 'context': dict(context), # copy context to prevent side-effects of eval - 'object': obj, - 'time': time, - }) + expr = eval(euq, cxt) else: expr = exp.value res[exp.col1.name] = expr - obj_pool = None - res_id = False - model = action.copy_object.split(',')[0] cid = action.copy_object.split(',')[1] obj_pool = self.pool.get(model)