Skip to content

Batch Code to create campaign members asynchonously

mscholtz edited this page Apr 3, 2012 · 1 revision

This code by Nick from Dogwood

global class GW_AddToCampaign implements Schedulable {

global void execute(SchedulableContext sc){

//if already scheduled, don't schedule it again
// check running batches in case there is already one running
 AsyncApexJob[] batchInProgress = [select id from AsyncApexJob where (status = 'Queued' or status = 'Processing') and ApexClass.Name = 'GW_AddToCampaign'];

 if (batchInProgress.size() < 1) {
  GW_AddToCampaign gwatc = new GW_AddToCampaign();
  
  //change query in tests to not modify production data
  if (!test.isrunningtest()) gwatc.createCampaignMember([SELECT Id, Campaign_Id__c, Campaign_Member_Status__c FROM Contact WHERE Campaign_Id__c!=NULL LIMIT 1000]);
  else gwatc.createCampaignMember([SELECT Id, Campaign_Id__c, Campaign_Member_Status__c FROM Contact WHERE Campaign_Id__c!=NULL AND FirstName='Tester8' LIMIT 1000]);
 }

}

public class TestException extends Exception {} public string memo;

public void createCampaignMember(list contactsToProcess){

list<CampaignMember> membershipRecords = new list<CampaignMember>();

map<id,id> contactIds = new map<id,id>();
set<string> concatIds = new set<string>();

for (Contact thisContact : contactsToProcess) contactIds.put(thisContact.id, thisContact.Campaign_Id__c);

for (CampaignMember cm:[SELECT Id, ContactId, CampaignId FROM CampaignMember WHERE ContactId in :contactIds.keySet() and CampaignId in :contactIds.values()]) {
  concatIds.add((string)cm.ContactId + ((string)cm.CampaignId).tolowercase().substring(0,15));
}
  
for (Contact thisContact : contactsToProcess) {
  
  if (thisContact.Campaign_Id__c != NULL && !concatIds.contains(thisContact.Id + thisContact.Campaign_Id__c.tolowercase())) {
    CampaignMember cmContact = new CampaignMember (        
      CampaignId=thisContact.Campaign_Id__c,
      ContactId=thisContact.Id
    );
    
    if (thisContact.Campaign_Member_Status__c!=null) cmContact.Status = thisContact.Campaign_Member_Status__c;
    
    membershipRecords.add(cmContact);
  } else system.debug('This Contact already has a CampaignMember: '+thisContact);
}

boolean membersInserted = false;

try{
  // test exception handling!
  if (this.memo == 'cause exception') throw new TestException('You asked, we delivered: your exception!');
  
  if (membershipRecords.size()>0) insert membershipRecords;
  membersInserted=true;
          
              
} catch (System.Exception ex) {
  /*if (StatusCode.UNABLE_TO_LOCK_ROW==ex.getDmlType(0)) {
    system.debug('UNABLE_TO_LOCK_ROW received');
  }*/
  
  Messaging.reserveSingleEmailCapacity(1);
  Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
  mail.setToAddresses(new String[] {'[email protected]'});
  mail.setSubject('Dogwood Campaign Error');
  mail.setPlainTextBody('Exception: ' + ex +' Contacts: ' + contactsToProcess);    
  Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
  
  Datetime sysTime = System.now().addMinutes(5);
  String chron_exp = '' + sysTime.second() + ' ' + sysTime.minute() + ' ' + sysTime.hour() + ' ' + sysTime.day() + ' ' + sysTime.month() + ' ? ' + sysTime.year();
  GW_AddToCampaign batch = new GW_AddToCampaign();
  System.schedule('GW_AddToCampaign scheduled job ' + sysTime.getTime(), chron_exp, batch);
}

//if the insert succeeded, blank the contact fields.
if (membersInserted) blankContactFields(contactIds.keyset());

}

@future //because fields on Contact can't be updated in an After Insert trigger call static void blankContactFields (set contactIds){ list contactsToBlank = [SELECT Id, Campaign_Id__c, Campaign_Member_Status__c FROM Contact WHERE Id in :contactIds];

for (Contact c: contactsToBlank) {
  c.Campaign_Id__c = null;
  c.Campaign_Member_Status__c = null;
}

update contactsToBlank;

}

static testmethod void addMember(){ Campaign tc = new Campaign( Name='Foobar', isactive=true ); insert tc;

CampaignMemberStatus cms = new CampaignMemberStatus(
  Label='FOO',
  CampaignId = tc.id,
  HasResponded=true,
  SortOrder = 8
);
insert cms;

list<Contact> testcons = new list<Contact>();

for(integer i=0;i<5;i++) {
  Contact c = new Contact(
    FirstName='Tester8',
    LastName='LN_'+i,
    Email='[email protected]',
    Campaign_Id__c = tc.id,
    Campaign_Member_Status__c='FOO'
  );
  testcons.add(c);
}
test.startTest();
  insert testcons;
test.stopTest();

//Verify CampaignMembers
list<CampaignMember> querycm = [SELECT Id, Status FROM CampaignMember WHERE CampaignId=:tc.id ];
system.assertequals(5, querycm.size(), 'Five Campaign Members should be created');
system.assertequals('FOO', querycm[0].Status, 'Status should be set correctly');

//Verify Contact fields are blanked out
list<Contact> querycon = [SELECT Id, Campaign_Id__c, Campaign_Member_Status__c FROM Contact WHERE Email='[email protected]'];
system.assertequals(null,querycon[0].Campaign_Id__c,'Campaign_Id__c should be null');
system.assertequals(null,querycon[0].Campaign_Member_Status__c,'Campaign_Member_Status__c should be null');

}

static testmethod void existingCampaignMember(){

GW_AddToCampaign atc = new GW_AddToCampaign();

Campaign tc = new Campaign(
  Name='Foobar',
  isactive=true
);
insert tc;

Contact con = new Contact(
  LastName='o,o',
  FirstName='Tester8',
  Email='[email protected]'
);
insert con;

//setting this variables after insert so the trigger doesn't fire
con.Campaign_Id__c = tc.id;

update con;

CampaignMember cm = new CampaignMember(
  ContactId = con.id,
  CampaignId = tc.id
);
insert cm;

atc.createCampaignMember([SELECT Id, Campaign_Id__c, Campaign_Member_Status__c FROM Contact WHERE ID=:con.id]);

}

static testmethod void testException(){

GW_AddToCampaign atc = new GW_AddToCampaign();
atc.memo='cause exception';

Campaign tc = new Campaign(
  Name='Foobar',
  isactive=true
);
insert tc;

Contact con = new Contact(
  LastName='o,o',
  FirstName='Tester8',
  Email='[email protected]'
);
insert con;

//setting this variables after insert so the trigger doesn't fire
con.Campaign_Id__c = tc.id;
update con;
    
    test.startTest();
    
//this should fail gracefully
     atc.createCampaignMember([SELECT Id, Campaign_Id__c, Campaign_Member_Status__c FROM Contact WHERE id=:con.id ]);

    list<CampaignMember> cm = [SELECT Id, Status FROM CampaignMember WHERE CampaignId=:tc.id ];
system.assertequals(0, cm.size(), 'Campaign Member should not exist due to the exception thrown');

// causes queued code to run.
test.stopTest();

cm = [SELECT Id, Status FROM CampaignMember WHERE CampaignId=:tc.id ];
system.assertequals(1, cm.size(), 'Campaign Member should be created');

} }

Clone this wiki locally