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
RandyBarton24RandyBarton24 

Trigger.oldmap field value same as Trigger.newmap field value when field updated.

This one is making me a little crazy... I'm sure it's something small I am overlooking, but I can't seem to figure it out.

In my developer sandbox I have the following test class: 
@isTest static void numberOfProvidersUpdatedToLessThan3FromMoreThan3() {
		
		Account a = TestUtilities.insertBasicAccount();
		Opportunity o = TestUtilities.createBasicOpportunity(a.Id);
		o.Number_of_Providers__c = 4;
		
		insert o;
		Test.startTest();
		
		o.Number_of_Providers__c = 1;
		update o;

		Test.stopTest();

		Opportunity o2 = TestUtilities.getOppData(o.Id);

		Map<String, Decimal> oppLineItemQty = new Map<String, Decimal>();
		Map<String, Decimal> oppLineItemPrice = new Map<String, Decimal>();

		if(o2.HasOpportunityLineItem) {
			
			for(OpportunityLineItem oppLi : o2.OpportunityLineItems) {
				oppLineItemQty.put(oppLi.PricebookEntry.Name, oppLi.Quantity);
				oppLineItemPrice.put(oppLi.PricebookEntry.Name, oppLi.TotalPrice);
			}
		}
		System.assertNotEquals(o2.Pricebook2Id, null, 'The Pricebook was not set');
		System.assert(o2.HasOpportunityLineItem, 'The Opportunity does not have any products');
		System.assertEquals(2, o2.OpportunityLineItems.size(), 'Two products were expected on this Opportunity');
		System.assert(oppLineItemPrice.containsKey('Monthly Service Fee'), 'The MSF Product was not added');
		System.assert(oppLineItemPrice.containsKey('Setup Fee'), 'The SF Product was not added');
		System.assert(!oppLineItemPrice.containsKey('Additional Providers'), 'The AP Product should have been removed');
		System.assertEquals(1, oppLineItemQty.get('Monthly Service Fee'), 'The MSF quantity is incorrect');
		System.assertEquals(1, oppLineItemQty.get('Setup Fee'), 'The SF quantity is incorrect');
		System.assertEquals(379, oppLineItemPrice.get('Monthly Service Fee'), 'The MSF price is incorrect');
		System.assertEquals(399, oppLineItemPrice.get('Setup Fee'), 'The SF price is incorrect');
	}

The method I am testing is as follows:
 
public static void updateAPProductForNumberOfProvidersChange(Opportunity[] updatedOpps, Map<ID, Opportunity> oldOpportunityMap, Map<ID, Opportunity> newOpportunityMap) {

    	Boolean hasAdditionalProviderLineItem = false;
    	Map<Id, OpportunityLineItem> mapInsertOppLis = new Map<Id, OpportunityLineItem>();
    	Map<Id, OpportunityLineItem> mapUpdateOppLis = new Map<Id, OpportunityLineItem>();
    	Map<Id, OpportunityLineItem> mapDeleteOppLis = new Map<Id, OpportunityLineItem>();

    	if(!FlowControl.InClass1) {

    		FlowControl.InClass1 = true;
	    	
	    	for(Opportunity o : updatedOpps) {

	    		System.debug(o.Number_of_Providers__c);
	    		System.debug(oldOpportunityMap.get(o.Id).Number_of_Providers__c);
	    		System.debug(newOppDataMap.get(o.Id).Number_of_Providers__c);

	    		if(o.RecordTypeId != DEFAULT_RENEWAL_RECORD_TYPE.getRecordTypeId()){

		    		if(o.Number_of_Providers__c != oldOpportunityMap.get(o.Id).Number_of_Providers__c){

		    			if(o.HasOpportunityLineItem) {

			    			for(OpportunityLineItem oppLi : newOppDataMap.get(o.Id).OpportunityLineItems) {

			    				if(oppLi.PricebookEntry.Product2.ProductCode == APProduct) {
			    					oppLi.Quantity = o.Number_of_Providers__c > 3 ? o.Number_of_Providers__c - 3 : 0;
			    					oppLi.UnitPrice = oppLi.PricebookEntry.UnitPrice;
			    					hasAdditionalProviderLineItem = true;

			    					if(oppLi.Quantity == 0) {
			    						mapDeleteOppLis.put(oppLi.Id, oppLi);
			    						System.debug(mapDeleteOppLis);
			    					} else {
			    						mapUpdateOppLis.put(oppLi.Id, oppLi);
			    						System.debug(mapUpdateOppLis);
			    					} 
			    				}
			    			}

			    			if(!hasAdditionalProviderLineItem && o.Number_of_Providers__c > 3) {

			    				for(PriceBookEntry pbEntry : STANDARD_PRICEBOOK) {

			    					if(pbEntry.Product2.ProductCode == APProduct) {
			    						OpportunityLineItem newOppLi = OpportunityUtilities.addOpportunityLineItem(o, pbEntry, o.Number_of_Providers__c -3);
			    						mapInsertOppLis.put(pbEntry.Id, newOppLi);
			    					}
			    				}
			    			}

			    		} else if(o.Number_of_Providers__c > 3 && o.Pricebook2Id != null) {
			    			
			    			for(PriceBookEntry pbEntry : STANDARD_PRICEBOOK) {

			    				if(pbEntry.Product2.ProductCode == APProduct) {
			    					OpportunityLineItem newOppLi = OpportunityUtilities.addOpportunityLineItem(o, pbEntry, o.Number_of_Providers__c -3);
			    					mapInsertOppLis.put(pbEntry.Id, newOppLi);
			    				}
			    			}
			    		}
		    		}
		    	}
	    	}
	    	SRUtilities.runDml(mapInsertOppLis, mapUpdateOppLis, mapDeleteOppLis, 'OpportunityUtilities.updateAPProductForNumberOfProvidersChange');
        	if(!mapUpdateOppLis.isEmpty() || !mapInsertOppLis.isEmpty() || !mapDeleteOppLis.isEmpty()) OpportunityTriggerHandler.oppDataMap = OpportunityUtilities.getOppData(newOppDataMap);
        	FlowControl.InClass1 = false;
        }
    }

The 3 Debug statements return the following:

System.debug(o.Number_of_Providers__c); = 4
System.debug(oldOpportunityMap.get(o.Id).Number_of_Providers__c); = 4
System.debug(newOppDataMap.get(o.Id).Number_of_Providers__c); = 4

When I am expecting:

System.debug(o.Number_of_Providers__c); = 1
System.debug(oldOpportunityMap.get(o.Id).Number_of_Providers__c); = 4
System.debug(newOppDataMap.get(o.Id).Number_of_Providers__c); = 1

As a sanity check, I put the same code in a fresh dev org, run the test, and I get the results I am expecting.  Any ideas??  Thank you in advance for your help.
Hargobind_SinghHargobind_Singh
Can you post your trigger as well, are you using afterupdate or beforeupdate trigger ?
 
RandyBarton24RandyBarton24
Not sure I can explain exactly why, but it is working now after changing my recursion variables.  I think it is because there was another Opportunity Trigger that was causing the recursion flag to change before it got to the update I expected.  If you can explain it better, please feel free to share.

Old TriggerHandler code(Didn't work):
public void OnAfterUpdate(Opportunity[] oldOpps, Opportunity[] updatedOpps, Map<ID, Opportunity> oldOpportunityMap, Map<ID, Opportunity> newOpportunityMap){
        
        if(!FlowControl.opportunityAfterUpdateRecursion) {
            OpportunityTriggerHandler.oppDataMap = OpportunityUtilities.getOppData(newOpportunityMap);
            OpportunityUtilities.updateAPProductForNumberOfProvidersChange(updatedOpps, oldOpportunityMap, oppDataMap);
            OpportunityUtilities.updatePricingForCampaignChange(updatedOpps, oldOpportunityMap, oppDataMap);
            processHandler.updateOppLineItemsWithDefaultRenewalRule(newOpportunityMap, oldOpportunityMap);
            FlowControl.opportunityAfterUpdateRecursion = true;
        }           
    }

New TriggerHandler code(Works):
 
public void OnAfterUpdate(Opportunity[] oldOpps, Opportunity[] updatedOpps, Map<ID, Opportunity> oldOpportunityMap, Map<ID, Opportunity> newOpportunityMap){
        
        if(FlowControl.opportunityAfterUpdateRecursionCount < 4) {
            OpportunityTriggerHandler.oppDataMap = OpportunityUtilities.getOppData(newOpportunityMap);
            OpportunityUtilities.updateAPProductForNumberOfProvidersChange(updatedOpps, oldOpportunityMap, oppDataMap);
            OpportunityUtilities.updatePricingForCampaignChange(updatedOpps, oldOpportunityMap, oppDataMap);
            processHandler.updateOppLineItemsWithDefaultRenewalRule(newOpportunityMap, oldOpportunityMap);
            FlowControl.opportunityAfterUpdateRecursionCount = FlowControl.opportunityAfterUpdateRecursionCount + 1;
        }           
    }

Trigger code abbreviated(Same in both instances):
 
trigger OpportunityUnified on Opportunity (after delete, after insert, after undelete,
after update, before delete, before insert, before update) {

OpportunityTriggerHandler handler = new OpportunityTriggerHandler(Trigger.isExecuting, Trigger.size);

if(Trigger.isUpdate && Trigger.isAfter){
        handler.OnAfterUpdate(Trigger.old, Trigger.new, Trigger.oldMap, Trigger.newMap);
}