From 6b04635f54c45bf8fac7f9e493f1cf7326d096cb Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Wed, 18 Aug 2010 17:55:29 +0200 Subject: [PATCH] [IMP] marketing_campaign: review + some improvements: - Modified workflow to support resetting Campaigns and Segments to draft after cancelling/closing - Increased size of condition field on activities - Improved logic of workitems processing - Added missing ondelete properties in model - Adapt for latest changes to email_template bzr revid: odo@openerp.com-20100818155529-31ykqaglcmi0xf2s --- .../marketing_campaign/marketing_campaign.py | 52 ++++++++++++------- .../marketing_campaign_view.xml | 7 +-- .../marketing_campaign_workflow.xml | 25 ++++++++- 3 files changed, 59 insertions(+), 25 deletions(-) diff --git a/addons/marketing_campaign/marketing_campaign.py b/addons/marketing_campaign/marketing_campaign.py index e479b835bbf..f0d6af479e7 100644 --- a/addons/marketing_campaign/marketing_campaign.py +++ b/addons/marketing_campaign/marketing_campaign.py @@ -27,6 +27,7 @@ from operator import itemgetter from traceback import format_exception from sys import exc_info from tools.safe_eval import safe_eval as eval +import re from osv import fields, osv import netsvc @@ -133,9 +134,9 @@ Normal - the campaign runs normally and automatically sends all emails and repor if activity.type != 'email': continue - if not activity.email_template_id.enforce_from_account: + if not activity.email_template_id.from_account: raise osv.except_osv(_("Error"), _("The campaign cannot be started: an email account is missing in the email activity '%s'")%activity.name) - if activity.email_template_id.enforce_from_account.state != 'approved': + if activity.email_template_id.from_account.state != 'approved': raise osv.except_osv(_("Error"), _("The campaign cannot be started: the email account is not approved in the email activity '%s'")%activity.name) if not has_start and not has_signal_without_from: @@ -211,14 +212,15 @@ class marketing_campaign_segment(osv.osv): _columns = { 'name': fields.char('Name', size=64,required=True), 'campaign_id': fields.many2one('marketing.campaign', 'Campaign', - required=True, select=1), + required=True, select=1, ondelete="cascade"), 'object_id': fields.related('campaign_id','object_id', type='many2one', relation='ir.model', string='Object'), 'ir_filter_id': fields.many2one('ir.filters', 'Filter', help=""), 'sync_last_date': fields.datetime('Latest Synchronization'), 'sync_mode': fields.selection([('create_date', 'If record created after last sync'), - ('write_date', 'If record modified after last sync (no duplicates)')], + ('write_date', 'If record modified after last sync (no duplicates)'), + ('all', 'All records (no duplicates)')], 'Workitem creation mode', help="Determines when new workitems should be created for records matching a segment."), 'state': fields.selection([('draft', 'Draft'), @@ -269,13 +271,16 @@ class marketing_campaign_segment(osv.osv): action_date = time.strftime('%Y-%m-%d %H:%M:%S') campaigns = set() for segment in self.browse(cr, uid, segment_ids, context=context): + if segment.campaign_id.state != 'running': + continue + campaigns.add(segment.campaign_id.id) act_ids = self.pool.get('marketing.campaign.activity').search(cr, uid, [('start', '=', True), ('campaign_id', '=', segment.campaign_id.id)], context=context) model_obj = self.pool.get(segment.object_id.model) criteria = [] - if segment.sync_last_date: + if segment.sync_last_date and segment.sync_mode != 'all': criteria += [(segment.sync_mode, '>', segment.sync_last_date)] if segment.ir_filter_id: criteria += eval(segment.ir_filter_id.domain) @@ -284,7 +289,7 @@ class marketing_campaign_segment(osv.osv): # XXX TODO: rewrite this loop more efficiently without doing 1 search per record! for o_ids in model_obj.browse(cr, uid, object_ids, context=context): # avoid duplicated workitem for the same resource - if segment.sync_mode == 'write_date': + if segment.sync_mode in ('write_date','all'): wi_ids = Workitems.search(cr, uid, [('res_id','=',o_ids.id),('segment_id','=',segment.id)], context=context) if wi_ids: continue @@ -332,17 +337,22 @@ class marketing_campaign_activity(osv.osv): type='many2one', relation='ir.model', string='Object', readonly=True), 'start': fields.boolean('Start', help= "This activity is launched when the campaign starts.", select=True), - 'condition': fields.char('Condition', size=256, required=True, - help="Python condition to know if the activity can be executed, otherwise it will be deleted or cancelled."), + 'condition': fields.text('Condition', size=256, required=True, + help="Python expression to decide whether the activity can be executed, otherwise it will be deleted or cancelled." + "The expression may use the following [browsable] variables:\n" + " - activity: the campaign activity\n" + " - workitem: the campaign workitem\n" + " - object: the object this campaign item represents\n" + " - transitions: list of campaign transitions outgoing from this activity\n" + "...- re: Python regular expression module"), 'type': fields.selection(_action_types, 'Type', required=True, help="Describe type of action to be performed on the Activity.Eg : Send email,Send paper.."), - 'email_template_id': fields.many2one('email.template','Email Template'), - 'report_id': fields.many2one('ir.actions.report.xml', 'Reports', ), + 'email_template_id': fields.many2one('email.template','The e-mail to send when this activity is activated'), + 'report_id': fields.many2one('ir.actions.report.xml', 'The report to generate when this activity is activated', ), 'report_directory_id': fields.many2one('document.directory','Directory', - help="Folder is used to store the generated reports"), + help="This folder is used to store the generated reports"), 'server_action_id': fields.many2one('ir.actions.server', string='Action', - help= "Describes the action name.\n" - "eg:On which object which action to be taken on basis of which condition"), + help= "The action to perform when this activity is activated"), 'to_ids': fields.one2many('marketing.campaign.transition', 'activity_from_id', 'Next Activities'), @@ -459,10 +469,10 @@ class marketing_campaign_transition(osv.osv): type='char', size=128), 'activity_from_id': fields.many2one('marketing.campaign.activity', 'Previous Activity', select=1, - required=True), + required=True, ondelete="cascade"), 'activity_to_id': fields.many2one('marketing.campaign.activity', 'Next Activity', - required=True), + required=True, ondelete="cascade"), 'interval_nbr': fields.integer('Interval Value', required=True), 'interval_type': fields.selection(_interval_units, 'Interval Unit', required=True), @@ -550,7 +560,8 @@ class marketing_campaign_workitem(osv.osv): 'activity': activity, 'workitem': workitem, 'object': object_id, - 'transition': activity.to_ids + 'transitions': activity.to_ids, + 're': re, } try: condition = activity.condition @@ -599,18 +610,19 @@ class marketing_campaign_workitem(osv.osv): } wi_id = self.create(cr, uid, values, context=context) - # Now, depending of the trigger and the campaign mode - # we know if must run the newly created workitem. + # Now, depending on the trigger and the campaign mode + # we know whether we must run the newly created workitem. # # rows = transition trigger \ colums = campaign mode # # test test_realtime manual normal (active) # time Y N N N # cosmetic N N N N - # auto Y Y Y Y + # auto Y Y N Y # - run = transition.trigger == 'auto' \ + run = (transition.trigger == 'auto' \ + and campaign_mode != 'manual') \ or (transition.trigger == 'time' \ and campaign_mode == 'test') if run: diff --git a/addons/marketing_campaign/marketing_campaign_view.xml b/addons/marketing_campaign/marketing_campaign_view.xml index 235d3ba34ce..1c0e4075b13 100644 --- a/addons/marketing_campaign/marketing_campaign_view.xml +++ b/addons/marketing_campaign/marketing_campaign_view.xml @@ -28,6 +28,7 @@