Creating a Geolocation Trigger in Salesforce Winter '13 - Archive of IC Blog

Creating a Geolocation Trigger in Salesforce Winter ’13

NOTE: Due to a change in the Google Maps API licensing, we recommend you have a look at Geopointe on the AppExchange instead of following this blog post.

In Winter ’13, we will see a brand new field type for Geolocation that will store latitude and longitude coordinates. This can open up a whole slew of new possibilites for the platform, such as calculating distances between two objects in Salesforce or searching for Accounts / Contacts within a certain radius.

But when you finally have the option to use Geolocation in your org this October, you might be at a loss for finding useful functionality with it. Just for starters, let’s add a custom location field for Accounts and add it to the Account page layout.

Great… so now what?

As we can see, there is nothing in the field. If we go to the edit page, we have the option of manually entering the latitude and longitude coordinates, but I am sure that typing in all those numbers would drive anyone crazy.

We need to get some useful data into the system without having to manually type it in. If we had a spreadsheet of coordinates, we could import them into the system via Data Loader. But I think that we can use the platform itself with a little help from the Google Maps API.

First, make sure that your Location__c field is set to decimals to the 7th digit. The coordinates sent from Google will be in this format. Next, go to Setup -> Administration Setup -> Security Controls -> Remote Site Settings and then add the Google Maps API domain http://maps.googleapis.com to your org.

Now we’re going to create a static remote function to callout to the Google Maps API with an Account billing address. If we get back coordinates from Google, we write them to Salesforce. Note that if we name our Geolocation field Location__c, the coordinates will be stored in the Location__Latitude__s and Location__Longitude__s fields.

public class LocationCallouts {

     @future (callout=true)  // future method needed to run callouts from Triggers
      static public void getLocation(id accountId){
        // gather account info
        Account a = [SELECT BillingCity,BillingCountry,BillingPostalCode,BillingState,BillingStreet FROM Account WHERE id =: accountId];

        // create an address string
        String address = '';
        if (a.BillingStreet != null)
            address += a.BillingStreet +', ';
        if (a.BillingCity != null)
            address += a.BillingCity +', ';
        if (a.BillingState != null)
            address += a.BillingState +' ';
        if (a.BillingPostalCode != null)
            address += a.BillingPostalCode +', ';
        if (a.BillingCountry != null)
            address += a.BillingCountry;

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

        // build callout
        Http h = new Http();
        HttpRequest req = new HttpRequest();
        req.setEndpoint('http://maps.googleapis.com/maps/api/geocode/json?address='+address+'&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());
            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) {
        }
    }
}

We can call this function anywhere in our Salesforce org, but I think it would be most appropriate in a trigger. So let’s add a trigger.

// Trigger runs getLocation() on Accounts with no Geolocation
trigger SetGeolocation on Account (after insert, after update) {
    for (Account a : trigger.new)
        if (a.Location__Latitude__s == null)
            LocationCallouts.getLocation(a.id);
}

Now when we insert or update an account with a billing address, we will get the coordinates populated into the field.

This is just the start of what we can do with Geolocation in Salesforce, but we will save distance functions for future blog posts. You can download the source code used in this post on the Internet Creations GitHub repository. If you have any questions about our geolocation code, contact us by adding a comment below, or @ reply us on Twitter. We’re on Facebook too!