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
RelaxItsJustCodeRelaxItsJustCode 

I need help with a trigger that creates clone of contract and line items in bulk, Kudos given

The code below has been slightly simplified for the sake of this post.  What I have incountered is that when I need to load more than 5 or 6 contracts each with multiple contract line items if I do a straight copy it loads well in bulk, but when I try to tie in the pricebookentry table (given the pricebook2id is a constant) to get the latest list price on a product I blow up the SOQL gov.

What I need is a way of tying in the Pricebookentry table without blowing up the SOQL governer.  Please help I will give kudos if you can help me resolve this issue.

Here is the code:

Trigger ContractTriggerCreatContractAndOLIs on Contract (after update)
{

    map<id, contract>  originalToCloneMap = new map<id, contract>(); 
    
    List<Contract> ContractsToClone = [Select id, Parent_Contract__c, Status, Attn_To__c, Original_Case__c, Maintenance_out_of_sync__c, NewlyCreatedNumDays__c, 
            DateFinal__c,PrevNumberOfDays__c,
            PrevStartDate__c, PrevEndDate__c, PrevNumberOfLeapYearDays__c, Term_In_Days__c, XNumberOfDays__c, AccountId, XNumberOfLeapYearDays__c, NumberOfLeapYearDays2__c,
            SpecialTerms, FEndDate__c, FCompareDayEndDate__c, Total_Maintenance_Price__c,Months_between_start_and_end__c,Override_Total_Price__c,StartDate,
            Contract_End_Date__c, Case__c, RecordTypeId 
            from Contract where Status = 'Maintenance Paid' and Test_Contract_Clone__c = TRUE and Processed_Renewal_Contract__c = False and Id in :Trigger.newMap.keySet()];
    
    List<Contract> ContractsToInsert = new List<Contract>();
    Contract newContract = new Contract();
        
    List<Contract> ContractsToUpdate = new List<Contract>();
        
    for(Contract c: ContractsToClone)
    {
        c.Processed_Renewal_Contract__c = TRUE;
        ContractsToUpdate.add(c);
        
        cParentId = c.id;
        
        NewContract = new Contract();
         
        StartDate = c.StartDate;
        PrevStartDate = c.StartDate;
        PrevEndDate = c.Contract_End_Date__c;
        EndDate = c.Contract_End_Date__c;
        OriginalCase = c.Original_Case__c;
        MaintTermMisMatch = c.Maintenance_out_of_sync__c;
    
        PrevNumberOfDays = PrevStartDate.DaysBetween(PrevEndDate)+1;
      
        newContract.PrevNumberOfDays__c = PrevNumberOfDays;
        newContract.PrevStartDate__c = PrevStartDate;
        newContract.PrevEndDate__c = PrevEndDate;
        newContract.PrevNumberOfLeapYearDays__c = PrevNumberOfLeapYearDays;
    
        newContract.Months_between_start_and_end__c = c.StartDate.monthsBetween((c.Contract_End_Date__c +1));
              
        Integer count = 0;
               
               
        NumberOfDays = StartDate.DaysBetween(EndDate)+1;
        newContract.NewlyCreatedNumDays__c = NumberOfDays;
        NumberOfLeapYearDays = 0;
        Date CurrentDay;
        newContract.Contract_End_Date__c = c.Contract_End_Date__c.addDays((NumberOfDays));
        newContract.RecordTypeId = ServiceClass.getRecordTypesNameMap('Contract').get('Maintenance Contract').Id;
                
        newContract.SpecialTerms = c.SpecialTerms;
        newContract.Override_Total_Price__c = c.Override_Total_Price__c;
        newContract.Total_Maintenance_Price__c = c.Total_Maintenance_Price__c;
    
        newContract.StartDate = c.Contract_End_Date__c + 1;
        newContract.Attn_To__c = c.Attn_To__c;
        
        newContract.Original_Case__c = OriginalCase;
        newContract.Maintenance_out_of_sync__c = c.Maintenance_out_of_sync__c;
   
        NewContract.Status = 'Pending';
        NewContract.Accountid = c.AccountId;
        NewContract.RecordTypeId = c.RecordTypeId;
        NewContract.Parent_Contract__c = cParentId;
            
        originaltoCloneMap.put(c.id, NewContract);
        ContractsToInsert.add(NewContract);
    }
    
    Update ContractsToUpdate;
    Insert ContractsToInsert;
    
 
     
       Contract_Line_Item__c newCLI = new Contract_Line_Item__c();    
       
       List<Contract_Line_Item__c> CLIsToInsert = new List<Contract_Line_Item__c>();
 
       for(Contract_Line_Item__c cc :[Select Contract_Line_Item_Status__c, Contract__c, List_Price__c, Product_LU__c, Quantity__c, Account__c from Contract_Line_Item__c where Contract__c in :originalToCloneMap.keyset()])
        {
        
            newCLI = new Contract_Line_Item__c();
           
           newCLI.Contract__c = originaltoCloneMap.get(cc.Contract__c).id;
           newCLI.Contract_Line_Item_Status__c = 'Pending';
           newCLI.Product_LU__c = '01t7000000170yy';
           
          // PriceBookEntry cccc = [Select Id, UnitPrice from PriceBookEntry where Pricebook2Id = '01s3000000004T2' and Product2Id = : cc.Product_Lu__c Limit 1];
          // newCLI.List_Price__c = cccc.UnitPrice;
           newCLI.List_Price__c = cc.List_Price__c;
           newCLI.Product_LU__c = cc.Product_Lu__c;
           newCLI.Quantity__c = cc.Quantity__c;
           newCLI.Account__c = cc.Account__c;
           newCLI.Contract_Line_Item_Origin__c = 'Contract Clone Follow Up Contract';
                      if(cc.Contract_Line_Item_Status__c == 'Do Not Renew')
                    {
                         newCLI.Contract_Line_Item_Status__c = 'Do Not Renew';
                    }       
                    if(cc.Contract_Line_Item_Status__c == 'Cancelled')
                    {
                         newCLI.Contract_Line_Item_Status__c = 'Cancelled';
                    }  
            CLIsToInsert.add(newCLI);
            
        }   
         insert CLIsToInsert;    
}

Thank you,
S
logontokartiklogontokartik
Hi S,

Why dont you use the map to populate the Pricebook Entries first? Here is the code which should work. I am querying the PriceBook outside of for loop.

List<Contract_Line_Item__c> existingCLIs = new List<Contract_Line_Item__c>();
existingCLIs = [Select Contract_Line_Item_Status__c, Contract__c, List_Price__c, Product_LU__c, Quantity__c, Account__c from Contract_Line_Item__c where Contract__c in :originalToCloneMap.keyset()];
Set<String> productLUIds = new Set<String>();
for(Contract_Line_Item__c cl : existingCLIs){
  productLUIds.add(cl.Product_Lu__c);
}
Map<Id,PriceBookEntry> productLUPriceBookMap = new Map<Id,PriceBookEntry>();
for(PriceBookEntry pbe : [Select Id, UnitPrice,Product2Id from PriceBookEntry where Pricebook2Id = '01s3000000004T2' and Product2Id IN :productLUIds]){
   productLUPriceBookMap.put(pbe.Product2Id,pbe);
}

for(Contract_Line_Item__c cc :existingCLIs)
        {
        
            newCLI = new Contract_Line_Item__c();
           
           newCLI.Contract__c = originaltoCloneMap.get(cc.Contract__c).id;
           newCLI.Contract_Line_Item_Status__c = 'Pending';
           newCLI.Product_LU__c = '01t7000000170yy';
          
          // You can now check the map and get the unit price
          if(productLUPriceBookMap.get(cc.Product_Lu__c) != null){
            newCLI.List_Price__c = productLUPriceBookMap.get(cc.Product_Lu__c).UnitPrice;
          }
           
          // PriceBookEntry cccc = [Select Id, UnitPrice from PriceBookEntry where Pricebook2Id = '01s3000000004T2' and Product2Id = : cc.Product_Lu__c Limit 1];
          // newCLI.List_Price__c = cccc.UnitPrice;
         //  newCLI.List_Price__c = cc.List_Price__c;
           newCLI.Product_LU__c = cc.Product_Lu__c;
           newCLI.Quantity__c = cc.Quantity__c;
           newCLI.Account__c = cc.Account__c;
           newCLI.Contract_Line_Item_Origin__c = 'Contract Clone Follow Up Contract';
                      if(cc.Contract_Line_Item_Status__c == 'Do Not Renew')
                    {
                         newCLI.Contract_Line_Item_Status__c = 'Do Not Renew';
                    }       
                    if(cc.Contract_Line_Item_Status__c == 'Cancelled')
                    {
                         newCLI.Contract_Line_Item_Status__c = 'Cancelled';
                    }  
            CLIsToInsert.add(newCLI);
            
        }   
         insert CLIsToInsert;



Also, qq. Is there a reason why you are using after update instead of before update? The reason I asked is you are explicitly doing an update to ContractsToUpdate, instead of you use before update, you can avoid that update. 

I am also assuming you have code to not go into the loop for the trigger? 

Anyways. Hope this helps.

Thank you




RelaxItsJustCodeRelaxItsJustCode
No I haven't tried this on a before update approach.

The for() code is almost the same as above in the real trigger minus a lot of variables and leap year crap.

I haven't had the chance to try the above but I really appriciate your help.  I will give it a go and let you know how it works out.

Thanks,
S