3

Scenario: We have a quoting system with a child object called zqu__QuoteCharge__c that acts as the individual line items on the quote. zqu__QuoteCharge__c is also the child of zqu__ProductRatePlanCharge__c, which holds a total available quantity field that comes from another connected app.

I recently created a class that just acts as a sophisticated, dynamic validation rule that makes sure the amount you are trying to sell doesn't exceed the total available quantity. If it does, we .addError in the loop so that the VR inserts the name of the product, available quantity, and quantity that you are trying to sell.


Problem: Users in our org have the potential to add the same item as 2+ lines (2+ zqu__QuoteCharge__c records) if they are discounting one of the products but not the other, etc. To deal with this, I've attempted to create an <Id,Decimal> map that, while in the for loop through new QuoteCharge records, puts <Id,0> if the key isn't already found, and if the key is found I instead try to increment the number by getting the current value for that key and then adding (+=) the quantity of the record in the loop. The line of code that should be incrementing the value is where the error occurs.


I've added my code below, and added !!!ERROR OCCURS HERE!!! to the comment on the line that throws the error in my compiler.

Code:

public void customValidation(List<zqu__QuoteCharge__c> newList){
    if (newList != null && newList.size() > 0){

        Map<Id,zqu__ProductRatePlanCharge__c> rpcMap = new Map<Id,zqu__ProductRatePlanCharge__c>(); // Create a map for ProductRatePlanCharge (parent object) where the total available quantity is held 
        Map<Id, Decimal> parentToQuantity = new Map<Id, Decimal>(); // Create a map to count the total quantity related to the same parent

        for(zqu__QuoteCharge__c quoteCharge : newList){
            if(quoteCharge.Name != 'Discount'){ // skip discount records as they do not apply for available quantity checks
                if(!parentToQuantity.containsKey(quoteCharge.zqu__ProductRatePlanCharge__c)){ // if key doesn't already exist
                    parentToQuantity.put(quoteCharge.zqu__ProductRatePlanCharge__c,0); // put key with default count of 0
                }
                else{ // if key already exists
                    parentToQuantity.put(quoteCharge.zqu__ProductRatePlanCharge__c,parentToQuantity.get(quoteCharge.zqu__ProductRatePlanCharge__c) += quoteCharge.zqu__Quantity__c); // !!!ERROR OCCURS HERE!!! update key/val pair, current val += quantity of charge
                }
                rpcMap.put(quoteCharge.zqu__ProductRatePlanCharge__c,null); // put the ProductRatePlanCharge in the map to later check available quantity
            }
        }

        // Debug
        System.debug('parentToQuantity KeySet::: ' +parentToQuantity.keySet());
        System.debug('parentToQuantity Total Values::: ' +parentToQuantity.values());

        rpcMap.remove(null); // remove null key      
        rpcMap.putAll([SELECT Id, Name, Ascent_Quantity__c FROM zqu__ProductRatePlanCharge__c WHERE Id IN :rpcMap.keySet()]); // build real map of ProductRatePlanCharge (parent object) from keySet

        for(zqu__QuoteCharge__c quoteCharge : newList){
            if(quoteCharge.Name != 'Discount'){ // Skip discount records as they do not apply for available quantity checks
                if(rpcMap.containsKey(quoteCharge.zqu__ProductRatePlanCharge__c)){ // if this quote charge is the child of a PRPC in our rpcMap
                    Decimal ascentQuantity = rpcMap.get(quoteCharge.zqu__ProductRatePlanCharge__c).Ascent_Quantity__c; // create friendlier Decimal val for available quantity from ascent
                    Decimal productQuantity = parentToQuantity.get(quoteCharge.zqu__ProductRatePlanCharge__c); // create friendlier Decimal val for total quantity being inserted

                    // Debug
                    System.debug('Ascent Quantity:: ' +ascentQuantity);
                    System.debug('Product Quantity:: ' +productQuantity);

                    if(ascentQuantity == 0 || ascentQuantity < productQuantity){
                            /*Add to the productMap to stop a recursive update attempt from the linkDiscountsToCharges method
                            // the productMap is a private class scope map where we put the quoteCharges when they fail to meet the VR criteria.
                            // We do this because we need to check later to see if they are in the map before trying to update the associated discount record.
                            // Since the discount is its own separate record which tries to update itself whenever you update the related product, even if it wasn't changed (thanks Zuora -_-)
                            // this should stop us from attempting to save any new discounts to the records if the product itself wasn't committed to DB due to failing VR criteria
                            // but should still allow us to adjust the discount % on updates if they don't fail the VR */
                            productMap.put(quoteCharge.Id,quoteCharge);
                            // VALIDATION ERROR USING quoteCharge.addError();
                            quoteCharge.addError('The Product "' +quoteCharge.Name + '" only has ' +ascentQuantity + ' in stock but you are trying to sell ' +productQuantity);
                            //Old
                            //quoteCharge.addError('The Product "' +quoteCharge.Name + '" only has ' +ascentQuantity + ' in stock but you are trying to sell ' +quoteCharge.zqu__Quantity__c.intValue());
                    }
                }
            }
        }
    }
}
3

This is reproducible using execute anonymous. This does not compile with the error:

Decimal x = (1 += 2);

and this does:

Decimal x = (1 + 2);

While you perhaps can argue that the += should work, the + is the more appropriate operator in this case.

Or to use the map idiom from the question this does not compile:

m.put(key, m.get(key) += increment);

and this does:

m.put(key, m.get(key) + increment);
1
  • 1
    Hahahaha... wow. Literally one keystroke. I've been ONE = sign away from going home for the last hour! Thank you! Apr 28 '16 at 20:40

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.