function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
aKallNVaKallNV 

Duplicate_Value on Campaign Member Status Trigger

I have written a trigger to standardize Campaign Member Status options. It works great with one exception: it throws a Dupliacte_Value error when I try to Clone a campaign...not sure where to start with debugging.

 

 

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;
}

 

 

Best Answer chosen by Admin (Salesforce Developers) 
David SchachDavid Schach

You could query for existing values, and if they are there already, don't insert "new" ones.  Do a query and store the results in a Set, and then if !myset.contains(value) add to your list.  Otherwise, move on to the next one.

All Answers

jkucerajkucera

You are trying to add "Invited" once for every status in teh campaign that already exists (given your query of CMS).

 

This should be closer to the solution you need:

 

 

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);

           CampaignMemberStatus cms1 = new CampaignMemberStatus(CampaignId = camp.CampaignId, HasResponded=false,
             Label = 'Invited', SortOrder = 3, isDefault = true);
             cms2Insert.add(cms1);          
            
            CampaignMemberStatus cms2 = new CampaignMemberStatus(CampaignId = camp.CampaignId, HasResponded=true,
             Label = 'Accepted', SortOrder = 4);
             cms2Insert.add(cms2);
             
            CampaignMemberStatus cms3 = new CampaignMemberStatus(CampaignId = camp.CampaignId, HasResponded=true,
             Label = 'Attended', SortOrder = 5);
             cms2Insert.add(cms3); 
             
             CampaignMemberStatus cms4 = new CampaignMemberStatus(CampaignId = camp.CampaignId, HasResponded=true,
             Label = 'Declined', SortOrder = 6);
             cms2Insert.add(cms4);
    }   
    
    for(CampaignMemberStatus cm : [select Id, Label, CampaignId from CampaignMemberStatus where CampaignId IN :camps]) {
            if(cm.Label == 'Sent' || cm.Label == 'Responded') {             
                 cms2Delete.add(cm);                 
            }
    }
    
    insert cms2Insert;
    delete cms2Delete;
}

 

 

aKallNVaKallNV

Thanks. Unfortunately, your suggestion threw the same error. However, i think your comment has helped me to understand the problem better. Since this is only happening when a Campaign is cloned the CMSs are being cloned too, and are arleady present when the trigger tries to insert the same values. I kind of already understood this but wasn't really able to ariculate it very well, until now. 

 

Anyway, it seems that the solution would be to delete all existing CMS values, not just the defaults of 'Sent' and 'Responded' or to somehow add criteria that would filter out records that resulted from a clone, but not sure how that would be done. 

jkucerajkucera

Yeah-it may be tricky as you always have to have at least 1 CMS for a campaign that is default & responded, so you may need several operations:

 - Clone

 - Add dummy CMS

 - Delete all other CMS

 - Add in desired CMS

 - Delete dummy CMS

 

You can probably merge a few steps like re-using the dummy CSM to save DML inserts/deletes.

David SchachDavid Schach

You could query for existing values, and if they are there already, don't insert "new" ones.  Do a query and store the results in a Set, and then if !myset.contains(value) add to your list.  Otherwise, move on to the next one.

This was selected as the best answer
aKallNVaKallNV

Thanks guys. I ended up with this, which seems to work. Rather than use a Set as x20d suggested, I decided to use a map because I didn't see how a set would handle a bulk trigger. Let me know if I'm mistaken.

 

Thanks for the help.

 

 

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;
}

 

 

RajnisfRajnisf
Hi


Can u plz provide me Test Class of the same code.