4

We have several custom objects that can be related to Leads and that should end up related to the resulting Account/Contact/Opp during Lead Conversion. These Objects have multiple Lookup fields on them (one for Lead, then at least one for Account and/or Contact and/or Opp). When the Lead is converted, the relationships of these "child" records should change to the Account/Contact/Opp that the Lead was converted to.

I found a code recipe in the AppExchange which I modified for my needs. It assumed only a single Custom Object though, so I made an attempt to make it work for multiple objects. The Trigger is working well and the related child records are reassociated to the appropriate Account/Contact/Opp during Conversion. However, there is something amiss because the Test Class is failing due to too many SOQL queries on the 2nd test method for "static testMethod void testBulkUpdate()" (the last half/third of the Test Class).

Is there a different/better/more-efficient way to write the Trigger or Class to work on multiple objects? I'm very new on Apex code, not a "developer" but have learned enough to modify existing code.


Trigger:

trigger LeadConvertCustomObjects on Lead (before update) {
//This trigger will associate Custom Object records with the Account, Contact, and/or      opportunity associated to the 
//lead after it has been converted.
//The Custom Object is associated to an opportunity only if an opportunity record exist on the Lead.
for (Integer i = 0; i < Trigger.new.size(); i++){
    if (Trigger.new[i].IsConverted == true && Trigger.old[i].isConverted == false){
        Set<Id> leadIds = new Set<Id>();
        for (Lead lead : Trigger.new) 
            leadIds.add(lead.Id);

        Map<Id, DocuSign_Account__c> entries_DSA = new Map<Id, DocuSign_Account__c>([select Account__c, Lead__c from DocuSign_Account__c where lead__c in :leadIds]);        
        if(!Trigger.new.isEmpty()) {
            for (Lead lead : Trigger.new)  {
                for (DocuSign_Account__c DSA : entries_DSA.values()) {
                    if (DSA.Lead__c == lead.Id) {
                        // DSA.contact__c = lead.ConvertedContactId;
                        // DSA.opportunity__c = lead.ConvertedOpportunityId;
                        DSA.account__c = lead.ConvertedAccountId;
                        update DSA;
                        // break;
                    }
                }
            }
        }

        Map<Id, DocuSign_Account_Member__c> entries_DSAM = new Map<Id, DocuSign_Account_Member__c>([select Contact__c, Lead__c from DocuSign_Account_Member__c where lead__c in :leadIds]);        
        if(!Trigger.new.isEmpty()) {
            for (Lead lead : Trigger.new)  {
                for (DocuSign_Account_Member__c DSAM : entries_DSAM.values()) {
                    if (DSAM.Lead__c == lead.Id) {
                        DSAM.Contact__c = lead.ConvertedContactId;
                        // DSAM.opportunity__c = lead.ConvertedOpportunityId;
                        // DSAM.account__c = lead.ConvertedAccountId;
                        update DSAM;
                        // break;
                    }
                }
            }
        }

        Map<Id, Use_Case__c> entries_UC = new Map<Id, Use_Case__c>([select Account__c, Lead__c from Use_Case__c where lead__c in :leadIds]);        
        if(!Trigger.new.isEmpty()) {
            for (Lead lead : Trigger.new)  {
                for (Use_Case__c UC : entries_UC.values()) {
                    if (UC.Lead__c == lead.Id) {
                        // UC.contact__c = lead.ConvertedContactId;
                        // UC.opportunity__c = lead.ConvertedOpportunityId;
                        UC.account__c = lead.ConvertedAccountId;
                        update UC;
                        // break;
                    }
                }
            }
        }

        Map<Id, Ecosystem__c> entries_ECO = new Map<Id, Ecosystem__c>([select Account__c, Lead__c from Ecosystem__c where lead__c in :leadIds]);        
        if(!Trigger.new.isEmpty()) {
            for (Lead lead : Trigger.new)  {
                for (Ecosystem__c ECO : entries_ECO.values()) {
                    if (ECO.Lead__c == lead.Id) {
                        // ECO.contact__c = lead.ConvertedContactId;
                        // ECO.opportunity__c = lead.ConvertedOpportunityId;
                        ECO.account__c = lead.ConvertedAccountId;
                        update ECO;
                        // break;
                    }
                }
            }
        }

        Map<Id, Partner_Influence__c> entries_PI = new Map<Id, Partner_Influence__c>([select Account__c, Lead__c from Partner_Influence__c where lead__c in :leadIds]);        
        if(!Trigger.new.isEmpty()) {
            for (Lead lead : Trigger.new)  {
                for (Partner_Influence__c PI : entries_PI.values()) {
                    if (PI.Lead__c == lead.Id) {
                        // PI.contact__c = lead.ConvertedContactId;
                        PI.opportunity__c = lead.ConvertedOpportunityId;
                        PI.account__c = lead.ConvertedAccountId;
                        update PI;
                        // break;
                    }
                }
            }
        }

        Map<Id, Qualification_Credit__c> entries_QC = new Map<Id, Qualification_Credit__c>([select Account__c, Lead__c from Qualification_Credit__c where lead__c in :leadIds]);        
        if(!Trigger.new.isEmpty()) {
            for (Lead lead : Trigger.new)  {
                for (Qualification_Credit__c QC : entries_QC.values()) {
                    if (QC.Lead__c == lead.Id) {
                        // QC.contact__c = lead.ConvertedContactId;
                        QC.opportunity__c = lead.ConvertedOpportunityId;
                        QC.account__c = lead.ConvertedAccountId;
                        update QC;
                        // break;
                    }
                }
            }
        }


    }
}

}

Test Class

@isTest
//This is a test case for a situation where a lead will be converted.  The developer must explicitly call the convert lead
//method to simulate the user action.

private class TestLeadConvertCustomObjects {
    static testMethod void TestReferralUpdate() {
    // Insert the Lead
    List<Lead> leads = new List<Lead>();
    Lead leadt = new Lead (FirstName ='fname', LastName ='test', Company ='myCompany');
    insert leadt;
    // Insert the DocuSign_Account__c Record 
    DocuSign_Account__c DSA = new DocuSign_Account__c (Lead__c = leadt.Id);
    insert DSA;
    // Insert the DocuSign_Account_Member__c Record
    DocuSign_Account_Member__c DSAM = new DocuSign_Account_Member__c (Lead__c = leadt.Id, DocuSign_Account__c = DSA.Id);
    insert DSAM;
    // Insert the Use_Case__c Record
    Use_Case__c UC = new Use_Case__c (Lead__c = leadt.Id, Department__c='Legal', Use_Case__c='NDAs', Status__c='Interest');
    insert UC;
    // Insert a Partner Account Record with a Partner Go To Market to relate Ecosystem & Partner Influence to
    Account PartnerAccount = new Account (Name='PartnerAccount', Partner_Go_To_Market_Count_Active__c=1);
    insert PartnerAccount;
    Partner_Go_To_Market__c PGTM = new Partner_Go_To_Market__c (Name='PartnerGoToMarket', Account__c = PartnerAccount.Id, GTM_Status__c='Agreement Signed');
    insert PGTM;
    // Insert the Ecosystem__c Record
    Ecosystem__c ECO = new Ecosystem__c (Lead__c = leadt.Id, Partner__c = PartnerAccount.Id, Ecosystem_Type__c='CRM', Integration__c='Not Integrated');
    insert ECO;
    // Insert the Partner_Influence__c Record
    Partner_Influence__c PI = new Partner_Influence__c (Lead__c = leadt.Id, Partner__c = PartnerAccount.Id, Role__c='Influencer', Influence_Type__c='Neutral');
    insert PI;
    // Insert the Qualification_Credit__c Record
    Qualification_Credit__c QC = new Qualification_Credit__c (Lead__c = leadt.Id, Status__c='Qualified');
    insert QC;

//test.startTest();

//Convert the Lead
Database.LeadConvert lc = new database.LeadConvert();
lc.setLeadId(leadt.Id);
LeadStatus convertStatus = [Select Id, MasterLabel from LeadStatus where MasterLabel='Contact Created Only' AND IsConverted=true limit 1];
lc.setConvertedStatus(convertStatus.MasterLabel);
Database.LeadConvertResult lcr = Database.convertLead(lc);    

//Requery for the referral record to see if it is updated
DocuSign_Account__c ref_upd_DSA = [select Account__c from DocuSign_Account__c where Lead__c = :leadt.Id];
DocuSign_Account_Member__c ref_upd_DSAM = [select Contact__c from DocuSign_Account_Member__c where Lead__c = :leadt.Id];
Use_Case__c ref_upd_UC = [select Account__c from Use_Case__c where Lead__c = :leadt.Id];
Ecosystem__c ref_upd_ECO = [select Account__c from Ecosystem__c where Lead__c = :leadt.Id];
Partner_Influence__c ref_upd_PI = [select Account__c, Opportunity__c from Partner_Influence__c where Lead__c = :leadt.Id];
Qualification_Credit__c ref_upd_QC = [select Account__c, Opportunity__c, Contact__c from Qualification_Credit__c where Lead__c = :leadt.Id];

//Check that the test passed
    System.assertEquals(ref_upd_DSA.Account__c,[Select ConvertedAccountId From Lead Where Id = :DSA.Lead__c].ConvertedAccountId);
    System.assertEquals(ref_upd_DSAM.Contact__c,[Select ConvertedContactId From Lead Where Id = :DSAM.Lead__c].ConvertedContactId);
    System.assertEquals(ref_upd_UC.Account__c,[Select ConvertedAccountId From Lead Where Id = :UC.Lead__c].ConvertedAccountId);
    System.assertEquals(ref_upd_ECO.Account__c,[Select ConvertedAccountId From Lead Where Id = :ECO.Lead__c].ConvertedAccountId);
    System.assertEquals(ref_upd_PI.Account__c,[Select ConvertedAccountId From Lead Where Id = :PI.Lead__c].ConvertedAccountId);
    System.assertEquals(ref_upd_QC.Account__c,[Select ConvertedAccountId From Lead Where Id = :QC.Lead__c].ConvertedAccountId);
    System.assertEquals(ref_upd_QC.Contact__c,[Select ConvertedContactId From Lead Where Id = :QC.Lead__c].ConvertedContactId);
    System.assertEquals(ref_upd_PI.Opportunity__c,[Select ConvertedOpportunityId From Lead Where Id = :PI.Lead__c].ConvertedOpportunityId);
    System.assertEquals(ref_upd_QC.Opportunity__c,[Select ConvertedOpportunityId From Lead Where Id = :QC.Lead__c].ConvertedOpportunityId);       

//Test if no opty is created
string NoOpty = 'Y';    
if (NoOpty =='Y'){
  Lead leadto = new Lead (FirstName ='fnameo', LastName ='testo', Company ='myCompanyo');
      insert leadto;
      // Insert the custom object record 
      // CustomObject__c customobjecto = new CustomObject__c (Lead__c = leadto.Id);
      // insert customobjecto;
      // Insert the DocuSign_Account__c Record 
      DocuSign_Account__c DSAo = new DocuSign_Account__c (Lead__c = leadto.Id);
      insert DSAo;
      // Insert the DocuSign_Account_Member__c Record
      DocuSign_Account_Member__c DSAMo = new DocuSign_Account_Member__c (Lead__c = leadto.Id, DocuSign_Account__c = DSAo.Id);
      insert DSAMo;    
      // Insert the Use_Case__c Record
      Use_Case__c UCo = new Use_Case__c (Lead__c = leadto.Id, Department__c='Legal', Use_Case__c='NDAs', Status__c='Interest');
      insert UCo;
      // Insert a Partner Account Record with a Partner Go To Market to relate Ecosystem & Partner Influence to
      Account PartnerAccounto = new Account (Name='PartnerAccounto', Partner_Go_To_Market_Count_Active__c=1);
      insert PartnerAccounto;
      Partner_Go_To_Market__c PGTMo = new Partner_Go_To_Market__c (Name='PartnerGoToMarketo', Account__c = PartnerAccounto.Id, GTM_Status__c='Agreement Signed');
      insert PGTMo;
      // Insert the Ecosystem__c Record
      Ecosystem__c ECOo = new Ecosystem__c (Lead__c = leadto.Id, Partner__c = PartnerAccounto.Id, Ecosystem_Type__c='CRM', Integration__c='Not Integrated');
      insert ECOo;
      // Insert the Partner_Influence__c Record
      Partner_Influence__c PIo = new Partner_Influence__c (Lead__c = leadto.Id, Partner__c = PartnerAccounto.Id, Role__c='Influencer', Influence_Type__c='Neutral');
      insert PIo;
      // Insert the Qualification_Credit__c Record
      Qualification_Credit__c QCo = new Qualification_Credit__c (Lead__c = leadto.Id, Status__c='Qualified');
      insert QCo;




  Database.LeadConvert lco = new database.LeadConvert();
  lco.setLeadId(leadto.Id);
  lco.isDoNotCreateOpportunity();
  lco.setDoNotCreateOpportunity(true);
  LeadStatus convertStatuso = [Select Id, MasterLabel from LeadStatus where MasterLabel='Contact Created Only' AND IsConverted=true limit 1];
  lco.setConvertedStatus(convertStatuso.MasterLabel);
  Database.LeadConvertResult lcro = Database.convertLead(lco); 

  DocuSign_Account__c ref_updo_DSA = [select Account__c from DocuSign_Account__c where Lead__c = :leadto.Id];
  DocuSign_Account_Member__c ref_updo_DSAM = [select Contact__c from DocuSign_Account_Member__c where Lead__c = :leadto.Id];
  Use_Case__c ref_updo_UC = [select Account__c from Use_Case__c where Lead__c = :leadto.Id];
  Ecosystem__c ref_updo_ECO = [select Account__c from Ecosystem__c where Lead__c = :leadto.Id];
  Partner_Influence__c ref_updo_PI = [select Account__c, Opportunity__c from Partner_Influence__c where Lead__c = :leadto.Id];
  Qualification_Credit__c ref_updo_QC = [select Account__c, Opportunity__c, Contact__c from Qualification_Credit__c where Lead__c = :leadto.Id];


  //Check that the test passed
      System.assertEquals(ref_updo_DSA.Account__c,[Select ConvertedAccountId From Lead Where Id = :DSAo.Lead__c].ConvertedAccountId);
      System.assertEquals(ref_updo_DSAM.Contact__c,[Select ConvertedContactId From Lead Where Id = :DSAMo.Lead__c].ConvertedContactId);
      System.assertEquals(ref_updo_UC.Account__c,[Select ConvertedAccountId From Lead Where Id = :UCo.Lead__c].ConvertedAccountId);
      System.assertEquals(ref_updo_ECO.Account__c,[Select ConvertedAccountId From Lead Where Id = :ECOo.Lead__c].ConvertedAccountId);
      System.assertEquals(ref_updo_PI.Account__c,[Select ConvertedAccountId From Lead Where Id = :PIo.Lead__c].ConvertedAccountId);
      System.assertEquals(ref_updo_QC.Account__c,[Select ConvertedAccountId From Lead Where Id = :QCo.Lead__c].ConvertedAccountId);
      System.assertEquals(ref_updo_QC.Contact__c,[Select ConvertedContactId From Lead Where Id = :QCo.Lead__c].ConvertedContactId);
      System.assertEquals(ref_updo_PI.Opportunity__c,[Select ConvertedOpportunityId From Lead Where Id = :PIo.Lead__c].ConvertedOpportunityId);
      System.assertEquals(ref_updo_QC.Opportunity__c,[Select ConvertedOpportunityId From Lead Where Id = :QCo.Lead__c].ConvertedOpportunityId);       
      // System.assert(ref_updo__DSA.Opportunity__c == null);

//test.stopTest();
}  
}

  static testMethod void testBulkUpdate() {
    List<Lead> leads = new List<Lead>();       
    for (Integer i=0;i<5;i++) {
        Lead l = new Lead (FirstName ='bulk', LastName ='Test', Company ='myCompanyo');
    insert l;
    // Insert the Custom Record 
     DocuSign_Account__c DSAr = new DocuSign_Account__c (Lead__c = l.Id);
     insert DSAr;
     DocuSign_Account_Member__c DSAMr = new DocuSign_Account_Member__c (Lead__c = l.Id, DocuSign_Account__c = DSAr.Id);
     insert DSAMr;
     // Insert the Use_Case__c Record
     Use_Case__c UCr = new Use_Case__c (Lead__c = l.Id, Department__c='Legal', Use_Case__c='NDAs', Status__c='Interest');
     insert UCr;
     // Insert a Partner Account Record with a Partner Go To Market to relate Ecosystem & Partner Influence to
     Account PartnerAccountr = new Account (Name='PartnerAccountBulk', Partner_Go_To_Market_Count_Active__c=1);
     insert PartnerAccountr;
     Partner_Go_To_Market__c PGTMr = new Partner_Go_To_Market__c (Name='PartnerGoToMarketBulk', Account__c = PartnerAccountr.Id, GTM_Status__c='Agreement Signed');
     insert PGTMr;
     // Insert the Ecosystem__c Record
     Ecosystem__c ECOr = new Ecosystem__c (Lead__c = l.Id, Partner__c = PartnerAccountr.Id, Ecosystem_Type__c='CRM', Integration__c='Not Integrated');
     insert ECOr;
     // Insert the Partner_Influence__c Record
     Partner_Influence__c PIr = new Partner_Influence__c (Lead__c = l.Id, Partner__c = PartnerAccountr.Id, Role__c='Influencer', Influence_Type__c='Neutral');
     insert PIr;
     // Insert the Qualification_Credit__c Record
     Qualification_Credit__c QCr = new Qualification_Credit__c (Lead__c = l.Id, Status__c='Qualified');
     insert QCr;


      test.startTest();

      //Convert the Lead
  Database.LeadConvert lcb = new database.LeadConvert();
  lcb.setLeadId(l.Id);
  LeadStatus convertStatusb = [Select Id, MasterLabel from LeadStatus where MasterLabel='Contact Created Only' AND IsConverted=true limit 1];
  lcb.setConvertedStatus(convertStatusb.MasterLabel);
  Database.LeadConvertResult lcrb = Database.convertLead(lcb);

  DocuSign_Account__c bulkup_DSA = [select Account__c from DocuSign_Account__c where Lead__c =:l.Id];
  DocuSign_Account_Member__c bulkup_DSAM = [select Contact__c from DocuSign_Account_Member__c where Lead__c =:l.Id];
  Use_Case__c bulkup_UC = [select Account__c from Use_Case__c where Lead__c = :l.Id];
  Ecosystem__c bulkup_ECO = [select Account__c from Ecosystem__c where Lead__c = :l.Id];
  Partner_Influence__c bulkup_PI = [select Account__c, Opportunity__c from Partner_Influence__c where Lead__c = :l.Id];
  Qualification_Credit__c bulkup_QC = [select Account__c, Opportunity__c, Contact__c from Qualification_Credit__c where Lead__c = :l.Id];

  //Check that the test has passed
      System.assertEquals(bulkup_DSA.Account__c,[Select ConvertedAccountId From Lead Where Id = :DSAr.Lead__c].ConvertedAccountId);
      System.assertEquals(bulkup_DSAM.Contact__c,[Select ConvertedContactId From Lead Where Id = :DSAMr.Lead__c].ConvertedContactId);
      System.assertEquals(bulkup_UC.Account__c,[Select ConvertedAccountId From Lead Where Id = :UCr.Lead__c].ConvertedAccountId);
      System.assertEquals(bulkup_ECO.Account__c,[Select ConvertedAccountId From Lead Where Id = :ECOr.Lead__c].ConvertedAccountId);
      System.assertEquals(bulkup_PI.Account__c,[Select ConvertedAccountId From Lead Where Id = :PIr.Lead__c].ConvertedAccountId);
      System.assertEquals(bulkup_QC.Account__c,[Select ConvertedAccountId From Lead Where Id = :QCr.Lead__c].ConvertedAccountId);
      System.assertEquals(bulkup_QC.Contact__c,[Select ConvertedContactId From Lead Where Id = :QCr.Lead__c].ConvertedContactId);
      System.assertEquals(bulkup_PI.Opportunity__c,[Select ConvertedOpportunityId From Lead Where Id = :PIr.Lead__c].ConvertedOpportunityId);
      System.assertEquals(bulkup_QC.Opportunity__c,[Select ConvertedOpportunityId From Lead Where Id = :QCr.Lead__c].ConvertedOpportunityId);       
      // System.assertEquals(bulkup.Opportunity__c,[Select ConvertedOpportunityId From Lead Where Id = :r.Lead__c].ConvertedOpportunityId);


     }  
  }
}
  • By the way, note that if we comment out the "for (Integer i=0;i<5;i++)" the test passes, but then we're not testing for bulk update. – Jason Paquette May 14 '13 at 20:16
2

The problem is that all of your queries are in the opening for loop, that loops over the trigger set. By my quick glance, they don't have to be. A common pattern that you see in triggers is that the trigger often starts with building a collection of sobjects or ids, then a query based on that collection, and then some action on either the original trigger set or related records.

In this case, the collection of ids is in the initial for loop, but that loop never gets closed.

In fact, I don't understand this whole initial block of code:

for (Integer i = 0; i < Trigger.new.size(); i++){
if (Trigger.new[i].IsConverted == true && Trigger.old[i].isConverted == false){
    Set<Id> leadIds = new Set<Id>();
    for (Lead lead : Trigger.new) 
        leadIds.add(lead.Id);

You are looping through the leads in the trigger set with the first for loop and then looping through them again within that loop. The set of leadIds needs to be declared outside of the first for loop so the variable that is accessible throughout the trigger. Then you need to close this block of code above before you start any of these code blocks:

Map<Id, DocuSign_Account__c> entries_DSA = new Map<Id, DocuSign_Account__c>([select Account__c, Lead__c from DocuSign_Account__c where lead__c in :leadIds]);        
    if(!Trigger.new.isEmpty()) {
        for (Lead lead : Trigger.new)  {

Hope that helps, I can get more detailed if need be.

For reference, the DeveloperForce wiki has a good article on best practices around architecting triggers:

http://wiki.developerforce.com/page/Apex_Code_Best_Practices

  • I don't understand that top part of the trigger either, but it was part of the code recipe so I didn't mess with it. So is it just a matter of closing with a } before I go into the Map blocks of code? – Jason Paquette May 14 '13 at 20:52
  • and moving the declaration of the set of leadids above the opening for loop, yes – greenstork May 14 '13 at 20:54
  • I don't really think you need that second for loop either, you can lose it and change the code to this leadIds.add(lead[i].id); – greenstork May 14 '13 at 20:56
  • Sorry, that should have read leadIds.add(Trigger.new[i].id); – greenstork May 14 '13 at 21:03
2

You're performing a lot of SOQL Queries in your for loop in the failing test method.

The number of select statements multiplied by the number of iterations in your for-loop is causing the Governor Limit (100 SOQL Queries) to be violated.

Also, your bulk update test method is not really testing for bulk, as although its iterating over 5 leads, its only doing one at a time. I would've thought you wanted to insert 5 at once and then query after to make assertions.

So I would

  • insert all the leads with the related objects objects (within for-loop)
  • convert the leads created en masse by passing through the List of leads (outside for loop)
  • then query all accounts, contacts and related objects afterwards to make assertions.

Also worth noting the Test.startTest starts a new meter for Governor Limits (SOQL Queries, et all) which stops counting at Test.stopTest

As an aside, I'd reckon the trigger on Lead should be After Update rather than Before Update to hook into the Lead Conversion Process.

  • So I'm not a dev, but let me take a stab to see if I can understand this... static testMethod void testBulkUpdate() { List<Lead> leads = new List<Lead>(); //for (Integer i=0;i<1;i++) { // all the insert test records stuff, // then end with the curly bracket here... } // then convert... // then check... Do I get it? Or am I clueless and should wait until I can get a real dev to look at this for me? – Jason Paquette May 14 '13 at 20:49
  • Sure, hopefully that makes sense,please let me know if any questions. The thumb rule is to aggregate before queryinq - spend soql wisely :) – techtrekker May 14 '13 at 20:54
  • Yes you're on the right track with that, create in for loop, convert bulk, query bulk and then make your assertions. Also look at @greenstork's observations, he makes some valid points about unnecessary loops in your trigger. – techtrekker May 14 '13 at 20:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.