+ Start a Discussion
Morgan MarcheseMorgan Marchese 

Apex: Populate Data from One Record to Another in the same Object if they have a matching field?

Hi all, I'm new to apex but currently going through some online courses but haven't quite grasped how I can achieve this yet...

Scenario: We have a custom object from our Zuora managed package called 'Quote Charge'. Within this object are many records. Two of these records are technically 'associated' with each other, but not using a lookup field or any traditional SFDC linking. Instead, they have a custom field that shares a unique value between these 2 'associated' records. So, both of these records have a field where the value is "20150814ABCD" for example - that field is unique to these TWO records and will never be found on any other records of this object. One of these 2 records is named "Discount", and the other one can have any varying name.

Goal: I need to, using apex I presume, find these 2 matching records based on that custom field being an exact match between the 2, and then take the discount % from a field on the record named "Discount" and apply it to another custom field on the record that isn't named "Discount"

Can anyone give me a good starting point for this/point me in the right direction? I started writing some code in a class to play around with the idea, but I don't think I'm going about it the best way. Would appreciate some feedback from the SFDC Gurus.

Many thanks,

Morgan
Best Answer chosen by Morgan Marchese
Vishal_GuptaVishal_Gupta
Hi Morgan,

My assumption is that your code is executing in Before Insert, If yes please use the below code :

   public static void linkDiscountsToCharges(List<zqu__QuoteCharge__c> newQuoteCharges)
    {
        Map<String,zqu__QuoteCharge__c> discountQuoteCharge = new Map<String,zqu__QuoteCharge__c>();
        Map<String,zqu__QuoteCharge__c> nonDiscountQuoteCharge = new Map<String,zqu__QuoteCharge__c>();
        
        for(zqu__QuoteCharge__c qc: newQuoteCharges)
        {
           if(qc.Name == 'Discount')
           {
                discountQuoteCharge.put(qc.zqu__TimeProductAdded__c,qc);
           }
           else
           {
                nonDiscountQuoteCharge.put(qc.zqu__TimeProductAdded__c,qc);
           }
        }
        
        for(String uniqueValue : discountQuoteCharge.keySet())
        {
            zqu__QuoteCharge__c productQC = nonDiscountQuoteCharge.get(uniqueValue);
            zqu__QuoteCharge__c discountQC = discountQuoteCharge.get(uniqueValue);
            productQC.True_Discount__c = discountQC.zqu__EffectivePrice__c; // please use your fields in this line or apply or logic
        }
    }

Please let me know if I can help you more.

Thanks,
Vishal

All Answers

Vishal_GuptaVishal_Gupta
Hi Morgan,

I am not exactly sure what is your buisness flow means where and when(event) you want to implement your above logic but I have written below code snippet to give you basic idea to start with :

List<Quote_Charge> lstQuoteCharge = [Select Id, Name from Quote Charge where relationship_Field__c = '20150814ABCD' Limit 2];
if(lstQuoteCharge[0].name == 'Discount')
{
    //Implement logic to apply discount on lstQuoteCharge[1]
}
else
{
    //Implement logic to apply discount on lstQuoteCharge[0]
}

Please let me know if I can help you more.

Thanks,
Vishal
Morgan MarcheseMorgan Marchese

Hi Vishal,

Thanks for your reply - unfortunately I don't think that meets the need.. to be more specific, there could be 20 records added to the object at the same time, and each set of 2 records would have a matching value - so adding the value to a SQL query in the APEX won't help me since the value will change for every set of 2 that is added.

For example:

We create a quote with 10 products on it. When we save it, it creates 20 Quote Charges records (10 products and 10 discounts), each of those 10 Quote Charges has an associated Discount Quote Charge record called 'Discount' that shares that relationship field value... like this:

Product A : 20150814-1111Z
Discount:  20150814-1111Z

Product B: 20150814-2222Z
Discount: 20150814-2222Z

Product C: 20150814-3333Z
Discount: 20150814-3333Z

What I need to do is take data from the associated discount record and populate it to its associated product record. I don't care if that means I use apex to populate the actual fields or if it means I use apex to create a lookup relationship that links these 2 records together so that I can use formula fields, but ultimately the end result is that I need to carry the specific discount % from the discount record to its associated product record.

I'll share some code that I wrote as a start - but I don't know if I'm approaching this the right way:
 

public with sharing class QuoteChargeHandler
{
    public QuoteChargeHandler()
    {
        
    }

    public static void linkDiscountsToCharges(List<Zuora__QuoteCharge__c> newQuoteCharges)
    {
        // Generate a set of Quote Charge IDs
        Set<ID> chargeID = new Set<ID>();
        for(Zuora__QuoteCharge__c qc: newQuoteCharges)
        {
            chargeID.add(qc.Id);
        }

        List<Zuora__QuoteCharge__c> discountList = [SELECT Id, zqu_TimeProductAdded__c, Name FROM Zuora__QuoteCharge__c WHERE Name = 'Discount' AND Id in: chargeID];
        List<Zuora__QuoteCharge__c> nondiscountList = [SELECT Id, zqu_TimeProductAdded__c, Name FROM Zuora__QuoteCharge__c WHERE Name != 'Discount' AND Id in: chargeID];
    }

 I'm basically stuck with a situation where I've created a list of all new quote charges where name = Discount, and I've created a list where they DON'T equal discount, but now I don't know how to determine that 2 items in those 2 separate lists are a 'match' to each other, and update the associated non-discount item with data from the discount item.

Does that make more sense?

Vishal_GuptaVishal_Gupta
Hi Morgan,

Please use below code :

public static void linkDiscountsToCharges(List<Zuora__QuoteCharge__c> newQuoteCharges)
    {
        // Generate a set of Quote Charge IDs
        Set<ID> chargeID = new Set<ID>();
        for(Zuora__QuoteCharge__c qc: newQuoteCharges)
        {
            chargeID.add(qc.Id);
        }
        Map<String,Zuora__QuoteCharge__c> discountQuoteCharge = new Map<String,Zuora__QuoteCharge__c>();
        Map<String,Zuora__QuoteCharge__c> noDiscountQuoteCharge = new Map<String,Zuora__QuoteCharge__c>();
        for(Zuora__QuoteCharge__c discountQC : SELECT Id, zqu_TimeProductAdded__c, Name FROM Zuora__QuoteCharge__c WHERE Name   = 'Discount' AND Id in: chargeID)
        {
            discountQuoteCharge.put(discountList.zqu_TimeProductAdded__c,discountQC);
        }
        
        for(Zuora__QuoteCharge__c nonDiscountQC : SELECT Id, zqu_TimeProductAdded__c, Name FROM Zuora__QuoteCharge__c WHERE Name != 'Discount' AND Id in: chargeID)
        {
            discountQuoteCharge.put(nonDiscountQC.zqu_TimeProductAdded__c,nonDiscountQC);
        }
        
        for(String uniqueValue : discountQuoteCharge.keySet())
        {
            Zuora__QuoteCharge__c productQC = discountQuoteCharge.get(uniqueValue);
            Zuora__QuoteCharge__c discountQC = discountQuoteCharge.get(uniqueValue)
            productQC.applyDiscount = discountQC.discount__c; // please use your fields in this line or apply your logic
        }
    }
}

Please let me know if I can help you more.

Thanks,
Vishal
Vishal_GuptaVishal_Gupta
Hi Morgan,

Please use this code, I have mad esome changes in my last code :


public with sharing class QuoteChargeHandler
{
    public QuoteChargeHandler()
    {
        
    }

    public static void linkDiscountsToCharges(List<Zuora__QuoteCharge__c> newQuoteCharges)
    {
        // Generate a set of Quote Charge IDs
        Set<ID> chargeID = new Set<ID>();
        for(Zuora__QuoteCharge__c qc: newQuoteCharges)
        {
            chargeID.add(qc.Id);
        }
        Map<String,Zuora__QuoteCharge__c> discountQuoteCharge = new Map<String,Zuora__QuoteCharge__c>();
        Map<String,Zuora__QuoteCharge__c> nonDiscountQuoteCharge = new Map<String,Zuora__QuoteCharge__c>();
        for(Zuora__QuoteCharge__c discountQC : SELECT Id, zqu_TimeProductAdded__c, Name FROM Zuora__QuoteCharge__c WHERE Name = 'Discount' AND Id in: chargeID)
        {
            discountQuoteCharge.put(discountQC.zqu_TimeProductAdded__c,discountQC);
        }
        
        for(Zuora__QuoteCharge__c nonDiscountQC : SELECT Id, zqu_TimeProductAdded__c, Name FROM Zuora__QuoteCharge__c WHERE Name != 'Discount' AND Id in: chargeID)
        {
            nonDiscountQuoteCharge.put(nonDiscountQC.zqu_TimeProductAdded__c,nonDiscountQC );
        }
        
        for(String uniqueValue : discountQuoteCharge.keySet())
        {
            Zuora__QuoteCharge__c productQC = nonDiscountQuoteCharge.get(uniqueValue);
            Zuora__QuoteCharge__c discountQC = discountQuoteCharge.get(uniqueValue)
            productQC.applyDiscount = discountQC.discount__c; // please use your fields in this line or apply or logic
        }
    }
}

Thanks,
Vishal
Morgan MarcheseMorgan Marchese
Hi Vishal,

I put your code in, and with the exception of a few minor fixes (missing semi-colons and bad field names), it saved without any issues. I added a call to the method in my trigger and then tested it but nothing was updated on my record.. i entered my name into debug to see what was happening and I found this:


15:04:32.180 (1180867737)|SOQL_EXECUTE_BEGIN|[119]|Aggregations:0|SELECT Id, zqu__TimeProductAdded__c, Name FROM zqu__QuoteCharge__c
15:04:32.182 (1182708428)|SOQL_EXECUTE_END|[119]|Rows:0

It seems to be getting cut off at the WHERE clause and not doing the WHERE Name = 'Discount' AND Id in: chargeID

Any idea why?
 
public static void linkDiscountsToCharges(List<zqu__QuoteCharge__c> newQuoteCharges)
    {
        // Generate a set of Quote Charge IDs
        Set<ID> chargeID = new Set<ID>();
        for(zqu__QuoteCharge__c qc: newQuoteCharges)
        {
            chargeID.add(qc.Id);
        }
        Map<String,zqu__QuoteCharge__c> discountQuoteCharge = new Map<String,zqu__QuoteCharge__c>();
        Map<String,zqu__QuoteCharge__c> nonDiscountQuoteCharge = new Map<String,zqu__QuoteCharge__c>();
        for(zqu__QuoteCharge__c discountQC : [SELECT Id, zqu__TimeProductAdded__c, Name FROM zqu__QuoteCharge__c WHERE Name = 'Discount' AND Id in: chargeID])
        {
            discountQuoteCharge.put(discountQC.zqu__TimeProductAdded__c,discountQC);
        }
        
        for(zqu__QuoteCharge__c nonDiscountQC : [SELECT Id, zqu__TimeProductAdded__c, Name FROM zqu__QuoteCharge__c WHERE Name != 'Discount' AND Id in: chargeID])
        {
            nonDiscountQuoteCharge.put(nonDiscountQC.zqu__TimeProductAdded__c,nonDiscountQC );
        }
        
        for(String uniqueValue : discountQuoteCharge.keySet())
        {
            zqu__QuoteCharge__c productQC = nonDiscountQuoteCharge.get(uniqueValue);
            zqu__QuoteCharge__c discountQC = discountQuoteCharge.get(uniqueValue);
            productQC.True_Discount__c = discountQC.zqu__EffectivePrice__c; // please use your fields in this line or apply or logic
        }
    }

 
Vishal_GuptaVishal_Gupta
Hi Morgan,

Please let me know your trigger is executing in After insert or Before Insert?

Thanks,
Vishal
Vishal_GuptaVishal_Gupta
Hi Morgan,

My assumption is that your code is executing in Before Insert, If yes please use the below code :

   public static void linkDiscountsToCharges(List<zqu__QuoteCharge__c> newQuoteCharges)
    {
        Map<String,zqu__QuoteCharge__c> discountQuoteCharge = new Map<String,zqu__QuoteCharge__c>();
        Map<String,zqu__QuoteCharge__c> nonDiscountQuoteCharge = new Map<String,zqu__QuoteCharge__c>();
        
        for(zqu__QuoteCharge__c qc: newQuoteCharges)
        {
           if(qc.Name == 'Discount')
           {
                discountQuoteCharge.put(qc.zqu__TimeProductAdded__c,qc);
           }
           else
           {
                nonDiscountQuoteCharge.put(qc.zqu__TimeProductAdded__c,qc);
           }
        }
        
        for(String uniqueValue : discountQuoteCharge.keySet())
        {
            zqu__QuoteCharge__c productQC = nonDiscountQuoteCharge.get(uniqueValue);
            zqu__QuoteCharge__c discountQC = discountQuoteCharge.get(uniqueValue);
            productQC.True_Discount__c = discountQC.zqu__EffectivePrice__c; // please use your fields in this line or apply or logic
        }
    }

Please let me know if I can help you more.

Thanks,
Vishal
This was selected as the best answer
Morgan MarcheseMorgan Marchese
Hi Vishal,

Yes I am executing before Insert - I thought you couldn't execute this type of code after insert for any object that you were modifying data on because it would be in a read_only status - also since both records are being added simultaneously i thought before insert made the most sense. I'll try your revised code and report back. Thanks for all of your patience!
Morgan MarcheseMorgan Marchese
Hi Vishal,

Success! The last code changes appear to work beautifully in our Sandbox. I'm very grateful for your help in this, and I have a better understanding of how to handle this with keyMaps in the future.

I've marked your answer as Best - cheers and have a great weekend!
Morgan MarcheseMorgan Marchese
Hi Vishal,

Hoping you can help me a bit further with this. I am using the following code based on what you provided last week - and it works perfectly with before insert, but I also realized I want the productQC data to be updated if the related discountQC is updated. I added a 'before update' to my trigger and referenced it to run this class, but it returns an error about de-referencing a null object. I believe it is because in an update scenario, the DISCOUNT record gets updated but the associated PRODUCT record does not, so when the trigger tries to reference productQC it is null.

Can I get this to work with BEFORE UPDATE? Right now it only works with BEFORE INSERT since both records with the uniqueValue are inserted simultaneously. Any thoughts?
 
public static void linkDiscountsToCharges(List<zqu__QuoteCharge__c> newQuoteCharges)
    {
        Map<String,zqu__QuoteCharge__c> discountQuoteCharge = new Map<String,zqu__QuoteCharge__c>();
        Map<String,zqu__QuoteCharge__c> nonDiscountQuoteCharge = new Map<String,zqu__QuoteCharge__c>();
        
        for(zqu__QuoteCharge__c qc: newQuoteCharges)
        {
           if(qc.Name == 'Discount')
           {
                discountQuoteCharge.put(qc.zqu__TimeProductAdded__c,qc);
           }
           else
           {
                nonDiscountQuoteCharge.put(qc.zqu__TimeProductAdded__c,qc);
           }
        }
        
        for(String uniqueValue : discountQuoteCharge.keySet())
        {
            zqu__QuoteCharge__c productQC = nonDiscountQuoteCharge.get(uniqueValue);
            zqu__QuoteCharge__c discountQC = discountQuoteCharge.get(uniqueValue);
            productQC.True_Discount__c = discountQC.zqu__EffectivePrice__c; // Set True Discount Custom Field on Products to match ZQU Effective Price (Discount) from associated discount record.
            productQC.Discount_Period__c = discountQC.zqu__Upto_How_Many_Periods__c; // Set Discount Period Custom Field on Products to Match ZQU How Mnay Periods field from associated discount record.
        }
    }

 
Vishal_GuptaVishal_Gupta
Hi Morgan,

I am modifying the code, will provide you in next half an hour.

Thanks,
Vishal 
Vishal_GuptaVishal_Gupta
Hi Morgan,

Please use below code and call it in Before Insert and After Update :

public static void linkDiscountsToCharges(List<zqu__QuoteCharge__c> newQuoteCharges)
    {
        Map<String,zqu__QuoteCharge__c> discountQuoteCharge = new Map<String,zqu__QuoteCharge__c>();
        Map<String,zqu__QuoteCharge__c> nonDiscountQuoteCharge = new Map<String,zqu__QuoteCharge__c>();
        
        for(zqu__QuoteCharge__c qc: newQuoteCharges)
        {
           if(qc.Name == 'Discount')
           {
                discountQuoteCharge.put(qc.zqu__TimeProductAdded__c,qc);
           }
           else
           {
                nonDiscountQuoteCharge.put(qc.zqu__TimeProductAdded__c,qc);
           }
        }
        if(Trigger.IsInsert)
        {
            for(String uniqueValue : discountQuoteCharge.keySet())
            {
                if(nonDiscountQuoteCharge.containsKey(uniqueValue))
                {
                    zqu__QuoteCharge__c productQC = nonDiscountQuoteCharge.get(uniqueValue);
                    zqu__QuoteCharge__c discountQC = discountQuoteCharge.get(uniqueValue);
                    productQC.True_Discount__c = discountQC.zqu__EffectivePrice__c; // Set True Discount Custom Field on Products to match ZQU Effective Price (Discount) from associated discount record.
                    productQC.Discount_Period__c = discountQC.zqu__Upto_How_Many_Periods__c; // Set Discount Period Custom Field on Products to Match ZQU How Mnay Periods field from associated discount record.
                }
            }
        }
        
        if(Trigger.isAfter && Trigger.isUpdate && discountQuoteCharge.size()>0)
        {
            List<zqu__QuoteCharge__c> lstProductToUpdate = new List<zqu__QuoteCharge__c>();
            for(zqu__QuoteCharge__c prodQC : [select Id,zqu__TimeProductAdded__c,True_Discount__c,Discount_Period__c,name from zqu__QuoteCharge__c where name != 'Discount' and Id in :discountQuoteCharge.keySet()])
            {
                if(discountQuoteCharge.containsKey(prodQC.zqu__TimeProductAdded__c))
                {
                    prodQC.True_Discount__c = discountQuoteCharge.get(prodQC.zqu__TimeProductAdded__c).zqu__EffectivePrice__c;
                    prodQC.Discount_Period__c = discountQuoteCharge.get(prodQC.zqu__TimeProductAdded__c).zqu__Upto_How_Many_Periods__c;
                    lstProductToUpdate.add(prodQC);
                }
            }
            if(lstProductToUpdate.size()>0)
             update lstProductToUpdate;
            
        }
    }

Please let me know if I can help you more.

Thanks,
Vishal
Morgan MarcheseMorgan Marchese
Hi Vishal,

Unfortunately the new changes w/ an After Update don't seem to be doing the trick

Here is my trigger:
 
trigger z_QuoteChargeTrigger on zqu__QuoteCharge__c (before insert, after insert, before update, after update) {
    
    z_QuoteChargeTriggerHandler handler = new z_QuoteChargeTriggerHandler(Trigger.isExecuting, Trigger.size);
    
    if(Trigger.isInsert && Trigger.isBefore) { 
        System.Debug('Calling Before Insert handler');
        handler.OnBeforeInsert(Trigger.New);
    }
    if(Trigger.isBefore && Trigger.isInsert) {
        z_QuoteChargeTriggerHandler.linkDiscountsToCharges(Trigger.New);
    }
    
    if(Trigger.isAfter && Trigger.isUpdate) {
        z_QuoteChargeTriggerHandler.linkDiscountsToCharges(Trigger.New);
    }

And I am using your most recent code posted above. I update the discount record but the associated product record remains unchanged and the last modified time is unchanged as well so it's not even editing the record at all.

Debug:
 
14:22:54.418 (418920348)|METHOD_ENTRY|[14]|01pU0000000s3h3|z_QuoteChargeTriggerHandler.linkDiscountsToCharges(List<zqu__QuoteCharge__c>)
14:22:54.419 (419000002)|SYSTEM_MODE_ENTER|false
14:22:54.419 (419089143)|SYSTEM_METHOD_ENTRY|[114]|List<zqu__QuoteCharge__c>.iterator()
14:22:54.419 (419114316)|SYSTEM_METHOD_EXIT|[114]|List<zqu__QuoteCharge__c>.iterator()
14:22:54.419 (419126084)|SYSTEM_METHOD_ENTRY|[114]|system.ListIterator.hasNext()
14:22:54.419 (419141808)|SYSTEM_METHOD_EXIT|[114]|system.ListIterator.hasNext()
14:22:54.419 (419288050)|SYSTEM_METHOD_ENTRY|[118]|Map<String,zqu__QuoteCharge__c>.put(Object, Object)
14:22:54.419 (419318009)|SYSTEM_METHOD_EXIT|[118]|Map<String,zqu__QuoteCharge__c>.put(Object, Object)
14:22:54.419 (419328018)|SYSTEM_METHOD_ENTRY|[114]|system.ListIterator.hasNext()
14:22:54.419 (419339866)|SYSTEM_METHOD_EXIT|[114]|system.ListIterator.hasNext()
14:22:54.419 (419359756)|SYSTEM_METHOD_ENTRY|[139]|Map<String,zqu__QuoteCharge__c>.size()
14:22:54.419 (419375881)|SYSTEM_METHOD_EXIT|[139]|Map<String,zqu__QuoteCharge__c>.size()
14:22:54.419 (419388571)|SYSTEM_CONSTRUCTOR_ENTRY|[141]|<init>()
14:22:54.419 (419403444)|SYSTEM_CONSTRUCTOR_EXIT|[141]|<init>()
14:22:54.419 (419422956)|SYSTEM_METHOD_ENTRY|[142]|Map<String,zqu__QuoteCharge__c>.keySet()
14:22:54.419 (419459375)|SYSTEM_METHOD_EXIT|[142]|Map<String,zqu__QuoteCharge__c>.keySet()
14:22:54.419 (419841646)|SOQL_EXECUTE_BEGIN|[142]|Aggregations:0|SELECT Id, zqu__TimeProductAdded__c, True_Discount__c, Discount_Period__c, name FROM zqu__QuoteCharge__c 
14:22:54.422 (422513455)|SOQL_EXECUTE_END|[142]|Rows:0
14:22:54.422 (422571610)|SYSTEM_METHOD_ENTRY|[142]|Database.QueryLocator.iterator()
14:22:54.422 (422651350)|SYSTEM_METHOD_EXIT|[142]|Database.QueryLocator.iterator()
14:22:54.422 (422670281)|SYSTEM_METHOD_ENTRY|[142]|Database.QueryLocatorIterator.hasNext()
14:22:54.422 (422685330)|SYSTEM_METHOD_EXIT|[142]|Database.QueryLocatorIterator.hasNext()
14:22:54.422 (422706433)|SYSTEM_METHOD_ENTRY|[151]|List<zqu__QuoteCharge__c>.size()
14:22:54.422 (422724308)|SYSTEM_METHOD_EXIT|[151]|List<zqu__QuoteCharge__c>.size()
14:22:54.422 (422734730)|SYSTEM_MODE_EXIT|false
14:22:54.422 (422743285)|METHOD_EXIT|[14]|01pU0000000s3h3|z_QuoteChargeTriggerHandler.linkDiscountsToCharges(List<zqu__QuoteCharge__c>)

 
Vishal_GuptaVishal_Gupta
Hi Morgan,

I reviwed the code and it shoud work.

Is it possible for you to share your org for one hour with me, I will check and do changes accordingly. My email id is vishal.er.gupta@gmail.com

If there is any concern, please share complete code of Trigger and Handler, also let me know if there is any other trigger written on zqu__QuoteCharge__c.

Thanks,
Vishal
Morgan MarcheseMorgan Marchese
Hi Vishal,

I am stepping into a meeting right now so I'm worried about giving org access to our SBX while I am away from my desk (no offense, just being cautious). I can share the entire trigger/handler class with you now if that will help - though there isn't much more to it other than what you and I have been working on.

Trigger:
trigger z_QuoteChargeTrigger on zqu__QuoteCharge__c (before insert, after insert, before update, after update) {
    
    z_QuoteChargeTriggerHandler handler = new z_QuoteChargeTriggerHandler(Trigger.isExecuting, Trigger.size);
    
    if(Trigger.isInsert && Trigger.isBefore) { 
        System.Debug('Calling Before Insert handler');
        handler.OnBeforeInsert(Trigger.New);
    }
    if(Trigger.isBefore && Trigger.isInsert) {
        z_QuoteChargeTriggerHandler.linkDiscountsToCharges(Trigger.New);
    }
    
    if(Trigger.isAfter && Trigger.isUpdate) {
        z_QuoteChargeTriggerHandler.linkDiscountsToCharges(Trigger.New);
    } 
}

Handler:
public with sharing class z_QuoteChargeTriggerHandler {
    private Boolean isTriggerExecuting = false;  
    private Integer batchSize = 0;
    private final String debugStr = 'z_QuoteChargeTriggerHandler: ';

    //Constructor
    public z_QuoteChargeTriggerHandler(boolean isExecuting, integer size){
        isTriggerExecuting = isExecuting;
        batchSize = size;
    } 
    
    public void OnBeforeInsert(List<zqu__QuoteCharge__c> newList){
        if (newList != null && newList.size() > 0) {
            System.Debug(debugStr + 'OnBeforeInsert');

            //Holds set of zuora product rate plan charge ids
            Set<String> zuoraProductChargeIds = new Set<String>();
            
            //Populate zuoraProductChargeIds      
            for(zqu__QuoteCharge__c quoteCharge: newList){
                if(quoteCharge.zqu__RatePlanCharge_ZuoraID__c != null){
                    System.Debug(debugStr+'Adding zuora id '+quoteCharge.zqu__RatePlanCharge_ZuoraID__c+' to zuoraProductChargeIds');
                    zuoraProductChargeIds.add(quoteCharge.zqu__RatePlanCharge_ZuoraID__c);     
                } else {
                    System.Debug(debugStr+'quoteCharge Zuora Id is null: '+quoteCharge);
                }                       
            }

            if (zuoraProductChargeIds.size() > 0) {
                //Field Set containing fields to sync
                Schema.FieldSet productChargeFieldSet = SObjectType.zqu__ProductRatePlanCharge__c.FieldSets.getMap().get('CustomChargeFields');

                if (productChargeFieldSet != null) {

                    //Field Set information 
                    List<Schema.FieldSetMember> productChargeFields = productChargeFieldSet.getFields();

                    if (productChargeFields.size() > 0 || Test.isRunningTest()) {
                        //Set to hold fields to query from Product Rate Plan Charge
                        Set<String> chargeFields = new Set<String>();

                        //Cycle through each field in field set and add to query
                        for (Schema.FieldSetMember productChargeField : productChargeFields) {
                            chargeFields.add(productChargeField.getFieldPath());
                        }

                        if (Test.isRunningTest()) {
                            chargeFields.add('Name');
                        }

                        //Product Charge query string
                        String chargeQuery = 'SELECT Id, zqu__ZuoraId__c';
                        
                        //Cycle through Quote Fields Set and build query string
                        for (String field : chargeFields) {
                            chargeQuery += ', '+field;
                        }
                        
                        chargeQuery += ' FROM zqu__ProductRatePlanCharge__c WHERE zqu__ZuoraId__c IN :zuoraProductChargeIds AND zqu__Deleted__c = false';
                        
                        System.Debug('chargeQuery: '+chargeQuery);
                        
                        List<zqu__ProductRatePlanCharge__c> productCharges = Database.query(chargeQuery);

                        if (productCharges.size() > 0) {

                            System.Debug(debugStr+'Starting to populate Quote\'s charges');

                            //Populate Quote's charges
                            for (zqu__QuoteCharge__c quoteCharge : newList) {

                                for (zqu__ProductRatePlanCharge__c productCharge : productCharges) {

                                    if (productCharge.zqu__ZuoraId__c != null && productCharge.zqu__ZuoraId__c == quoteCharge.zqu__RatePlanCharge_ZuoraID__c) {
                                        System.Debug(debugStr+'Found matching Product Charge '+productCharge.Id+' for Quote Charge ');
                                        for (String field : chargeFields) {
                                            try {
                                                quoteCharge.put(field, productCharge.get(field));
                                                System.Debug(debugStr+'Field: '+field+', Value: '+productCharge.get(field));
                                            } catch(Exception ex) {
                                                System.Debug(debugStr+'Error pushing field \''+field+'\' from product charge to quote charge');
                                            }
                                        }
                                        break;
                                    } else {
                                        System.Debug(debugStr+'Product Charge and Quote Charge do not match. Skipping to next charge');
                                    }
                                }
                            }

                            System.Debug(debugStr+'Done populating Quote\'s charges');
                        } else {
                            System.Debug(debugStr+'Failed to retrieve any ProductRatePlanCharges based on query \''+chargeQuery+'\'');
                        }
                    } else {
                        System.Debug(debugStr+'Field Set is empty. Will not sync custom fields to quote charges');
                    }
                } else {
                    System.Debug(debugStr+'could not find fieldset \'CustomChargeFields\' on Product Rate Plan Charge object. Will not sync any custom fields');
                }
            } else {
                System.Debug(debugStr+'Failed to find any zuora product charge Ids from Quote\'s charges');
            }
        } else {
            System.Debug(debugStr + 'OnBeforeInsert, newList null or empty');
        }
     }
     
    public static void linkDiscountsToCharges(List<zqu__QuoteCharge__c> newQuoteCharges)
    {
        Map<String,zqu__QuoteCharge__c> discountQuoteCharge = new Map<String,zqu__QuoteCharge__c>();
        Map<String,zqu__QuoteCharge__c> nonDiscountQuoteCharge = new Map<String,zqu__QuoteCharge__c>();
        
        for(zqu__QuoteCharge__c qc: newQuoteCharges)
        {
           if(qc.Name == 'Discount')
           {
                discountQuoteCharge.put(qc.zqu__TimeProductAdded__c,qc);
           }
           else
           {
                nonDiscountQuoteCharge.put(qc.zqu__TimeProductAdded__c,qc);
           }
        }
        if(Trigger.IsInsert)
        {
            for(String uniqueValue : discountQuoteCharge.keySet())
            {
                if(nonDiscountQuoteCharge.containsKey(uniqueValue))
                {
                    zqu__QuoteCharge__c productQC = nonDiscountQuoteCharge.get(uniqueValue);
                    zqu__QuoteCharge__c discountQC = discountQuoteCharge.get(uniqueValue);
                    productQC.True_Discount__c = discountQC.zqu__EffectivePrice__c; // Set True Discount Custom Field on Products to match ZQU Effective Price (Discount) from associated discount record.
                    productQC.Discount_Period__c = discountQC.zqu__Upto_How_Many_Periods__c; // Set Discount Period Custom Field on Products to Match ZQU How Mnay Periods field from associated discount record.
                }
            }
        }
        
        if(Trigger.isAfter && Trigger.isUpdate && discountQuoteCharge.size()>0)
        {
            List<zqu__QuoteCharge__c> lstProductToUpdate = new List<zqu__QuoteCharge__c>();
            for(zqu__QuoteCharge__c prodQC : [select Id,zqu__TimeProductAdded__c,True_Discount__c,Discount_Period__c,name from zqu__QuoteCharge__c where name != 'Discount' and Id in :discountQuoteCharge.keySet()])
            {
                if(discountQuoteCharge.containsKey(prodQC.zqu__TimeProductAdded__c))
                {
                    prodQC.True_Discount__c = discountQuoteCharge.get(prodQC.zqu__TimeProductAdded__c).zqu__EffectivePrice__c;
                    prodQC.Discount_Period__c = discountQuoteCharge.get(prodQC.zqu__TimeProductAdded__c).zqu__Upto_How_Many_Periods__c;
                    lstProductToUpdate.add(prodQC);
                }
            }
            if(lstProductToUpdate.size()>0)
             update lstProductToUpdate;
            
        }
    }
}

The part that I don't understand is why the debug log is showing that the SOQL query was not the same as the one executed in our code:
 
14:22:54.419 (419841646)|SOQL_EXECUTE_BEGIN|[142]|Aggregations:0|SELECT Id,zqu__TimeProductAdded__c, True_Discount__c, Discount_Period__c, name FROM zqu__QuoteCharge__c

14:22:54.422 (422513455)|SOQL_EXECUTE_END|[142]|Rows:0

For some reason, it's stopping after FROM zqu__QuoteCharge__c and not including any of the WHERE arguments in the log? Is that normal?
Vishal_GuptaVishal_Gupta
Hi Morgan,

I have made small change, please use the below handler class :

public with sharing class z_QuoteChargeTriggerHandler {
    private Boolean isTriggerExecuting = false;  
    private Integer batchSize = 0;
    private final String debugStr = 'z_QuoteChargeTriggerHandler: ';

    //Constructor
    public z_QuoteChargeTriggerHandler(boolean isExecuting, integer size){
        isTriggerExecuting = isExecuting;
        batchSize = size;
    } 
    
    public void OnBeforeInsert(List<zqu__QuoteCharge__c> newList){
        if (newList != null && newList.size() > 0) {
            System.Debug(debugStr + 'OnBeforeInsert');

            //Holds set of zuora product rate plan charge ids
            Set<String> zuoraProductChargeIds = new Set<String>();
            
            //Populate zuoraProductChargeIds      
            for(zqu__QuoteCharge__c quoteCharge: newList){
                if(quoteCharge.zqu__RatePlanCharge_ZuoraID__c != null){
                    System.Debug(debugStr+'Adding zuora id '+quoteCharge.zqu__RatePlanCharge_ZuoraID__c+' to zuoraProductChargeIds');
                    zuoraProductChargeIds.add(quoteCharge.zqu__RatePlanCharge_ZuoraID__c);     
                } else {
                    System.Debug(debugStr+'quoteCharge Zuora Id is null: '+quoteCharge);
                }                       
            }

            if (zuoraProductChargeIds.size() > 0) {
                //Field Set containing fields to sync
                Schema.FieldSet productChargeFieldSet = SObjectType.zqu__ProductRatePlanCharge__c.FieldSets.getMap().get('CustomChargeFields');

                if (productChargeFieldSet != null) {

                    //Field Set information 
                    List<Schema.FieldSetMember> productChargeFields = productChargeFieldSet.getFields();

                    if (productChargeFields.size() > 0 || Test.isRunningTest()) {
                        //Set to hold fields to query from Product Rate Plan Charge
                        Set<String> chargeFields = new Set<String>();

                        //Cycle through each field in field set and add to query
                        for (Schema.FieldSetMember productChargeField : productChargeFields) {
                            chargeFields.add(productChargeField.getFieldPath());
                        }

                        if (Test.isRunningTest()) {
                            chargeFields.add('Name');
                        }

                        //Product Charge query string
                        String chargeQuery = 'SELECT Id, zqu__ZuoraId__c';
                        
                        //Cycle through Quote Fields Set and build query string
                        for (String field : chargeFields) {
                            chargeQuery += ', '+field;
                        }
                        
                        chargeQuery += ' FROM zqu__ProductRatePlanCharge__c WHERE zqu__ZuoraId__c IN :zuoraProductChargeIds AND zqu__Deleted__c = false';
                        
                        System.Debug('chargeQuery: '+chargeQuery);
                        
                        List<zqu__ProductRatePlanCharge__c> productCharges = Database.query(chargeQuery);

                        if (productCharges.size() > 0) {

                            System.Debug(debugStr+'Starting to populate Quote\'s charges');

                            //Populate Quote's charges
                            for (zqu__QuoteCharge__c quoteCharge : newList) {

                                for (zqu__ProductRatePlanCharge__c productCharge : productCharges) {

                                    if (productCharge.zqu__ZuoraId__c != null && productCharge.zqu__ZuoraId__c == quoteCharge.zqu__RatePlanCharge_ZuoraID__c) {
                                        System.Debug(debugStr+'Found matching Product Charge '+productCharge.Id+' for Quote Charge ');
                                        for (String field : chargeFields) {
                                            try {
                                                quoteCharge.put(field, productCharge.get(field));
                                                System.Debug(debugStr+'Field: '+field+', Value: '+productCharge.get(field));
                                            } catch(Exception ex) {
                                                System.Debug(debugStr+'Error pushing field \''+field+'\' from product charge to quote charge');
                                            }
                                        }
                                        break;
                                    } else {
                                        System.Debug(debugStr+'Product Charge and Quote Charge do not match. Skipping to next charge');
                                    }
                                }
                            }

                            System.Debug(debugStr+'Done populating Quote\'s charges');
                        } else {
                            System.Debug(debugStr+'Failed to retrieve any ProductRatePlanCharges based on query \''+chargeQuery+'\'');
                        }
                    } else {
                        System.Debug(debugStr+'Field Set is empty. Will not sync custom fields to quote charges');
                    }
                } else {
                    System.Debug(debugStr+'could not find fieldset \'CustomChargeFields\' on Product Rate Plan Charge object. Will not sync any custom fields');
                }
            } else {
                System.Debug(debugStr+'Failed to find any zuora product charge Ids from Quote\'s charges');
            }
        } else {
            System.Debug(debugStr + 'OnBeforeInsert, newList null or empty');
        }
     }
     
    public static void linkDiscountsToCharges(List<zqu__QuoteCharge__c> newQuoteCharges)
    {
        Map<String,zqu__QuoteCharge__c> discountQuoteCharge = new Map<String,zqu__QuoteCharge__c>();
        Map<String,zqu__QuoteCharge__c> nonDiscountQuoteCharge = new Map<String,zqu__QuoteCharge__c>();
        for(zqu__QuoteCharge__c qc: newQuoteCharges)
        {
           if(qc.Name == 'Discount')
           {
                discountQuoteCharge.put(qc.zqu__TimeProductAdded__c,qc);
           }
           else
           {
                nonDiscountQuoteCharge.put(qc.zqu__TimeProductAdded__c,qc);
           }
        }
        if(Trigger.IsInsert)
        {
            for(String uniqueValue : discountQuoteCharge.keySet())
            {
                if(nonDiscountQuoteCharge.containsKey(uniqueValue))
                {
                    zqu__QuoteCharge__c productQC = nonDiscountQuoteCharge.get(uniqueValue);
                    zqu__QuoteCharge__c discountQC = discountQuoteCharge.get(uniqueValue);
                    productQC.True_Discount__c = discountQC.zqu__EffectivePrice__c; // Set True Discount Custom Field on Products to match ZQU Effective Price (Discount) from associated discount record.
                    productQC.Discount_Period__c = discountQC.zqu__Upto_How_Many_Periods__c; // Set Discount Period Custom Field on Products to Match ZQU How Mnay Periods field from associated discount record.
                }
            }
        }
        
        if(Trigger.isAfter && Trigger.isUpdate && discountQuoteCharge.size()>0)
        {
            List<zqu__QuoteCharge__c> lstProductToUpdate = new List<zqu__QuoteCharge__c>();
            for(zqu__QuoteCharge__c prodQC : [select Id,zqu__TimeProductAdded__c,True_Discount__c,Discount_Period__c,name from zqu__QuoteCharge__c where name != 'Discount' and zqu__TimeProductAdded__c in :discountQuoteCharge.keySet()])
            {
                if(discountQuoteCharge.containsKey(prodQC.zqu__TimeProductAdded__c))
                {
                    prodQC.True_Discount__c = discountQuoteCharge.get(prodQC.zqu__TimeProductAdded__c).zqu__EffectivePrice__c;
                    prodQC.Discount_Period__c = discountQuoteCharge.get(prodQC.zqu__TimeProductAdded__c).zqu__Upto_How_Many_Periods__c;
                    lstProductToUpdate.add(prodQC);
                }
            }
            if(lstProductToUpdate.size()>0)
             update lstProductToUpdate;
            
        }
    }
}

Please let me know if I can help you more.

Thanks,
Vishal
Morgan MarcheseMorgan Marchese
Hi Vishal,

Can you tell me what changes you made? Did you make changes to the rest of the handler or just changes to the linkDiscountsToCharges class? I want to make sure I properly document and test everything if changes were made outside of the new class.

Thanks for all of your time 
Morgan MarcheseMorgan Marchese
Hi Vishal,

Please disregard my question above - I see the area that you highlighted in bold is the area that you changed... and good news is... it appears that fixed it! I am very grateful for your continued assistance getting me through this, you don't know how much it means to know that there are people like you willing to help to such a great degree.

I hope you have a fantastic day!
Vishal_GuptaVishal_Gupta
Hi Morgan,

I am pleased that I assist you and worked with you . Please feel free to let me know if I can help you in future. Just drop me an email.

Thanks,
Vishal