[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
This commit is contained in:
Olivier Dony
2010-08-18 17:55:29 +02:00
parent 84aea26e88
commit 6b04635f54
3 changed files with 59 additions and 25 deletions
+32 -20
View File
@@ -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:
@@ -28,6 +28,7 @@
<group col="10" colspan="4">
<field name="state" readonly="1" select="2" nolabel="1"/>
<button name="state_running_set" string="Run" states="draft,done,cancelled" icon="gtk-apply"/>
<button name="state_draft_set" string="Set to Draft" states="done,cancelled" icon="gtk-convert"/>
<button name="state_done_set" string="Close" states="running" icon="terp-dialog-close"/>
<button name="state_cancel_set" string="Cancelled" states="running" icon="terp-gtk-stop"/>
</group>
@@ -59,7 +60,7 @@
<field name="name"/>
<field name="type"/>
<field name="start" invisible="1"/>
<field name="condition"/>
<field name="condition" widget="char"/>
</node>
<arrow object="marketing.campaign.transition" source="activity_from_id" destination="activity_to_id" label="['name']">
<field name="activity_from_id"/>
@@ -148,7 +149,7 @@
<button name="state_running_set" string="Run" states="draft" icon="gtk-apply"/>
<button name="state_done_set" string="Close" states="running" icon="terp-dialog-close"/>
<button name="state_cancel_set" string="Cancel" states="running" icon="terp-gtk-stop"/>
<button name="state_draft_set" string="Set To Draft" states="cancelled" icon="gtk-convert"/>
<button name="state_draft_set" string="Set to Draft" states="done,cancelled" icon="gtk-convert"/>
</group>
</form>
</field>
@@ -235,7 +236,7 @@
<separator string="Action" colspan="4"/>
<group colspan='4' col='4'>
<group colspan="4" col="6">
<field name="condition" colspan='5'/>
<field name="condition" colspan="5" widget="char"/>
<group col='2'>
<field name="keep_if_condition_not_met" />
</group>
@@ -15,6 +15,8 @@
<field name="wkf_id" ref="wkf_marketing_campaign"/>
<field name="flow_start">True</field>
<field name="name">draft</field>
<field name="kind">function</field>
<field name="action">write({'state':'draft'})</field>
</record>
<record id="act_marketing_campaign_running" model="workflow.activity">
@@ -34,7 +36,7 @@
<record id="act_marketing_campaign_cancel" model="workflow.activity">
<field name="wkf_id" ref="wkf_marketing_campaign"/>
<field name="name">cancel</field>
<field name="flow_stop">True</field>
<field name="flow_stop" eval="False"/>
<field name="kind">function</field>
<field name="action">state_cancel_set()</field>
</record>
@@ -57,7 +59,19 @@
<field name="act_to" ref="act_marketing_campaign_cancel"/>
<field name="signal">state_cancel_set</field>
</record>
<record id="trans_campaign_done_draft" model="workflow.transition">
<field name="act_from" ref="act_marketing_campaign_done"/>
<field name="act_to" ref="act_marketing_campaign_draft"/>
<field name="signal">state_draft_set</field>
</record>
<record id="trans_campaign_cancelled_draft" model="workflow.transition">
<field name="act_from" ref="act_marketing_campaign_cancel"/>
<field name="act_to" ref="act_marketing_campaign_draft"/>
<field name="signal">state_draft_set</field>
</record>
<!-- ==================Marketing Campaign Segment================== -->
<record id="wkf_marketing_campaign_segment" model="workflow">
@@ -94,6 +108,7 @@
<field name="name">cancel</field>
<field name="kind">function</field>
<field name="action">state_cancel_set()</field>
<field name="flow_stop" eval="False"/>
</record>
<!-- Transition -->
@@ -120,5 +135,11 @@
<field name="act_to" ref="act_marketing_campaign_segment_draft"/>
<field name="signal">state_draft_set</field>
</record>
<record id="trans_campaign_segment_done_draft" model="workflow.transition">
<field name="act_from" ref="act_marketing_campaign_segment_done"/>
<field name="act_to" ref="act_marketing_campaign_segment_draft"/>
<field name="signal">state_draft_set</field>
</record>
</data>
</openerp>