[IMP] marketing_campaign: duplicate prevention for segments can now use a unique field set on the campaign

bzr revid: odo@openerp.com-20110316182356-r7xqcmz42se6n4ms
This commit is contained in:
Olivier Dony 2011-03-16 19:23:56 +01:00
parent e48220bf9d
commit 0045ab984c
1 changed files with 49 additions and 9 deletions

View File

@ -93,7 +93,17 @@ class marketing_campaign(osv.osv):
this campaign to be run"),
'partner_field_id': fields.many2one('ir.model.fields', 'Partner Field',
domain="[('model_id', '=', object_id), ('ttype', '=', 'many2one'), ('relation', '=', 'res.partner')]",
help="The generated workitems will be linked to the partner related to the record. If the record is the partner itself leave this field empty."),
help="The generated workitems will be linked to the partner related to the record. "\
"If the record is the partner itself leave this field empty. "\
"This is useful for reporting purposes, via the Campaign Analysis or Campaign Follow-up views."),
'unique_field_id': fields.many2one('ir.model.fields', 'Unique Field',
domain="[('model_id', '=', object_id), ('ttype', 'in', ['char','int','many2one','text','selection'])]",
help='If set, this field will help segments that work in "no duplicates" mode to avoid '\
'selecting similar records twice. Similar records are records that have the same value for '\
'this unique field. For example by choosing the "email_from" field for CRM Leads you would prevent '\
'sending the same campaign to the same email address again. If not set, the "no duplicates" segments '\
"will only avoid selecting the same record again if it entered the campaign previously. "\
"Only easily comparable fields like textfields, integers, selections or single relationships may be used."),
'mode': fields.selection([('test', 'Test Directly'),
('test_realtime', 'Test in Realtime'),
('manual', 'With Manual Confirmation'),
@ -209,6 +219,30 @@ Normal - the campaign runs normally and automatically sends all emails and repor
def copy(self, cr, uid, id, default=None, context=None):
raise osv.except_osv(_("Operation not supported"), _("Sorry, campaign duplication is not supported at the moment."))
def _find_duplicate_workitems(self, cr, uid, record, campaign_rec, context=None):
"""Finds possible duplicates workitems for a record in this campaign, based on a uniqueness
field.
:param record: browse_record to find duplicates workitems for.
:param campaign_rec: browse_record of campaign
"""
Workitems = self.pool.get('marketing.campaign.workitem')
duplicate_workitem_domain = [('res_id','=', record.id),
('campaign_id','=', campaign_rec.id)]
unique_field = campaign_rec.unique_field_id
if unique_field:
unique_value = getattr(record, unique_field.name, None)
if unique_value:
if unique_field.ttype == 'many2one':
unique_value = unique_value.id
similar_res_ids = self.pool.get(campaign_rec.object_id.model).search(cr, uid,
[(unique_field.name, '=', unique_value)], context=context)
if similar_res_ids:
duplicate_workitem_domain = [('res_id','in', similar_res_ids),
('campaign_id','=', campaign_rec.id)]
return Workitems.search(cr, uid, duplicate_workitem_domain, context=context)
marketing_campaign()
class marketing_campaign_segment(osv.osv):
@ -227,13 +261,19 @@ class marketing_campaign_segment(osv.osv):
'campaign_id': fields.many2one('marketing.campaign', 'Campaign', required=True, select=1, ondelete="cascade"),
'object_id': fields.related('campaign_id','object_id', type='many2one', relation='ir.model', string='Resource'),
'ir_filter_id': fields.many2one('ir.filters', 'Filter', ondelete="restrict",
help="Filter to select the matching resource records that belong to this segment. New filters can be created and saved using the advanced search on the list view of the Resource. If no filter is set, all records are selected without filtering. The synchronization mode may also add a criterion to the filter."),
help="Filter to select the matching resource records that belong to this segment. "\
"New filters can be created and saved using the advanced search on the list view of the Resource. "\
"If no filter is set, all records are selected without filtering. "\
"The synchronization mode may also add a criterion to the filter."),
'sync_last_date': fields.datetime('Last Synchronization', help="Date on which this segment was synchronized last time (automatically or manually)"),
'sync_mode': fields.selection([('create_date', 'Only records created after last sync'),
('write_date', 'Only records modified after last sync (no duplicates)'),
('all', 'All records (no duplicates)')],
'Synchronization mode',
help="Determines an additional criterion to add to the filter when selecting new records to inject in the campaign."),
help="Determines an additional criterion to add to the filter when selecting new records to inject in the campaign. "\
'"No duplicates" prevents selecting records which have already entered the campaign previously.'\
'If the campaign has a "unique field" set, "no duplicates" will also prevent selecting records which have '\
'the same value for the unique field as other records that already entered the campaign.'),
'state': fields.selection([('draft', 'Draft'),
('running', 'Running'),
('done', 'Done'),
@ -302,6 +342,7 @@ class marketing_campaign_segment(osv.osv):
def process_segment(self, cr, uid, segment_ids=None, context=None):
Workitems = self.pool.get('marketing.campaign.workitem')
Campaigns = self.pool.get('marketing.campaign')
if not segment_ids:
segment_ids = self.search(cr, uid, [('state', '=', 'running')], context=context)
@ -324,21 +365,20 @@ class marketing_campaign_segment(osv.osv):
object_ids = model_obj.search(cr, uid, criteria, context=context)
# 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
for record in model_obj.browse(cr, uid, object_ids, context=context):
# avoid duplicate workitem for the same resource
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:
if Campaigns._find_duplicate_workitems(cr, uid, record, segment.campaign_id, context=context):
continue
wi_vals = {
'segment_id': segment.id,
'date': action_date,
'state': 'todo',
'res_id': o_ids.id
'res_id': record.id
}
partner = self.pool.get('marketing.campaign')._get_partner_for(segment.campaign_id, o_ids)
partner = self.pool.get('marketing.campaign')._get_partner_for(segment.campaign_id, record)
if partner:
wi_vals['partner_id'] = partner.id