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
Harjeet Singh 13Harjeet Singh 13 

Coordinates are not updating on bulk insert/update

Dear All,

I am immense need of help from all of you. After giving a much thought and so much brainstorming happened finally I turned up here for advise.

Requirement:
I need to fetch coordinates value of account based on Map address provided. Map addresses are new fields created on accounts object(map street,map city,map postal code,map countrymap state)

Solution approach
I create few fields on accounts like MapAddressCity,MapAddressState,MapAddressStreet,MapAddressPostalCode and MapAddresscountry on account. When an user enters values in Map fields and clicks on save button I am calling Google API. Google API will returns one coordinate value based on address filled in Map fields. I have created one field called "Location"(Data Type-Geolocation) which will stores coordinates and also I created 2 formula fields which stores the longitude and latitude values of coordinates in "LonField" and "LatField" respectively

If an user enters below in account:
MapAddressCity: San Francisco  
MapAddressCountry: United States  
MapAddressPostalCode: 94105  
MapPostalState: CA  
MapAddressStreet: One Market Street
and clicks on Save-Google API call will be made and below information wiull be stored on account:
Location-37°47'38''N 122°23'41''W  
LongValue-122.3948  
LatValue37.7939

My Question:
In our org there is already one trigger written on account and there is already one accounthandler class and we always follow best practices so I didnt write a separate trigger and class to achieve above mentioned requirement. I am reusing same accounttriggerhandler class and apex trigger which is written on account.
When I am trying to insert account records through data loader some accounts have updated coordinates after insertion whereas some doesn't have coordinates inserted.
I tried inserting around 17K records upon which 5K records inserted succesfully and also their corresponding coordinates are updated. Rest 12K records also inserted succesfully but their coordinates are not updated.


Kindly help me. Below is trigger which is already existing on account:
//Single Master Trigger on Account using Handlers for each individual actions
trigger AccountTrigger on Account (before delete, before insert, before update, after insert, after update,after delete) {

    checkRecursive.isRunOnce = true; // ToDo : Need to change the recursive handling logic
    AccountTriggerHandler accHandler = new AccountTriggerHandler(trigger.new,trigger.old,trigger.newMap,trigger.oldMap,trigger.isUpdate);
    
 
    if(trigger.isBefore && trigger.isInsert){
        accHandler.HandleBeforeInsert();
        
    }
    if(trigger.isBefore && trigger.isUpdate){
        accHandler.HandleBeforeUpdate();
       
    }
    if(trigger.isAfter && trigger.isInsert) {  
        accHandler.HandleAfterInsert();
    
    }
  
    if(trigger.isAfter && trigger.isUpdate){
        accHandler.HandleAfterUpdate();
    
    }
 
    if(trigger.isBefore && trigger.isDelete)
        accHandler.HandleBeforeDelete();

    if(trigger.isAfter && trigger.isDelete)
        accHandler.HandleAfterDelete();       
}

My class code is as belows:
 
//Handler Class to handle Account Trigger
public class AccountTriggerHandler {
    
    public static Boolean runAccountTriggerHandler = true;
    private static Boolean geocodingCalled = false;

    //recursive variables
    public static boolean run = true;
    public static boolean runOnce(){
        if(run){
            run=false;
            return true;
        }else{
            return run;
        }
    }
	
	//trigger variables
    List<Account> newAccs;
    List<Account> oldAccs;
    Map<Id,Account> newAccMap;
    Map<Id,Account> oldAccMap;
    Id accountId;
    boolean isUpdate;
	
	
	//constructor
    public AccountTriggerHandler(List<Account> newAccs, List<Account> oldAccs, 
                                 Map<Id,Account> newAccMap, Map<Id,Account> oldAccMap, boolean isUpdate){
        this.newAccs = newAccs;
        this.oldAccs = oldAccs;
        this.newAccMap = newAccMap;
        this.oldAccMap = oldAccMap;
        this.isUpdate = isUpdate;
        this.accountId= accountId;                          
        this.consentService = new ConsentManagementService(Account.sObjectType);
    }
	
	 public void HandleAfterInsert(){ 
        system.debug(LoggingLevel.DEBUG, '***Inside after insert- ' );
        
            for(Account account : newAccs) {
  
                //check if Map Address has been updated
                Boolean addressChangedFlag = false;

                    if(Trigger.isInsert) {
                        Account newAccount = (Account)Trigger.newMap.get(account.Id);

                            if((account.MapAddressStreet__c != newAccount.MapAddressStreet__c) ||
                                (account.MapAddressCity__c != newAccount.MapAddressCity__c) ||
                                (account.MapPostalState__c!= newAccount.MapPostalState__c) ||
                                (account.MapAddressPostalCode__c!= newAccount.MapAddressPostalCode__c) || 
                                (account.MapAddressCountry__c!= newAccount.MapAddressCountry__c)) {
         
                                    addressChangedFlag = true;
         
                                    System.debug(LoggingLevel.DEBUG, '***Address changed for - ' +newAccount.Name);
                                }
                    }

              if(((account.Location__Latitude__s == null) || (addressChangedFlag == true)) && (String.isNotBlank(account.MapAddressCountry__c))){
                    System.debug(LoggingLevel.DEBUG,'***Geocoding Account - ' + account.Name);
                    AccountTriggerHandler.DoAddressGeocode(account.id);
                }   
            } 
        }  

	public void HandleAfterUpdate(){
          system.debug(LoggingLevel.DEBUG, '***Inside after update- ' );
        
            for(Account account : newAccs) {
  
                //check if Map Address has been updated
                Boolean addressChangedFlag = false;

                    if(Trigger.isUpdate) {
                        Account oldAccount = (Account)Trigger.oldMap.get(account.Id);

                            if((account.MapAddressStreet__c != oldAccount.MapAddressStreet__c) ||
                                (account.MapAddressCity__c != oldAccount.MapAddressCity__c) ||
                                (account.MapPostalState__c!= oldAccount.MapPostalState__c) ||
                                (account.MapAddressPostalCode__c!= oldAccount.MapAddressPostalCode__c) || 
                                (account.MapAddressCountry__c!= oldAccount.MapAddressCountry__c)) {
         
                                    addressChangedFlag = true;
         
                                    System.debug(LoggingLevel.DEBUG, '***Address changed for - ' +oldAccount.Name);
                                }
                    }
                     if(((account.Location__Latitude__s == null) || (addressChangedFlag == true)) && (String.isNotBlank(account.MapAddressCountry__c))) {
      
                    System.debug(LoggingLevel.DEBUG,'***Geocoding Account - ' + account.Name);
                    AccountTriggerHandler.DoAddressGeocode(account.id);
                }   
            }  
    }	
	public void HandleBeforeDelete(){
        
    }
 
    public void HandleAfterDelete(){
        
    }

    // wrapper method to prevent calling futuremethods from an existing future context
    public static void DoAddressGeocode(id accountId) {
       
        if(geocodingCalled || System.isFuture()) {
            System.debug(LoggingLevel.WARN,'***Address Geocoding Future Method Already Called - Aborting...');
                    return;
        }
                
        // if not being called from future context, geocode the address
                        geocodingCalled= true;
                        getLocation(accountId);
    }
	
    @future (callout=true)  // future method needed to run callouts from Triggers
        static public void getLocation( id accountId){
         
        String  geocodingKey ='AIzaSyD6DLnewg4y0Casi0-iFFjoenLJmmayt8c';
        Account a = new Account();
        if(!Test.isRunningTest())
        
        // gather account info
   
        a= [SELECT id, MapAddressCity__c,MapAddressCountry__c,MapAddressPostalCode__c,MapAddressStreet__c,MapPostalState__c FROM Account  WHERE id =: accountId];
      
        // create an address string
        String address = '';
        if (a.MapAddressStreet__c!= null)
            address += a.MapAddressStreet__c+', ';
        if (a.MapAddressCity__c != null)
            address += a.MapAddressCity__c +', ';
        if (a.MapPostalState__c!= null)
            address += a.MapPostalState__c+' ';
        if (a.MapAddressPostalCode__c!= null)
            address += a.MapAddressPostalCode__c+', ';
        if (a.MapAddressCountry__c!= null)
            address += a.MapAddressCountry__c;

        address = EncodingUtil.urlEncode(address, 'UTF-8');

        // build callout
            Http h = new Http();
            HttpRequest req = new HttpRequest();
            req.setEndpoint('https://maps.googleapis.com/maps/api/geocode/json?address='+address + '&key='+ geocodingKey+ '&sensor=false');
            req.setMethod('GET');
            req.setTimeout(60000);

        try{
            // callout
            HttpResponse res = h.send(req);

            // parse coordinates from response
            
            JSONParser parser = JSON.createParser(res.getBody());
            system.debug('Harjeet:'+ res.getBody());
            double lat = null;
            double lon = null;
            while (parser.nextToken() != null) {
                if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) &&
                    (parser.getText() == 'location')){
                       parser.nextToken(); // object start
                       while (parser.nextToken() != JSONToken.END_OBJECT){
                           String txt = parser.getText();
                           parser.nextToken();
                           if (txt == 'lat')
                               lat = parser.getDoubleValue();
                           else if (txt == 'lng')
                               lon = parser.getDoubleValue();
                       }

                }
            }

            // update coordinates if we get back
            if (lat != null){
                a.Location__Latitude__s = lat;
                a.Location__Longitude__s = lon;
                update a;
            }

        } catch (Exception e) {
        }
    }
	
}

I have removed all the extra codes and methods from class and only kept my method in class to have a better visibility for code to all of you.
I am calling "DoAddressGeocode​" method on HandleAfterInsert and HandleAfterUpdate.

Kindly help me why few thousand records inserted/updated succesfully using data loader with long/lat and coordinate values and other few thousand records are only inserting/updating but not lat/ong and coordinates are updating.

Any help will be greatly appreciated!

Thanks in advance

Thanks & Regards,
Harjeet