0

I am trying to create a trigger that will override the standard Primary Campaign Source association and put the first Campaign associated with a named Contact (based on a lookup field called Sourced_By__c) as the Primary Campaign Source instead. So I am using the Limit 1 to only return the first in my sorted list.

I am fairly new to Apex development and have the written a trigger that appears to be working and am now working on a test class but I am only able to cover it 80% and need help getting it to 100%. Thanks!

Trigger:

trigger VennSci_SetPrimaryCampaign on Opportunity (after insert) {

   // Make a List of Contact ID's.
    Set<Id> ContIds = new Set<Id>();
    for(Opportunity OPP: Trigger.new) contIds.add(OPP.Sourced_by__c);

    // Fetch all the Campaign Members for these Contacts
    List<CampaignMember> cms= new List<CampaignMember>([
        select 
             id, contactid, campaignid,status
          from CampaignMember 
        where contactid = :contIds ORDER BY CreatedDate ASC NULLS LAST LIMIT 1

    ]);

    // Build a Map, keyed by ContId, of Lists of the related CM's
    Map<Id, List<CampaignMember>> cmMap = new Map<Id, List<CampaignMember>>();
    for (CampaignMember cm: cms) {
       if (cmMap.containsKey(cm.ContactId)) {

            List<CampaignMember> x;
            x = cmMap.get(cm.ContactId);
            x.add(cm);
            cmMap.put(cm.ContactId, x);
       } else {

            List<CampaignMember> tmp = new List<CampaignMember>();
            tmp.add(cm);
            cmMap.put(cm.ContactId, tmp);
       }
    }


List<Opportunity> OPP1 = new List<Opportunity>(); 
    if(stoprecurssion.runonce()){

   for(Opportunity newOpp: Trigger.new){

       if (cmMap.containsKey(NewOpp.Sourced_by__c)) {

           for (CampaignMember cm: cmMap.get(newOpp.Sourced_by__c)) {
                OPP1.add(
                     New Opportunity(
                        CampaignId = cm.CampaignId,
                        id=newOpp.id)


               );
          }
     }
   }
     if (! OPP1.isEmpty())  update OPP1;
    }
}

Test Class

@IsTest (SeeAllData=true) private class VennSci_TEST_SetPrimaryCampaign{

    /* This is a basic test which simulates the primary positive case for the 
       insert method of an Opportunity. */

private static testMethod void myUnitTest() {

// create an Account
Account acc=new Account(Name='test');
insert acc;                

 // create a Contact
        Contact cont = new Contact(
        Firstname='Jane',
        Lastname='Doe',
        AccountID= acc.Id

    );
    insert cont;

       // create the 1st Campaign
    Campaign c1 = new Campaign(
        name='Campaign 1',
        IsActive=true,
        StartDate=Date.newInstance(2014,01,01)
        );
    insert c1;

   // create the 2nd Campaign
    Campaign c2 = new Campaign(
        name='Campaign 2',
        IsActive=true,
        StartDate=Date.newInstance(2014,01,01)
        );
    insert c2;

    // create the ist Campaign Member
    Campaignmember cm1 = new CampaignMember(
        CampaignId=c1.Id,
        ContactID=cont.Id,
        Status='Sent'
             );
    insert cm1;

   // create the 2nd Campaign Member
    CampaignMember cm2 = new CampaignMember(
        CampaignId=c2.Id,
        ContactId=cont.Id,
        Status='Sent'
                );
    insert cm2;


    // create the opportunity
        Opportunity opp1 = new Opportunity(
        name='Test Opp 1',
        StageName = 'Closed Won',
        CloseDate = Date.newInstance(2014,01,01),
        Sourced_By__c = cont.Id 

    );
    insert opp1;


   }
   }

2 Answers 2

1

You are limiting the number of Campaign Members to return 1 by the

LIMIT 1

Statement and thus your loop never cycles more than once and the containsKey will never evaluate to true

14
  • I am definitely a beginner. The trigger seems to work but if you have any suggestions to optimize it, they are welcome.
    – Grace
    May 22, 2014 at 22:22
  • 2
    Um.... Remove the Limit 1
    – Eric
    May 22, 2014 at 22:50
  • How do you suggest resolving it. I need the limit 1 in my trigger because I only want to return the first campaign associated to the contact, unless there is another way to do that?
    – Grace
    May 23, 2014 at 2:27
  • When I remove the Limit 1 I receive this error: System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, VennSci_SetPrimaryCampaign: execution of AfterInsert caused by: System.ListException: Duplicate id in list: 006W0000004jZG8IAM Trigger.VennSci_SetPrimaryCampaign: line 52, column 1: [] (System Code)
    – Grace
    May 23, 2014 at 13:18
  • You are going to have to provide more information on what you are trying to do. You have a loop that checks to see if a map contains a key (empty to start with) but are limiting the loop to 1 record so the key will never exist. Then you are updating the opps. The parts of your code you shared tell a conflicting story. Update your question with the exact and detailed business use case and we can help better.
    – Eric
    May 23, 2014 at 13:22
0

Here is an updated version that may get you closer:

trigger VennSci_SetPrimaryCampaign on Opportunity (after insert) {

   // Make a List of Contact ID's.
    Set<Id> ContIds = new Set<Id>();
    for(Opportunity OPP: Trigger.new) contIds.add(OPP.Sourced_by__c);

    // Fetch all the Campaign Members for these Contacts
    List<CampaignMember> cms= new List<CampaignMember>([
        select 
             id, contactid, campaignid,status
          from CampaignMember 
        where contactid IN :contIds ORDER BY CreatedDate ASC NULLS LAST

    ]);

    // Build a Map, keyed by ContId, of Lists of the related CM's
    Map<Id, List<CampaignMember>> cmMap = new Map<Id, List<CampaignMember>>();
    for (CampaignMember cm: cms) {
       if (cmMap.containsKey(cm.ContactId)) {
        cmMap.get(cm.ContactID).add(cm);
       } else {
        cmMap.put(cm.ContactID,New CampaignMember[]{cm});
       }
    }


Map<ID,Opportunity> OPP1 = new Map<ID,Opportunity>(); 
    if(stoprecurssion.runonce()){

   for(Opportunity newOpp: Trigger.new){

       if (cmMap.containsKey(NewOpp.Sourced_by__c)) {

           for (CampaignMember cm: cmMap.get(newOpp.Sourced_by__c)) {
                if(OPP1.containsKey(newOppID)){
                  if(OPP1.get(newOppID).Campaignid != cm.CampaignID){
                    //Handle multiple CampaignIDs for Same opp here
                  }
                }else{
                OPP1.put(newOppID,
                     New Opportunity(
                        CampaignId = cm.CampaignId,
                        id=newOpp.id)
                        );

                }

          }
     }
   }
     if (! OPP1.isEmpty())  update OPP1.values();
    }
}
1
  • Thanks @Eric! I tried to add an additional piece of logic here: for (CampaignMember cm: cmMap.get(newOpp.Sourced_by__c)) to prevent the primary campaign from populating with the first campaign in the system if the sourced by is blank but it didn't work. Do you have any suggestions for preventing this from firing if sourced by is blank?
    – Grace
    May 28, 2014 at 15:18

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .