Adding a Geolocation Trigger to the Salesforce Account Object

Exclusive offer: get 50% off this eBook here
Force.com Development Blueprints

Force.com Development Blueprints — Save 50%

Design and develop real-world, cutting-edge cloud applications using the powerful Force.com development framework with this book and ebook

$32.99    $16.50
by Stephen Moss | May 2014 | Enterprise Articles

This article has been written by Stephen Moss, the author of Force.com Development Blueprints. You might have noticed that since the Winter '13 release, Salesforce offers a custom field type of geolocation. This field can be used to specify a location by its latitude and longitude. However, the standard Salesforce user interface doesn't provide a great deal of support for filling these fields in with useful values.

Fortunately, with a little bit of Apex code, we can add a trigger to the Salesforce Account Object to automatically geolocate an address when an account is saved or updated.

(For more resources related to this topic, see here.)

Obtaining the Google API key

First, you need to obtain an API key for the Google Geocoding API:

  1. Visit https://code.google.com/apis/console and sign in with your Google account (assuming you already have one).
  2. Click on the Create Project button.
  3. Enter My Salesforce Account Project for the Project name.
  4. Accept the default value for the Project ID.
  5. Click on Create.
  6. Click on APIs & auth from the left-hand navigation bar.
  7. Set the Geocoding API to ON.

  8. Select Credentials and click on CREATE NEW KEY.
  9. Click on the Browser Key button.
  10. Click on Create to generate the key. Make a note of the API key.

Adding a Salesforce remote site

Now, we need to add a Salesforce remote site for the Google Maps API:

  1. Navigate to Setup | Security Controls | Remote Site Settings.
  2. Click on the New Remote Site button.
  3. Enter Google_Maps_API for the Remote Site Name.
  4. Enter https://maps.googleapis.com for the Remote Site URL.
  5. Ensure that the Active checkbox is checked.
  6. Click on Save.
  7. Your remote site detail should resemble the following screenshot:

Adding the Location custom field to Account

Next, we need to add a Location field to the Account object:

  1. Navigate to Setup | Customize | Accounts | Fields.
  2. Click on the New button in the Custom Fields & Relationships section.
  3. Select Geolocation for the Data Type. Click on Next.
  4. Enter Location for the Field Label. The Field Name should also default to Location.
  5. Select Decimal for the Latitude and Longitude Display Notation.
  6. Enter 7 for the Decimal Places. Click on Next.
  7. Click on Next to accept the defaults for Field-Level Security.
  8. Click on Save to add the field to all account related page layouts.

Adding the Apex Utility Class

Next, we need an Apex utility class to geocode an address using the Google Geocoding API:

  1. Navigate to Setup | Develop | Apex Classes.
  2. All of the Apex classes for your organization will be displayed. Click on Developer Console.
  3. Navigate to File | New | Apex Class.
  4. Enter AccountGeocodeAddress for the Class Name and click on OK.
  5. Enter the following code into the Apex Code Editor in your Developer Console window:

    // 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); }

  6. The AccountGeocodeAddress method and public static variable geocodingCalled protect us from a potential error where a future method may be called from within a future method that is already executing. If this isn't the case, we call the geocodeAddress method that is defined next. Enter the following code into the Apex Code Editor in your Developer Console window:

    // 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());   } }

  7. Insert your Google API key in the following line of code:

    String geocodingKey = '[Your API Key here]';

  8. Navigate to File | Save.

Adding the Apex Trigger

Finally, we need to implement an Apex trigger class to geocode the Billing Address when an Account is added or updated

  1. Navigate to Setup | Develop | Apex Triggers.
  2. All of the Apex triggers for your organization will be displayed. Click on Developer Console.
  3. Navigate to File | New | Apex Trigger in the Developer Console.
  4. Enter geocodeAccountAddress in the Name field.
  5. Select Account in the Objects dropdown list and click on Submit.
  6. Enter the following code into the Apex Code Editor in your Developer Console window:

    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);     }   } }

  7. Navigate to File | Save.

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.

Summary

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.

Resources for Article:


Further resources on this subject:


Force.com Development Blueprints Design and develop real-world, cutting-edge cloud applications using the powerful Force.com development framework with this book and ebook
Published: May 2014
eBook Price: $32.99
Book Price: $54.99
See more
Select your format and quantity:

About the Author :


Stephen Moss

Stephen Moss is a Salesforce.com-certified administrator and Force.com developer.

After his first brush with computing on Apple II, he was hooked to it and started programming on a Commodore 64 computer, back in the 1980s, to automate his math homework.

He has over 20 years' experience in the IT industry in a multitude of roles, ranging across application domains as diverse as CRM, GIS, manufacturing, broadcast engineering, billing, field services, IVR speech recognition, and call center management systems.

In addition to cloud computing, he also has a keen interest in the SOA/BPM systems (he is an Oracle BPM Suite Certified Implementation Specialist) and mobile device development (he even has an original PalmPilot in his attic somewhere!).

He is currently consulting with a range of clients, helping them embrace cloud computing and digitizing their businesses for the 21st century.

Books From Packt


Building E-commerce Sites with VirtueMart Cookbook
Building E-commerce Sites with VirtueMart Cookbook

Salesforce CRM: The Definitive Admin Handbook
Salesforce CRM: The Definitive Admin Handbook

Force.com Developer Certification Handbook (DEV401)
Force.com Developer Certification Handbook (DEV401)

Bootstrap Site Blueprints
Bootstrap Site Blueprints

Force.com Tips and Tricks
Force.com Tips and Tricks

Salesforce CRM Admin Cookbook
Salesforce CRM Admin Cookbook

Developing Applications with Salesforce Chatter
Developing Applications with Salesforce Chatter

Salesforce CRM: The Definitive Admin Handbook - Second Edition
Salesforce CRM: The Definitive Admin Handbook - Second Edition


Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software