Finding What's Hot and What's Not with geolocation
Let’s see, clear some cobwebs, dust off some settings, check that it was indeed over a year since my last post. Yep, every thing seems in order. To kick off this post-a-versary, how about a quick exploration of Salesforce’s built in geolocation features, now that this data has been automatically added to the standard address fields!
A quick primer for the uninitiated, geolocation information is the location of something on the globe. Instead of using streets or landmarks, it uses latitude and longitude to find a location’s exact position. With this information at our disposal we can start to look at data on a geographic level. To illustrate this, we will look at a fictional company and how they can use geolocation to better outfit their sales people.
Path Skull
Introducing Path Skull, a fictional manufacturer of outdoor goods. They sell to retailers instead of directly to consumers so their sales people need to work to get their product into stores. To help them out when courting leads, they are going to use geolocation to figure out what sort of products sell well in a particular area. There is no need to show off your rugged sneakers when there is only demand for boots or your triple insulated sleeping bag when the market just wants to keep cool at night.
A clean sweep
All of this will depend on having the latitude and longitude of your accounts and leads. You do have that populated, right? No? That is fine because with Salesforce and Data.com it is all automatic, all you need to do first is to enable it. Go into the setting for your org and locate the ‘Clean Rules.’ For our examples, we will be activating ‘Geocodes for Account Shipping Address’ and ‘Geocodes for Lead Address’ but please activate whatever works for your use case. For more information, check out the official Salesforce release notes for the geocode clean rules.
Button Up
A new button on the lead will be the point of entry to this new functionality. Leads have a built in address field that will become the center of our area to report on. First off we will create a new visualforce page with the lead object as our standard controller and a new apex class to use as our controller extension. In the constructor of our extension we will use a distance query to find all the accounts within a 100 mile radius.
SELECT Id FROM Account WHERE DISTANCE(ShippingAddress, :targetLead.Address, 'mi') < 100
For this example I am just hard coding 100 miles, but for greater flexibility, consider a custom setting with the ability to change it on the results screen. Next we will grab the top five assets and products as well as the bottom five for the previously found accounts. The top five is the obvious one but the bottom five could just as well help you with what products not to even waste your breath on.
SELECTProduct2.Id productId, Product2.Name productName
FROM Asset
WHERE AccountId IN :accountIds
GROUP BY Product2.Id, Product2.Name
ORDER BY SUM(Quantity) DESC
LIMIT 5
SELECT Product2.Id productId, Product2.Name productName
FROM Asset WHERE AccountId IN :accountIds
GROUP BY Product2.Id, Product2.Name
ORDER BY SUM(Quantity) ASC
LIMIT 5
Once you have your data, it is up to you to display it in the most relevant way on your page. To wrap it all up, add a new button to the lead which opens the visualforce page and place the button on the lead’s page layout. With just a few lines of code your sales people now know what a lead may be interested in from the outset. How easy was it? With comments, the source for the controller turned out to be only 18 lines long.
public with sharing class ProductPopularityController{
public List<AggregateResult> topAssets {get; set;}
public List<AggregateResult> bottomAssets {get; set;}
public ProductPopularityController(ApexPages.StandardController stdController){
//Get the lead
stdController.addFields(new List<String>{'Address'});
Lead targetLead= (Lead)stdController.getRecord();
//Get the nearby accounts
Set<Id> accountIds = new Map<Id, Account>([SELECT Id FROM Account WHERE DISTANCE(ShippingAddress, :targetLead.Address, 'mi') < 100]).keySet();
//Now get the top and bottom five products
topAssets = [SELECT Product2.Id productId, Product2.Name productName FROM Asset WHERE AccountId IN :accountIds GROUP BY Product2.Id, Product2.Name ORDER BY SUM(Quantity) DESC LIMIT 5];
bottomAssets = [SELECT Product2.Id productId, Product2.Name productName FROM Asset WHERE AccountId IN :accountIds GROUP BY Product2.Id, Product2.Name ORDER BY SUM(Quantity) ASC LIMIT 5];
}
}
The visualforce page to display the data as a pair of lists was only 15 lines long.
<apex:page standardController="Lead" extensions="ProductPopularityController">
<h1>HOT</h1>
<ul>
<apex:repeat value="{!topAssets}" var="product">
<li><apex:outputText value="{!product['productName']}" /></li>
</apex:repeat>
</ul>
<hr />
<h1>Not</h1>
<ul>
<apex:repeat value="{!bottomAssets}" var="product">
<li><apex:outputText value="{!product['productName']}" /></li>
</apex:repeat>
</ul>
</apex:page>
This was a simple example but with location-based SOQL queries and the location class, making use of location doesn’t have to be hard.