(For more resources related to this topic, see here.)
First, you need to obtain an API key for the Google Geocoding API:
Now, we need to add a Salesforce remote site for the Google Maps API:
Next, we need to add a Location field to the Account object:
Next, we need an Apex utility class to geocode an address using the Google Geocoding API:
// static variable to determine if geocoding has already occurred private static Boolean geocodingCalled = false; // wrapper method to prevent calling future methods 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; geocodeAddress(accountId); }
// we need a future method to call Google Geocoding API from Salesforce @future (callout=true) static private void geocodeAddress(id accountId) { // Key for Google Maps Geocoding API String geocodingKey = '[Your API Key here]'; // get the passed in address Account geoAccount = [SELECT BillingStreet, BillingCity, BillingState, BillingCountry, BillingPostalCode FROM Account WHERE id = :accountId]; // check that we have enough information to geocode the address if ((geoAccount.BillingStreet == null) || (geoAccount.BillingCity == null)) { System.debug(LoggingLevel.WARN, 'Insufficient Data to Geocode Address'); return; } // create a string for the address to pass to Google Geocoding API String geoAddress = ''; if (geoAccount.BillingStreet != null) geoAddress += geoAccount.BillingStreet + ', '; if (geoAccount.BillingCity != null) geoAddress += geoAccount.BillingCity + ', '; if (geoAccount.BillingState != null) geoAddress += geoAccount.BillingState + ', '; if (geoAccount.BillingCountry != null) geoAddress += geoAccount.BillingCountry + ', '; if (geoAccount.BillingPostalCode != null) geoAddress += geoAccount.BillingPostalCode; // encode the string so we can pass it as part of URL geoAddress = EncodingUtil.urlEncode(geoAddress, 'UTF-8'); // build and make the callout to the Geocoding API Http http = new Http(); HttpRequest request = new HttpRequest(); request.setEndpoint('https://maps.googleapis.com/maps/api/geocode/json?address=' + geoAddress + '&key=' + geocodingKey + '&sensor=false'); request.setMethod('GET'); request.setTimeout(60000); try { // make the http callout HttpResponse response = http.send(request); // parse JSON to extract co-ordinates JSONParser responseParser = JSON.createParser(response.getBody()); // initialize co-ordinates double latitude = null; double longitude = null; while (responseParser.nextToken() != null) { if ((responseParser.getCurrentToken() == JSONToken.FIELD_NAME) && (responseParser.getText() == 'location')) { responseParser.nextToken(); while (responseParser.nextToken() != JSONToken.END_OBJECT) { String locationText = responseParser.getText(); responseParser.nextToken(); if (locationText == 'lat') latitude = responseParser.getDoubleValue(); else if (locationText == 'lng') longitude = responseParser.getDoubleValue(); } } } // update co-ordinates on address if we get them back if (latitude != null) { geoAccount.Location__Latitude__s = latitude; geoAccount.Location__Longitude__s = longitude; update geoAccount; } } catch (Exception e) { System.debug(LoggingLevel.ERROR, 'Error Geocoding Address - ' + e.getMessage()); } }
String geocodingKey = '[Your API Key here]';
Finally, we need to implement an Apex trigger class to geocode the Billing Address when an Account is added or updated
trigger geocodeAccountAddress on Account (after insert, after update) { // bulkify trigger in case of multiple accounts for (Account account : trigger.new) { // check if Billing Address has been updated Boolean addressChangedFlag = false; if (Trigger.isUpdate) { Account oldAccount = Trigger.oldMap.get(account.Id); if ((account.BillingStreet != oldAccount.BillingStreet) || (account.BillingCity != oldAccount.BillingStreet) || (account.BillingCountry != oldAccount.BillingCountry) || (account.BillingPostalCode != oldAccount.BillingPostalCode)) { addressChangedFlag = true; System.debug(LoggingLevel.DEBUG, '***Address changed for - ' + oldAccount.Name); } } // if address is null or has been changed, geocode it if ((account.Location__Latitude__s == null) || (addressChangedFlag == true)) { System.debug(LoggingLevel.DEBUG, '***Geocoding Account - ' + account.Name); AccountGeocodeAddress.DoAddressGeocode(account.id); } } }
The after insert / after update account trigger itself is relatively simple. If the Location field is blank, or the Billing Address has been updated, a call is made to the AccountGeocodeAddress.DoAddressGeocode method to geocode the address against the Google Maps Geocoding API.
Congratulations, you have now completed the Geolocation trigger for your Salesforce Account Object. With this, we can calculate distances between two objects in Salesforce or search for accounts/contacts within a certain radius.
Further resources on this subject:
I remember deciding to pursue my first IT certification, the CompTIA A+. I had signed…
Key takeaways The transformer architecture has proved to be revolutionary in outperforming the classical RNN…
Once we learn how to deploy an Ubuntu server, how to manage users, and how…
Key-takeaways: Clean code isn’t just a nice thing to have or a luxury in software projects; it's a necessity. If we…
While developing a web application, or setting dynamic pages and meta tags we need to deal with…
Software architecture is one of the most discussed topics in the software industry today, and…
View Comments
Hello
I tried your tuto in my sandbox,
But I've some error. I thinks it's because of return lines into your code. Like "//"
And I don't have a name of geocodeAddress in point 6.
Could you send me the 3 classes by txt file?
Kind Regards
Benoit
public class AccountGeocodeAddress {
// static variable to determine if geocoding has already occurred
private static Boolean geocodingCalled = false;
// wrapper method to prevent calling future methods from an existing future context
public static void DoAddressGeocode (id accountId){
system.debug('Called');
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;
geocodeAddress(accountId);
}
// we need a future method to call Google Geocoding API from Salesforce
@future (callout=true)
static private void geocodeAddress(id accountId){
// Key for Google Maps Geocoding API
String geocodingKey = 'Your API Key Value';
// get the passed in address
Account geoAccount = [SELECT BillingStreet, BillingCity, BillingState, BillingCountry,
BillingPostalCode,Locations__Latitude__s,Locations__Longitude__s
FROM
Account
WHERE
id = :accountId];
// check that we have enough information to geocode the address
if((geoAccount.BillingStreet == null) || (geoAccount.BillingCity == null)) {
System.debug(LoggingLevel.WARN,
'Insufficient Data to Geocode Address');
return;
}
// create a string for the address to pass to Google Geocoding API
String geoAddress = '';
if(geoAccount.BillingStreet != null)
geoAddress += geoAccount.BillingStreet + ', ';
if(geoAccount.BillingCity != null)
geoAddress+= geoAccount.BillingCity + ', ';
if(geoAccount.BillingState != null)
geoAddress+= geoAccount.BillingState + ', ';
if(geoAccount.BillingCountry != null)
geoAddress+= geoAccount.BillingCountry + ', ';
if(geoAccount.BillingPostalCode != null)
geoAddress+= geoAccount.BillingPostalCode;
// encode the string so we can pass it as part of URL
geoAddress = EncodingUtil.urlEncode(geoAddress, 'UTF-8');
// build and make the callout to the Geocoding API
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setEndpoint('https://maps.googleapis.com/maps/api/geocode/json?address='+geoAddress + '&key=' + geocodingKey+ '&sensor=false');
request.setMethod('GET');
request.setTimeout(60000);
//try {
// make the http callout
HttpResponse response = http.send(request);
// parse JSON to extract co-ordinates
JSONParser responseParser = JSON.createParser(response.getBody());
// initialize co-ordinates
System.debug('JSONParser$$'+responseParser);
double latitude = null;
double longitude = null;
while (responseParser.nextToken() != null) {
System.debug('currentToken!!'+responseParser.getCurrentToken());
System.debug('NextToken!!'+responseParser.nextToken());
System.debug('text@@'+responseParser.getText());
System.debug('JSOn!!'+JSONToken.FIELD_NAME +'###'+JSONToken.END_OBJECT);
if((responseParser.getCurrentToken() == JSONToken.FIELD_NAME)) {
responseParser.nextToken();
while(responseParser.nextToken() != JSONToken.END_OBJECT) {
String locationText = responseParser.getText();
responseParser.nextToken();
if (locationText == 'lat')
latitude = responseParser.getDoubleValue();
else if (locationText == 'lng')
longitude = responseParser.getDoubleValue();
}
}
}
// update co-ordinates on address if we get them back
if(latitude != null) {
System.debug('!!'+latitude);
System.debug('@@'+longitude);
geoAccount.Locations__Latitude__s
= latitude;
geoAccount.Locations__Longitude__s
= longitude;
update geoAccount;
}
/* } catch
(Exception e) {
System.debug(LoggingLevel.ERROR, 'Error Geocoding Address - ' + e.getMessage());
}*/
}
}