[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:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user