+ Start a Discussion
pierrefrazny.ax358pierrefrazny.ax358 

Trigger to create Campaign Member Status automatically

Is it possible to use a trigger to automate the creation of Campaign Member Status? For example, when a campaign of certain type is created, I would like to automatically add 'Show', 'No show' i nthe list of Campaign Member Status. Is it possible?

Thanks

Pierre 

Best Answer chosen by Admin (Salesforce Developers) 
jkucerajkucera

Yup-create an After Insert trigger on Campaign to create the statuses.  Sytax is similar to this post here:

http://community.salesforce.com/sforce/board/message?message.uid=163776

 

 I haven't checked this syntax, but something like this should work:

trigger createStatuses on Campaign (after Insert){
for (Campaign c: trigger.new){
CampaignMemberStatus cms1 = new CampaignMemberStatus(CampaignId=c.Id, HasResponded=true, Label='Show', SortOrder=1);
CampaignMemberStatus cms2 = new CampaignMemberStatus(CampaignId=c.Id, HasResponded=False, Label='No Show', SortOrder=2);

insert new List<CampaignMemberStatus>{cms1, cms2};

}

 

All Answers

jkucerajkucera

Yup-create an After Insert trigger on Campaign to create the statuses.  Sytax is similar to this post here:

http://community.salesforce.com/sforce/board/message?message.uid=163776

 

 I haven't checked this syntax, but something like this should work:

trigger createStatuses on Campaign (after Insert){
for (Campaign c: trigger.new){
CampaignMemberStatus cms1 = new CampaignMemberStatus(CampaignId=c.Id, HasResponded=true, Label='Show', SortOrder=1);
CampaignMemberStatus cms2 = new CampaignMemberStatus(CampaignId=c.Id, HasResponded=False, Label='No Show', SortOrder=2);

insert new List<CampaignMemberStatus>{cms1, cms2};

}

 

This was selected as the best answer
pierrefrazny.ax358pierrefrazny.ax358

John,

This worked great! thanks.

Do you know if it is possible to change the label of the default Campaign Member Status (Sent and Responded)? What if I would like in a trigger to rename 'Responded' to  'Show' for example.

Thanks 

 

jkucerajkucera

Yes - you'd query for the existing statuses and then update the label:

 

Id campID='yourCampaignId'; List<CampaignMemberStatus> cms=[Select Id, Label FROM CampaignMemberStatus WHERE CampaignID=campID]; for (CampaignMemberStatus cm:cms){ if(cm.Label='Responded'){ cm.Label='Show'; } }

 

 

 

Eric_SantiagoEric_Santiago

There's a few issues with the two code samples above. The first has a DML statement in a for loop which could cause problems with governer limits. The second will fail because 'Label' is not an updateable field on the CampaignMemberStatus record. Here a sample that will remove the two default member status values and replace them each time a campaign of a certain record type is added.

 

 

trigger CampaignCommitteeStatus on Campaign (after insert) { //change default member statuses (Sent and Responded) for select campaigns Set <Id> cmpns = new Set <Id>(); for (Campaign c: trigger.new){ if (c.RecordTypeId == '01240000000M1hh') cmpns.add(c.Id); } List<CampaignMemberStatus> cms2Delete = new List<CampaignMemberStatus>(); List<CampaignMemberStatus> cms2Insert = new List<CampaignMemberStatus>(); for (CampaignMemberStatus cm: [Select Id, Label, CampaignID FROM CampaignMemberStatus WHERE CampaignID IN :cmpns]){ if(cm.Label == 'Responded' ){ CampaignMemberStatus cms1 = new CampaignMemberStatus(CampaignId=cm.CampaignID, Label='Active', HasResponded=true, IsDefault = True, SortOrder=3); System.debug(cms1); cms2Delete.add(cm); cms2Insert.add(cms1); } else if(cm.Label == 'Sent'){ CampaignMemberStatus cms2 = new CampaignMemberStatus(CampaignId=cm.CampaignID, Label='Retired', HasResponded=false, SortOrder=4); System.debug(cms2); cms2Delete.add(cm); cms2Insert.add(cms2); } } //perform insert before delete because system requires at least one CMS for a Campaign insert cms2Insert; delete cms2Delete; }

 

 

 

pierrefrazny.ax358pierrefrazny.ax358

Thanks Eric,

Indeed I could not update the label for the status 'Sent' and 'Responder'. Your code works great. The only change I made is to use a SOQL statement to get the campaign ID dynamically 

 

 

RecordType rt = [Select Id, Name from RecordType where Name = 'my campaign record type name' limit 1];

 

Thanks a lot for your post!

Pierre 

 

 

Message Edited by pierrefrazny on 01-29-2010 11:42 AM
LloydSLloydS

So it looks like the code below is for adding new statuses:

 

trigger createStatuses on Campaign (after Insert){
  for (Campaign c: trigger.new){
    CampaignMemberStatus cms1 = new CampaignMemberStatus(CampaignId=c.Id, HasResponded=true, Label='Show', SortOrder=1);	        
    CampaignMemberStatus cms2 = new CampaignMemberStatus(CampaignId=c.Id, HasResponded=False, Label='No Show', SortOrder=2);	        
 
insert new List<CampaignMemberStatus>{cms1, cms2};

}

 

And this code is for changing the default Sent and Responsed statuses:

 

 

trigger CampaignCommitteeStatus on Campaign (after insert) {
	//change default member statuses (Sent and Responded) for select campaigns
	Set <Id> cmpns = new Set <Id>();
	  
	for (Campaign c: trigger.new){ 
		if (c.RecordTypeId == '01240000000M1hh')
			cmpns.add(c.Id);
	}
	
	List<CampaignMemberStatus> cms2Delete = new List<CampaignMemberStatus>();
	List<CampaignMemberStatus> cms2Insert = new List<CampaignMemberStatus>();
	
	for (CampaignMemberStatus cm: [Select Id, Label, CampaignID  FROM CampaignMemberStatus WHERE CampaignID IN :cmpns]){
	  if(cm.Label == 'Responded' ){
			CampaignMemberStatus cms1 = new CampaignMemberStatus(CampaignId=cm.CampaignID, Label='Active', HasResponded=true, IsDefault = True, SortOrder=3);	        
	  		System.debug(cms1);
	  		cms2Delete.add(cm);
	  		cms2Insert.add(cms1);
	  }  else if(cm.Label == 'Sent'){	        
    		CampaignMemberStatus cms2 = new CampaignMemberStatus(CampaignId=cm.CampaignID, Label='Retired', HasResponded=false, SortOrder=4);
	  		System.debug(cms2);
	  		cms2Delete.add(cm);
	  		cms2Insert.add(cms2);
	  }
	}
	//perform insert before delete because system requires at least one CMS for a Campaign
	insert cms2Insert;
	delete cms2Delete; 

}

 

 

What's the best way of combining the two so that the default Sent and Responded values are changed, and other values are added?

pierrefrazny.ax358pierrefrazny.ax358

The code above actually deletes and inserts campaignmember status using the two lists "cms2Delete" and "cms2Insert".

cms2Deletecm
NaishadhNaishadh

@LloydS

 

What's the best way of combining the two so that the default Sent and Responded values are changed, and other values are added?

 

Use following steps for your solution.

1. Fetch all existing campaign member status record.

2. if Record exists update 

3. if not, find maximum number of sortorder, increment it by 1 and add new record into it.

aKallNVaKallNV

Hello Eric,

I wrote the following trigger based on what you submitted. Thanks!

 

I've just run into a snag, though. Everything works great except for when I try to Clone a campaign. When I clone a Campaign I get a Duplicate_Value error, and I'm struggling to debug. So, I'm curious to know if you've run into the same problem and have a solution.

 

 

trigger autoCampaignMemberStatusTrigger on Campaign (after insert) {
    
    List<Campaign> newCamps = [select Id, RecordType.Name from Campaign where Id IN :trigger.new AND ParentID = Null AND (RecordType.Name = 'Training' OR RecordType.Name = 'Presentation')];
    List<CampaignMemberStatus> cms = new List<CampaignMemberStatus>();
    Set<Id> camps = new Set<Id>();
    List<CampaignMemberStatus> cms2Delete = new List<CampaignMemberStatus>();
    List<CampaignMemberStatus> cms2Insert = new List<CampaignMemberStatus>();
    
    for(Campaign camp : newCamps){
       
            camps.add(camp.Id);
    }   
    
    for(CampaignMemberStatus cm : [select Id, Label, CampaignId from CampaignMemberStatus where CampaignId IN :camps]) {
            if(cm.Label == 'Sent' || cm.Label == 'Responded') {             
                 cms2Delete.add(cm);                 
            }
            
            CampaignMemberStatus cms1 = new CampaignMemberStatus(CampaignId = cm.CampaignId, HasResponded=false,
             Label = 'Invited', SortOrder = 3, isDefault = true);
             cms2Insert.add(cms1);          
            
            CampaignMemberStatus cms2 = new CampaignMemberStatus(CampaignId = cm.CampaignId, HasResponded=true,
             Label = 'Accepted', SortOrder = 4);
             cms2Insert.add(cms2);
             
            CampaignMemberStatus cms3 = new CampaignMemberStatus(CampaignId = cm.CampaignId, HasResponded=true,
             Label = 'Attended', SortOrder = 5);
             cms2Insert.add(cms3); 
             
             CampaignMemberStatus cms4 = new CampaignMemberStatus(CampaignId = cm.CampaignId, HasResponded=true,
             Label = 'Declined', SortOrder = 6);
             cms2Insert.add(cms4);
    }
    
    insert cms2Insert;
    delete cms2Delete;
}

 

 

TNiemanTNieman

The default check box is not getting set (see the Invited new status below).  Any ideas?

 

trigger autoCampaignMemberStatusTrigger on Campaign (after insert) {
   
    List<Campaign> newCamps = [select Id from Campaign where Id IN :trigger.new AND ParentID = Null];
    List<CampaignMemberStatus> cms = new List<CampaignMemberStatus>();
    Set<Id> camps = new Set<Id>();
    List<CampaignMemberStatus> cms2Delete = new List<CampaignMemberStatus>();
    List<CampaignMemberStatus> cms2Insert = new List<CampaignMemberStatus>();
   
    for(Campaign camp : newCamps){
      
            camps.add(camp.Id);
    }  
   
    for(CampaignMemberStatus cm : [select Id, Label, CampaignId from CampaignMemberStatus where CampaignId IN :camps]) {
            if(cm.Label == 'Sent' || cm.Label == 'Responded') {            
                 cms2Delete.add(cm);                
            }
           
            CampaignMemberStatus cms1 = new CampaignMemberStatus(CampaignId = cm.CampaignId, HasResponded=false,
             Label = 'Invited', SortOrder = 3, isDefault = true);
             cms2Insert.add(cms1);         
           
            CampaignMemberStatus cms2 = new CampaignMemberStatus(CampaignId = cm.CampaignId, HasResponded=true,
             Label = 'Accepted', SortOrder = 4);
             cms2Insert.add(cms2);
            
            CampaignMemberStatus cms3 = new CampaignMemberStatus(CampaignId = cm.CampaignId, HasResponded=true,
             Label = 'Attended', SortOrder = 5);
             cms2Insert.add(cms3);
            
             CampaignMemberStatus cms4 = new CampaignMemberStatus(CampaignId = cm.CampaignId, HasResponded=true,
             Label = 'Declined', SortOrder = 6);
             cms2Insert.add(cms4);
    }
   
    insert cms2Insert;
    delete cms2Delete;
}

aKallNVaKallNV

Hey, 

I just checked my trigger and found the same problem.  I'm not sure why.  I will let you know if find anything.

TNiemanTNieman

I found a fix for the Cloning issue described above.  I created a custom checbox field for campaigns called Campaign Template.  I also created a workflow that will uncheck the Campaign Template checkbox if the Campaign Name doesn't contain the word Template.

 

I also changed the first line in the trigger to be:

 

List<Campaign> newCamps = [select Id from Campaign where Id IN :trigger.new AND ParentID = Null AND Campaign_Template__c=false];

 

The trigger fires before the field update workflow rule, so the Member Status values won't be changed.

 

When you clone a template, change the name and make sure that Template is not in the name.  The Member Status Values will be as they are in the template.

 

If you are cloning a non-template, simply check the Campaign Template checkbox before you hit Save.  Again the Member Status Values will be as in the campaign that was cloned.

 

 

Tom

aKallNVaKallNV

Hey Tom,

Here is a more recent version that solves the cloning issue. I think Bob_Buzzard helped me through it in a different post. To be honest I don't really understand it how it works, but it does work. Just posting it as food for thought since you already found your own solution.

 

trigger autoCampaignMemberStatusTrigger on Campaign (after insert) {
    
    List<Campaign> newCamps = [select Id, RecordType.Name from Campaign where Id IN :trigger.new AND (RecordType.Name = 'Training' OR RecordType.Name = 'Presentation')];
    Map<ID,Set<String>> eCMS = new Map<ID,Set<String>>();
    Set<Id> camps = new Set<Id>();
    List<CampaignMemberStatus> cms2Delete = new List<CampaignMemberStatus>();
    List<CampaignMemberStatus> cms2Insert = new List<CampaignMemberStatus>();
    
    for(Campaign camp : newCamps){
       
            camps.add(camp.Id);
    }    
    
    for(CampaignMemberStatus CMS : [select ID, CampaignID,Label from CampaignMemberStatus where CampaignID IN :camps]) {
    	
    	Set<String> elCMS = eCMS.get(CMS.CampaignID);
    	
    	if(null == elCMS) {
    		elCMS = new Set<String>();
    		eCMS.put(CMS.CampaignId, elCMS);
    	}
    	
    	elCMS.add(CMS.Label);
    }     
    
    for(CampaignMemberStatus cm : [select Id, Label, CampaignId from CampaignMemberStatus where CampaignId IN :camps]) {
            
            if(cm.Label == 'Sent' || cm.Label == 'Responded') {             
                 cms2Delete.add(cm);                 
            }
            
            CampaignMemberStatus cms1 = new CampaignMemberStatus(CampaignId = cm.CampaignId, HasResponded=false,
             Label = 'Invited', SortOrder = 3, isDefault = true);
		     if(!eCMS.get(cm.CampaignId).contains(cms1.Label)) {
		     	cms2Insert.add(cms1);
		     }            
            
            CampaignMemberStatus cms2 = new CampaignMemberStatus(CampaignId = cm.CampaignId, HasResponded=true,
             Label = 'Accepted', SortOrder = 4);
             if(!eCMS.get(cm.CampaignId).contains(cms2.Label)) {
		     	cms2Insert.add(cms2);
		     } 
             
            CampaignMemberStatus cms3 = new CampaignMemberStatus(CampaignId = cm.CampaignId, HasResponded=true,
             Label = 'Attended', SortOrder = 5);
             if(!eCMS.get(cm.CampaignId).contains(cms3.Label)) {
		     	cms2Insert.add(cms3);
		     }  
             
             CampaignMemberStatus cms4 = new CampaignMemberStatus(CampaignId = cm.CampaignId, HasResponded=true,
             Label = 'Declined', SortOrder = 6);
             if(!eCMS.get(cm.CampaignId).contains(cms4.Label)) {
		     	cms2Insert.add(cms4);
		     } 
    }
    
   
    
    insert cms2Insert;
    delete cms2Delete;
}

 

TNiemanTNieman

aKaIINV - If you notice on the edit screen for Member Status, the Default column doesn't have checkboxes, it has option buttons. If you hover over each button they are Default1, Default2, and so on.

 

If you put isDefault = false for all of the new status values, you get an error on the delete step that you can't delete the default. So it is recognizing that the default is being changed but that data is not being saved.

 

Tom

TNiemanTNieman

I have contacted SF support - it got bumped to 2nd level - in 48-72 hours we should know more


Tom

TNiemanTNieman

Got help from SF 2nd level and got this code from them and it works properly

 

trigger autoCampaignMemberStatusTrigger on Campaign (after insert) {
   
    List<Campaign> newCamps = [select Id from Campaign where Id IN :trigger.new AND ParentID = Null AND Campaign_Template__c=false];
    List<CampaignMemberStatus> cms = new List<CampaignMemberStatus>();
    Set<Id> camps = new Set<Id>();
    List<CampaignMemberStatus> cms2Delete = new List<CampaignMemberStatus>();
    List<CampaignMemberStatus> cms2Insert = new List<CampaignMemberStatus>();
   
    for(Campaign camp : newCamps){
      
            camps.add(camp.Id);
    }  
   
   
   for (CampaignMemberStatus cm: [Select Id, Label, CampaignID  FROM CampaignMemberStatus WHERE CampaignID IN :camps]){
      if(cm.Label == 'Responded' ){
            CampaignMemberStatus cms1 = new CampaignMemberStatus(CampaignId=cm.CampaignID, Label='Email Sent', HasResponded=false, IsDefault = True, SortOrder=3);          
            System.debug(cms1);
            cms2Delete.add(cm);
            cms2Insert.add(cms1);
           
      }  else if(cm.Label == 'Sent'){          
            CampaignMemberStatus cms2 = new CampaignMemberStatus(CampaignId=cm.CampaignID, Label='Called', HasResponded=false, SortOrder=4);
            System.debug(cms2);
            cms2Delete.add(cm);
            cms2Insert.add(cms2);
           
            CampaignMemberStatus cms3 = new CampaignMemberStatus(CampaignId = cm.CampaignId, HasResponded=true, Label = 'Appointment Set', SortOrder = 5);
            cms2Insert.add(cms3);

      }
     


    }
    //perform insert before delete because system requires at least one CMS for a Campaign
    insert cms2Insert;
    delete cms2Delete;

}

AAkonsultPtyLtdAAkonsultPtyLtd

To save the hassle of writting the trigger, I have written a free App.  This will shortly be available on the AppExchange, but you can see details/install now from: http://www.aakonsult.com/AAKCampaignStatus.html

VIP Condos TorontoVIP Condos Toronto
Thanks AAkonsult, I just installed your campaign status app and it's working great! Also it lets you choose different campaign member status based on the campaign type which is even more than I could have asked for!
Kelly King 30Kelly King 30
Thank you to all whom have commented before! As a side note, if deploying an apex trigger to update the CampaignMemberStatus labels after insert of a campaign, when writing a test class, please be advised that there are some special considerations be to aware of. In short, queries of CampaignMemberStatus will fail to return the two default labels unless either hardcoded into the test class, or (seeAllData=true) is enabled. The following post has a great explanation of the issue and how to address it. https://salesforce.stackexchange.com/questions/14051
Hayley Dale 7Hayley Dale 7
Would anyone recommend trying to accomplish this same function using a combination of process builder and flows, or is trigger the best way? Thanks