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
Angie YzaguirreAngie Yzaguirre 

latitude and longitude

Hello - I have researched and researched and researched some more on how to do the following:  Pull the Google geolocation latitude and longitude coordinates into a field that I can report on.

I used the code here (http://blog.elieperez.net/geocode-your-record-salesforce/) and I was able to come up with the Visualforce page and find the coordinates that will populate if the user manually pushes a button in the account:
User-added image

All I want to do is pull the coordinates into a field that I can report on.  Is this possible and can someone please help out with the code?  I am new to the code.

Thank you!
 
Best Answer chosen by Angie Yzaguirre
logontokartiklogontokartik
If you just want to have the fields on your record and not worried about showing maps etc, maybe below code can help you. This is a batch job that can be executed to get the latitude and longitude from google and save it on Account.
 
global class BatchLatLongGenerator implements Database.Batchable<sObject>, Database.AllowsCallouts {
 
  String query;
 
 
  global BatchLatLongGenerator() {
    
    query = 'Select Id, Name, BillingLatitude,BillingLongitude,BillingStreet,BillingCity,BillingState, BillingCountry,BillingPostalCode from Account';
  }
 
  global Database.QueryLocator start(Database.BatchableContext BC) {
    return Database.getQueryLocator(query);
  }
 
  global void execute(Database.BatchableContext BC, List<sObject> scope) {
    
    for(Account acc : (List<Account>)scope){
      
      string address='';
      
      if(acc.BillingStreet!=null){
        address += acc.BillingStreet+',';
      }
      if(acc.BillingCity !=null){
        address += acc.BillingCity+',';
      }
      if(acc.BillingState!=null){
        address +=acc.BillingState+',';
      }
      if(acc.BillingCountry!=null){
        address += acc.BillingCountry+',';
      }
      if(acc.BillingPostalCode!=null){
        address += acc.BillingPostalCode+',';
      }
      /* if address is not blank then get the latitude and longitude through google api */
      if(address !=''){
        HttpRequest req = new HttpRequest();
        /* Encode address */
        address = EncodingUtil.urlEncode(address,'UTF-8');
        req.setEndPoint('https://maps.googleapis.com/maps/api/geocode/xml?address='+address+'&sensor=true');
        req.setMethod('GET');
        Http http = new Http();
        HttpResponse res;
        if(!Test.isRunningTest()){
          res = http.send(req);
        }else{
          /* create sample data for test method */
          String resString = '<GeocodeResponse><status>OK</status><result><geometry><location><lat>37.4217550</lat> <lng>-122.0846330</lng></location>';
          resString +='</geometry> </result> </GeocodeResponse>';
          res = new HttpResponse();
          res.setBody(resString);
          res.setStatusCode(200);
          
        }
        
        Dom.Document doc = res.getBodyDocument();   
        /* Get the root of xml response */
        Dom.XMLNode geocodeResponse = doc.getRootElement();
        if(geocodeResponse!=null){
          /* Get the result tag of xml response */
          Dom.XMLNode result = geocodeResponse.getChildElement('result',null);
          if(result!=null){
            /* Get the geometry tag  of xml response */
            Dom.XMLNode geometry = result.getChildElement('geometry',null);
            if(geometry!=null){
              /* Get the location tag  of xml response */
              Dom.XMLNode location = geometry.getChildElement('location',null);
              if(location!=null){
                /* Get the lat and lng tag  of xml response */
                String lat = location.getChildElement('lat', null).getText();
                String lng = location.getChildElement('lng', null).getText();
                try{
                  acc.BillingLatitude =Decimal.valueof(lat);
                  acc.BillingLongitude =Decimal.valueof(lng);
                  
                }catch(Exception ex){
                  system.debug('Exception '+ex.getMessage());
                }
              }
            }
          }
        }
      }
      
    }
    
    update scope;
    
  }
 
  global void finish(Database.BatchableContext BC) {
    //create a mail object to send a single email.
    Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
    User u =[select email,name from user where id=: userinfo.getUserId() limit 1];
    //set the email properties
    mail.setToAddresses(new string[] {u.email});
    mail.setSubject('Case Latitude Longitude batch completed');
    String body='';
    body +='Hi '+u.name+',';
    body+='<br/><br/>Account Latitude Longitude Calulation Batch is complete';
    body+='<br/><br/>Thank,<br/>Admin';
    mail.setHtmlBody(body);
    mail.setPlainTextBody('Account Latitude Longitude Calulation Batch is complete');
    //send the email
    Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail } );
  }
 
}

You can save the above class and then execute the batch via execute anonymous by running the below

BatchLatLongGenerator bJob = new BatchLatLongGenerator();
Database.executeBatch(bJob,10);



 

All Answers

logontokartiklogontokartik
If you just want to have the fields on your record and not worried about showing maps etc, maybe below code can help you. This is a batch job that can be executed to get the latitude and longitude from google and save it on Account.
 
global class BatchLatLongGenerator implements Database.Batchable<sObject>, Database.AllowsCallouts {
 
  String query;
 
 
  global BatchLatLongGenerator() {
    
    query = 'Select Id, Name, BillingLatitude,BillingLongitude,BillingStreet,BillingCity,BillingState, BillingCountry,BillingPostalCode from Account';
  }
 
  global Database.QueryLocator start(Database.BatchableContext BC) {
    return Database.getQueryLocator(query);
  }
 
  global void execute(Database.BatchableContext BC, List<sObject> scope) {
    
    for(Account acc : (List<Account>)scope){
      
      string address='';
      
      if(acc.BillingStreet!=null){
        address += acc.BillingStreet+',';
      }
      if(acc.BillingCity !=null){
        address += acc.BillingCity+',';
      }
      if(acc.BillingState!=null){
        address +=acc.BillingState+',';
      }
      if(acc.BillingCountry!=null){
        address += acc.BillingCountry+',';
      }
      if(acc.BillingPostalCode!=null){
        address += acc.BillingPostalCode+',';
      }
      /* if address is not blank then get the latitude and longitude through google api */
      if(address !=''){
        HttpRequest req = new HttpRequest();
        /* Encode address */
        address = EncodingUtil.urlEncode(address,'UTF-8');
        req.setEndPoint('https://maps.googleapis.com/maps/api/geocode/xml?address='+address+'&sensor=true');
        req.setMethod('GET');
        Http http = new Http();
        HttpResponse res;
        if(!Test.isRunningTest()){
          res = http.send(req);
        }else{
          /* create sample data for test method */
          String resString = '<GeocodeResponse><status>OK</status><result><geometry><location><lat>37.4217550</lat> <lng>-122.0846330</lng></location>';
          resString +='</geometry> </result> </GeocodeResponse>';
          res = new HttpResponse();
          res.setBody(resString);
          res.setStatusCode(200);
          
        }
        
        Dom.Document doc = res.getBodyDocument();   
        /* Get the root of xml response */
        Dom.XMLNode geocodeResponse = doc.getRootElement();
        if(geocodeResponse!=null){
          /* Get the result tag of xml response */
          Dom.XMLNode result = geocodeResponse.getChildElement('result',null);
          if(result!=null){
            /* Get the geometry tag  of xml response */
            Dom.XMLNode geometry = result.getChildElement('geometry',null);
            if(geometry!=null){
              /* Get the location tag  of xml response */
              Dom.XMLNode location = geometry.getChildElement('location',null);
              if(location!=null){
                /* Get the lat and lng tag  of xml response */
                String lat = location.getChildElement('lat', null).getText();
                String lng = location.getChildElement('lng', null).getText();
                try{
                  acc.BillingLatitude =Decimal.valueof(lat);
                  acc.BillingLongitude =Decimal.valueof(lng);
                  
                }catch(Exception ex){
                  system.debug('Exception '+ex.getMessage());
                }
              }
            }
          }
        }
      }
      
    }
    
    update scope;
    
  }
 
  global void finish(Database.BatchableContext BC) {
    //create a mail object to send a single email.
    Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
    User u =[select email,name from user where id=: userinfo.getUserId() limit 1];
    //set the email properties
    mail.setToAddresses(new string[] {u.email});
    mail.setSubject('Case Latitude Longitude batch completed');
    String body='';
    body +='Hi '+u.name+',';
    body+='<br/><br/>Account Latitude Longitude Calulation Batch is complete';
    body+='<br/><br/>Thank,<br/>Admin';
    mail.setHtmlBody(body);
    mail.setPlainTextBody('Account Latitude Longitude Calulation Batch is complete');
    //send the email
    Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail } );
  }
 
}

You can save the above class and then execute the batch via execute anonymous by running the below

BatchLatLongGenerator bJob = new BatchLatLongGenerator();
Database.executeBatch(bJob,10);



 
This was selected as the best answer
Angie YzaguirreAngie Yzaguirre
Hi and thank you for your quick response!!  I believe you are on the right track for what I need.  I do not need a map, just coordinates at the account level from the billing address on all accounts.

I am a bit confused on a few things:
1- I copy/pasted the code into an Apex Class and got a few errors, should I be copying the entire code you posted?
2- I see the coordinates in the code from the snapshot picture I attached as an example.
3- After I figure out how to save the above class, how do I execute the batch via execute anomymous?  Where am I supposed to do that part?

Thank you for your time!!
logontokartiklogontokartik
Hi Anie,

Create a new Apex Class with name 'BatchLatLongGenerator" and copy the entire code and save it. (you should not get any errors)

To execute the code, you can,

1. Open Developer Console --> Debug --> Open Execute Anonymous Window , copy /paste the 2 lines and click execute. You will receive email after the job is done.

 
Angie YzaguirreAngie Yzaguirre
Hello Kartik - I created the new Apex Class (with no errors) and executed the code within my sandbox using the Developer Console.  I did not receive an email yet and it's been three days.  Does it usually take a long time with many accounts or do you think someone went wrong?

Also, after the code has been executed, where would the fields be located that show the latitude and longitude coordinates for each account?
Angie YzaguirreAngie Yzaguirre
I still have not received an email, but I did see in the log that there is an error with the status:  List has no rows for assignment to SObject??

User-added image

Do you know what this means or how I can fix it?
Angie YzaguirreAngie Yzaguirre
I have created custom GeoLocation fields at the account level titled 'BillingLongitude' and 'BillingLatitude'.  I am now seeing success when executing the code, but still cannot pull any data into the reports nor have I received the email.
Angie YzaguirreAngie Yzaguirre
I also noticed that when I'm looking at the log, even though it says success, it looks like nothing was found??

User-added image
logontokartiklogontokartik
Hi Angie,
The BillingLatitude and BillingLongitude are the standard fields that should be available to you on account by default, you dont have to create them again. But if you want to show them, you need to have a formula field. Maybe the below post will help.

http://salesforce.stackexchange.com/questions/49668/how-to-display-location-part-of-address-field-type

Coming to the code above, the code should execute fine and get the latitude and longitude for you without any issues. Have you added "https://maps.googleapis.com" to remote site settings? if not please add and try execute

BatchLatLongGenerator bJob = new BatchLatLongGenerator();
Database.executeBatch(bJob,10);


in anonymous again.

It shouldnt take a long before you receive an email.


User-added image


 
Angie YzaguirreAngie Yzaguirre
I think it worked, omg!!  Thank you!!!

I just have one more question.  I noticed that when I change the billing address, the coordinates do not automatically change as well and they only change after I execute the code again.  Is there a way to automate this or the code needs to re-executed every time I need to pull coordinates?

Thank you again!!
logontokartiklogontokartik
Glad it worked for you.
You can schedule the job to run  or build a trigger that calls the code
Angie YzaguirreAngie Yzaguirre
Hello Kartik - I ran into an issue when deploying the code into Production.  I would now like to take the email part out of the code.  I deleted row 92-109, but I'm not sure what to delete from the first part of the code?

Can you guide me a bit more on this?

Thank you!