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
Jaymin Sutarwala 7Jaymin Sutarwala 7 

Map values getting overriden

Hi all,
A very strange issue is happening in the below apex code. I have return a batch job (Batch_Annual_Contract_Value_DER) to update Annual contract Value records with the latest Dated Exchange rates based on the Opportunity close date. The other class CurrencyUtil creates a yearExchngRateMap (Map<Integer, Map<String, Decimal>>) which holds the year as the key and another map with IsoCode as key and the Dated Exchange rate for that year as value. In the CurrencyUtil class when the getPrevYearCurrencyRate method is called from the Else at line 115 the values in the map yearExchngRateMap get overriden. I spent a lot of time on this but am not able to figure out why is this happening. Can anyone take a look at the code and see if they can figure out something.
public without sharing class CurrencyUtil {

    public static Map<String, Decimal> currencyExchangeRateMap = new Map<String, Decimal>();

    // Map that holds the Exchange Rates by Year
    Public static Map<Integer, Map<String, Decimal>> yearExchngRateMap = new Map<Integer, Map<String, Decimal>>();
    private static String CurrencyTypes = Label.Currency_Types;
    private static String[] currencies = CurrencyTypes.split(',');

    public static Decimal convertToOrgDefaultCurrency(Decimal amount, String isoCode) {
        Decimal convertedAmount = 0.0;
        if(amount != null && isoCode != null && !isoCode.equals('')) {
                convertedAmount = amount / currencyExchangeRateMap.get(isoCode);
        }
        return convertedAmount;
    }
    
    public static Decimal convertToOrgDefaultCurrency(Decimal amount, String isoCode, Integer fiscalYear) {
        Decimal convertedAmount = 0.0;
        if(amount != null && isoCode != null && !isoCode.equals('')) {
            convertedAmount = amount / yearExchngRateMap.get(fiscalYear).get(isoCode);
        }
        return convertedAmount;
    }

    public static void updateExchangeRatesMap() {
        currencyExchangeRateMap.clear();
        currencyExchangeRateMap.put('USD', 1.000000);
        List<DatedConversionRate> dtdExchngRates = [Select Id, ConversionRate, IsoCode, NextStartDate, StartDate 
                                                from DatedConversionRate
                                                where startdate = THIS_FISCAL_YEAR
                                                order by startdate desc];
        System.debug('dtdExchngRates : '+dtdExchngRates);
        for(DatedConversionRate dtdER : dtdExchngRates) {
            if(!currencyExchangeRateMap.containsKey(dtdER.IsoCode)) {
              currencyExchangeRateMap.put(dtdER.IsoCode, dtdER.ConversionRate);
            }
        }
        System.debug('currencyExchangeRateMap : '+currencyExchangeRateMap);
    }

    public static void updateConversionRatesMap() {
        System.debug('currencies : '+currencies);
        yearExchngRateMap.clear();
        String dteFormat = '-11-01';
        Integer lstFiveYr = System.today().Year() - 5;
        Date fiveYrAgo = Date.valueOf(String.valueOf(lstFiveYr) + dteFormat);
        System.debug('fiveYrAgo : '+fiveYrAgo);
        
        List<DatedConversionRate> dtdExchngRates = [SELECT Id, ConversionRate, IsoCode, NextStartDate, StartDate 
                                                      FROM DatedConversionRate
                                                     WHERE StartDate >=: fiveYrAgo
                                                    ORDER BY Startdate asc];
        System.debug('dtdExchngRates : '+dtdExchngRates);
        
        // Build the DatedConversionRateMap for the past five years - From DatedConversionRate Object
        if(!dtdExchngRates.isEmpty()) {
            Integer dcrYear = null;
            Map<String, Decimal> currRateMap = null;
            for(DatedConversionRate dcr : dtdExchngRates) {
                dcrYear = dcr.StartDate.Year();
                if(yearExchngRateMap != null && !yearExchngRateMap.containsKey(dcrYear)) {
                    yearExchngRateMap.put(dcrYear, new Map<String, Decimal> {'USD' => 1.000000});
                }
                if(yearExchngRateMap != null && yearExchngRateMap.containsKey(dcrYear)) {
                    currRateMap = yearExchngRateMap.get(dcrYear);
                    if(currRateMap != null && !currRateMap.containsKey(dcr.IsoCode)) {
                        currRateMap.put(dcr.IsoCode, null);
                        yearExchngRateMap.put(dcrYear, currRateMap);
                    }
                    if(currRateMap != null && currRateMap.containsKey(dcr.IsoCode)) {
                        currRateMap.put(dcr.IsoCode, dcr.ConversionRate);
                        yearExchngRateMap.put(dcrYear, currRateMap);
                    }
                }
            }
        }
        System.debug('yearExchngRateMap : '+yearExchngRateMap);
        
        /* Verify whether all the Currency Types are present for all the years, 
           If not add the missed out CurrencyRate from the Previous Fiscal Year
        */
        Decimal exchngRate = null;
        Map<String, Decimal> currencyRateMap = new Map<String, Decimal>();
        Date fiscalYrStartDate = Date.newInstance(Date.today().year(), 11, 1);
        Integer fiscalYear;
        if(yearExchngRateMap != null && !yearExchngRateMap.isEmpty()) {
        //    for(Integer fiscalYear : yearExchngRateMap.keyset()) {
            System.debug('Currencies: ' + currencies);
			if(Date.today() < fiscalYrStartDate)            
                fiscalYear = Date.today().year() - 1;
            else
                fiscalYear = Date.today().year();
            
            for(Integer iteration = 0; iteration<5; iteration++){
                System.debug('Inside iteration loop, iteration# ' + iteration);
                System.debug('Currency List size: ' + currencies.size());
                System.debug('fiscalYear: ' + fiscalYear);
                if(yearExchngRateMap.containsKey(fiscalYear)){
                	currencyRateMap = yearExchngRateMap.get(fiscalYear);   
                    System.debug('Currency Rate Map found for FY ' + fiscalYear);
                    System.debug('Currency Rate Map: (in IF) ' + currencyRateMap);
                    for(String curr : currencies) {
                        if(!currencyRateMap.containsKey(curr)) {
                    //      exchngRate = getPrevYearCurrencyRate(fiscalYear, curr, fiveYrAgo.year()-1);
                    		exchngRate = getPrevYearCurrencyRate(fiscalYear, curr);
                            System.debug('Currency (in IF): ' + curr);
                            System.debug('Exchange Rate (in IF): ' + exchngRate);
                            currencyRateMap.put(curr, exchngRate);
                        }
                    }
				 	yearExchngRateMap.put(fiscalYear, currencyRateMap);
                    System.debug('yearExchngRateMap (in IF): ' + yearExchngRateMap);
                }
                else{
					//currencyRateMap.clear();
                    System.debug('Currency Rate Map: (before) ' + currencyRateMap);
                    System.debug('yearExchngRateMap (before in ELSE): ' + yearExchngRateMap);
                    for(Integer key: yearExchngRateMap.keySet()){
            			System.debug('yearExchngRateMap(' + key + ')' + yearExchngRateMap.get(key));
        			}
                    for(String curr : currencies) {
                    //  exchngRate = getPrevYearCurrencyRate(fiscalYear, curr, fiveYrAgo.year()-1);
                        exchngRate = getPrevYearCurrencyRate(fiscalYear, curr);
                        System.debug('Currency: (in ELSE)' + curr);
                        System.debug('Exchange Rate: (in ELSE)' + exchngRate);
                        currencyRateMap.put(curr, exchngRate);
                    }
                    System.debug('Currency Rate Map: (after) ' + currencyRateMap );
                    System.debug('Fiscal Year: ' + fiscalYear);
                    yearExchngRateMap.put(fiscalYear, currencyRateMap);
                    System.debug('yearExchngRateMap (after in ELSE): ' + yearExchngRateMap);
                    for(Integer key: yearExchngRateMap.keySet()){
            			System.debug('yearExchngRateMap(' + key + ')' + yearExchngRateMap.get(key));
        			}
                }
                fiscalYear = fiscalYear - 1;
            }
        }
        System.debug('yearExchngRateMap : After Verification Logic : '+ yearExchngRateMap);
        //Display yearExchangRateMap
        for(Integer key: yearExchngRateMap.keySet()){
            System.debug('yearExchngRateMap(' + key + ')' + yearExchngRateMap.get(key));
        }
    }
                       
//  private static Decimal getPrevYearCurrencyRate(Integer fYear, String currencyIso, Integer fiveYrAgoYear) {
	private static Decimal getPrevYearCurrencyRate(Integer fYear, String currencyIso) {
		Decimal convRate;
        Integer prevFiscalYear = fYear - 1;
        //if(prevFiscalYear > fiveYrAgoYear){
        //
        	System.debug('yearExchngRateMap (in getPrevYearCurrencyRate): ' + yearExchngRateMap);
        	for(Integer key: yearExchngRateMap.keySet())
            	System.debug('yearExchngRateMap(' + key + ')' + yearExchngRateMap.get(key));
        //
            Map<String, Decimal> prevCurrRateMap = yearExchngRateMap.get(prevFiscalYear);
            convRate = null;
            System.debug('In getPrevYearCurrencyRate');
            if(prevCurrRateMap != null && prevCurrRateMap.containsKey(currencyIso)) {
                if(prevCurrRateMap.get(currencyIso) != null) {
                    convRate = prevCurrRateMap.get(currencyIso);
                } else {
                  //convRate = getPrevYearCurrencyRate(prevFiscalYear, currencyIso, fiveYrAgoYear);
                    convRate = getPrevYearCurrencyRate(prevFiscalYear, currencyIso);
                }
            }
            else{
                //convRate = getPrevYearCurrencyRate(prevFiscalYear, currencyIso, fiveYrAgoYear);
                convRate = getPrevYearCurrencyRate(prevFiscalYear, currencyIso);
            }
        /*}
        else{
            convRate = null;
        }*/
        return convRate;
    }
}
 
global class Batch_Annual_Contract_Value_DER implements Database.Batchable<sObject>, Database.Stateful {
    Map<Id,Annual_Contract_Value__c> MapquoteId = new Map<ID,Annual_Contract_Value__c>();
    Map<Id,String> MapIsoCode = new Map<ID,String>();
    Map<Id,Integer> MapCloseDate = new Map<ID,Integer>();
    final String[] oppStageToAvoid = new String[] {'Declined to Quote', 'Legacy'};  
    final String[] oppOpenStage = new String[] {'Fact Finding', 'Covering the Bases', 'Negotiating', 'Closing'};
    final String[] oppClosedStage = new String[] {'Closed/Lost', 'Closed/Won'};
        
    global List<Annual_Contract_Value__c> start(Database.BatchableContext BC) {     
        List<Annual_Contract_Value__c> acvList = [SELECT Id,Quote__r.Id,Dated_Exchange_Rate__c,Fiscal_Year__c,Quote__c,Expected_Revenue__c,Quote__r.CurrencyIsoCode,Opportunity_Stage__c,Opportunity_Close_Date__c, Batch_Error__c, Batch_Job_runtime__c, ACV_Currency__c
                                                    FROM Annual_Contract_Value__c
                                                   WHERE Opportunity_Stage__c !=: oppStageToAvoid
                                                     AND (Opportunity_Stage__c IN :oppOpenStage 
                                                         OR
                                                         (Opportunity_Stage__c IN :oppClosedStage
                                                          AND Opportunity_Last_Modified_Date__c = LAST_N_DAYS:31))
                                                  ORDER BY Id, Quote__c];        
        system.debug('acvList:'+acvList);
        system.debug('acvList size: ' + acvList.size());
        
        if(acvList.size() > 0){
            For(Annual_Contract_Value__c acvInstance:acvList){
                MapquoteId.put(acvInstance.Quote__c,acvInstance);
            }
        }
        
        List<Quote> qList = [select Id,CurrencyIsoCode,Opportunity.CloseDate from Quote where Id IN: MapquoteId.keyset()];        
        System.debug('qList size: ' + qList.size());
        if(qList.size() > 0){
            For(Quote qInstance:qList){
                MapIsoCode.put(qInstance.Id,qInstance.CurrencyIsoCode);
                Date fiscalYrStartDate = Date.newInstance(qInstance.Opportunity.CloseDate.year(), 11, 1);
                System.debug('Quote Id: ' + qInstance.Id);
                System.debug('fiscalYrStartDate: ' + fiscalYrStartDate);
                If(qInstance.Opportunity.CloseDate < fiscalYrStartDate)
                    MapCloseDate.put(qInstance.Id,qInstance.Opportunity.CloseDate.year() - 1);
                Else
                    MapCloseDate.put(qInstance.Id,qInstance.Opportunity.CloseDate.year());
            }
        }        
    //    system.debug('Map1Values:'+MapquoteId.values());
    //    system.debug('Map Values:'+MapIsoCode.values());
        return acvList;
    }
    
    global void execute(Database.BatchableContext BC, List<Annual_Contract_Value__c> scope) {
     //   CurrencyUtil.updateExchangeRatesMap();
        CurrencyUtil.updateConversionRatesMap();
        List<Annual_Contract_Value__c> updateACVList = new List<Annual_Contract_Value__c>();
        Decimal CUDER = 0.0;
        Integer currentFY;
        Date fiscalYrStartDate = Date.newInstance(Date.today().year(), 11, 1);
        System.debug('MapCloseDate size: ' + MapCloseDate.size());
        
        if(Date.today() > fiscalYrStartDate)
            currentFY=Date.today().year();
        else
            currentFY=Date.today().year() - 1;
        
        For(Annual_Contract_Value__c acvqList:scope){
            System.debug('Close date year: ' + MapCloseDate.get(acvqList.Quote__c));
            System.debug('Quote currency: ' + MapIsoCode.get(acvqList.Quote__c));
            System.debug('ACV record id: ' + acvqList.Id);
            
            if(CurrencyUtil.yearExchngRateMap.containsKey(MapCloseDate.get(acvqList.Quote__c)) == TRUE &&
               CurrencyUtil.yearExchngRateMap.get(MapCloseDate.get(acvqList.Quote__c)).containsKey(MapIsoCode.get(acvqList.Quote__c)) == TRUE)
            	CUDER = CurrencyUtil.yearExchngRateMap.get(MapCloseDate.get(acvqList.Quote__c))
                                                  .get(MapIsoCode.get(acvqList.Quote__c));
            else
                CUDER = NULL;
            
            if(CUDER == NULL && MapCloseDate.get(acvqList.Quote__c) >= currentFY)
                CUDER = CurrencyUtil.yearExchngRateMap.get(currentFY)
                                                  .get(MapIsoCode.get(acvqList.Quote__c));
            
            system.debug('CUDER from CurrencyUtil map: ' + CUDER);
            
            if(CUDER != NULL){
            	if(acvqList.Dated_Exchange_Rate__c != CUDER || acvqList.Dated_Exchange_Rate__c == NULL){
                	system.debug(acvqList);
                    acvqList.Dated_Exchange_Rate__c = CUDER; 
                    acvqList.Batch_Error__c = false;
                    acvqList.Batch_Job_runtime__c = DateTime.now();
                    updateACVList.add(acvqList);
                }
            }
            Else{
                if(acvqList.ACV_Currency__c == 'USD'){
                    system.debug(acvqList);
                    acvqList.Dated_Exchange_Rate__c = 1.0;
                    acvqList.Batch_Error__c = false;
                    acvqList.Batch_Job_runtime__c = DateTime.now();
                    updateACVList.add(acvqList);
                }
                else{                    
                    acvqList.Batch_Error__c = true;
                    acvqList.Batch_Job_runtime__c = DateTime.now();
                    updateACVList.add(acvqList);
                }
            }
        }
        
        if(updateACVList.size() > 0){
            Try{
                system.debug('updateACVList'+updateACVList);
                Update updateACVList;
            }Catch(DMLException DMLEx){
                System.debug('Exception While Updating ACV records.'+DMLEx);
            }
        }        
    }
    
    global void finish(Database.BatchableContext BC) {     
        
    }
}

Debug log

Thanks,
Jay