Salesforce : Locate nearest Account/Contact from your current location

Salespeople have to travel around meeting potential customers. So, a useful functionality which may come in handy a lot would be the ability to know the nearest Customer/contact in the city the user is visiting. Here, I have implemented a custom solution which helps out in this scenario. You need to have basic knowledge of Lightning Aura components and Apex code to replicate it in your orgs.

So, first step is to enable Data Integration Rules for Account Billing/Shipping address. This allows Salesforce to populate the latitude and longitude values of the recorded address using Data.com. Once the rules are enabled, next step is to dive right into the code.

Create a new Lightning component and name it NearestAccountComponent. Copy and paste the below code in it.

<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes,force:lightningQuickAction" 
                access="global"
                controller="NearestAccountController">
    <aura:attribute name="latitude" type="String"/>
    <aura:attribute name="longitude" type="String"/>
    <aura:attribute name="NearestAccount" type="Object"/>
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    <lightning:card footer="" title="Nearest Account Component">
    <div class="slds-p-horizontal_small slds-m-top_xx-small">
        <lightning:button variant="brand" label="Get Nearest Account!" title="nearbyContacts" onclick="{!c.getNearByContacts}"/>
    </div>
    <div class="slds-p-horizontal_small slds-m-top_x-small">
        <aura:if isTrue="{!v.NearestAccount}">
            <lightning:card footer="" title="Nearest Account">
                <p class="slds-p-horizontal_small slds-m-top_x-small">
                    <b>Account Name </b>: {!v.NearestAccount.accObj.Name}
                </p>
                <p class="slds-p-horizontal_small slds-m-top_x-small">
                    <b>Account Address</b> :- 
                </p>
                <p class="slds-p-horizontal_small slds-m-top_x-small">
                    {!v.NearestAccount.accObj.BillingStreet}
                </p>
                <p class="slds-p-horizontal_small slds-m-top_x-small">
                    {!v.NearestAccount.accObj.BillingCity}
                </p>
                <p class="slds-p-horizontal_small slds-m-top_x-small">
                    {!v.NearestAccount.accObj.Billingstate}
                </p>
                <p class="slds-p-horizontal_small slds-m-top_x-small">
                    {!v.NearestAccount.accObj.BillingCountry}
                </p>
                <p class="slds-p-horizontal_small slds-m-top_x-small">
                    Distance : {!v.NearestAccount.distance}
                </p>
                <p class="slds-p-horizontal_small slds-m-top_x-small">
                    Accuracy : {!v.NearestAccount.accObj.BillingGeocodeAccuracy}
                </p>
            </lightning:card>
        </aura:if>
    </div>
    </lightning:card>
</aura:component>

This component fetches the current location of the user and displays the nearest Account on the basis of it’s Billing Address. Next step is to create the Js client side controller. Paste the following code in the controller.

({
    doInit : function(component, event, helper){

        console.log("capability is there");
        var latitude;
        var longitude;
        navigator.geolocation.getCurrentPosition(function(e) {
            latitude = e.coords.latitude;
            longitude = e.coords.longitude;
            component.set("v.latitude",latitude);
            component.set("v.longitude",longitude);
        }, function() {
            console.log('There was an error.');
        },{maximumAge:600000});
        
        setTimeout(function(){
            console.log("After timeout");
            var action = component.get("c.getNearestAccount");
            action.setParams({
                "lat": latitude,
                "lon": longitude
            });
            action.setCallback(
                this,function(response){
                    var storeResponse = response.getReturnValue();
                    var state = response.getState();
                    if(state === "SUCCESS")
                    {
                        if(storeResponse != null){
                        console.log("Successful "+ JSON.stringify(storeResponse));
                        component.set("v.NearestAccount" , storeResponse);
                        }
                        else{
                            console.log("No Data found!");
                        }
                    }
                }
            );
            $A.enqueueAction(action);
        }, 3000);
    },
    getNearByContacts : function(component, event, helper) {
        console.log("capability is there");
        var latitude;
        var longitude;
        navigator.geolocation.getCurrentPosition(function(e) {
            console.log(e.coords.latitude + ', ' + e.coords.longitude);
            latitude = e.coords.latitude;
            longitude = e.coords.longitude;
            component.set("v.latitude",latitude);
            component.set("v.longitude",longitude);
        }, function() {
            console.log('There was an error.');
        },{maximumAge:600000});
        
        setTimeout(function(){
            console.log("After timeout");
            var action = component.get("c.getNearestAccount");
            action.setParams({
                "lat": latitude,
                "lon": longitude
            });
            action.setCallback(
                this,function(response){
                    var storeResponse = response.getReturnValue();
                    var state = response.getState();
                    if(state === "SUCCESS")
                    {
                        if(storeResponse != null){
                        console.log("Successful "+ JSON.stringify(storeResponse));
                        component.set("v.NearestAccount" , storeResponse);
                        }
                        else{
                            console.log("No Data found!");
                        }
                    }
                }
            );
            $A.enqueueAction(action);
        }, 3000);        
    }
})

Since we make two Asynchronous calls, one to fetch the current location and the other to get the nearest Account, I have used the setTimeout funtion to delay the call of the second server call by 3 seconds. Now, let’s create the server side controller. Create a new class named NearestAccountController and copy the below code.

public with sharing class NearestAccountController {
    @AuraEnabled
    public static NearestAccountWrapper getNearestAccount(String lat, String lon){
        system.debug('Inside&** '+ 'lat '+lat+' lon '+lon);
        List<Account> accList = new List<Account>();
        
        accList = [Select id , name, BillingLatitude, BillingLongitude 
                   From Account 
                   Where BillingLatitude != null AND BillingLongitude != null Limit 50000];
        
        Map<Id, Double> mapOfAccountIdToDistance = new Map<Id, Double>();
        Double val0 = 0.0;
        Double val1 = 0.0;
        Double val2 = 0.0;
        Double val3 = 0.0;
        Double p = 0.017453292519943295;
        Double a = 0.00;
        Double b = 0.00;
        Double c = 0.00;
        Double d = 0.00;
        
        for(Account accObj : accList){
            if(accObj.BillingLatitude != null &&
               accObj.BillingLongitude != null
              ){
                  
                  a = 0.5 - System.Math.cos((accObj.BillingLatitude - Double.valueOf(lat)) * p)/2 + 
                      System.Math.cos(Double.valueOf(lat) * p) * System.Math.cos(accObj.BillingLatitude * p) *
                      (1 - System.Math.cos((Double.valueOf(lon) - accObj.BillingLongitude)* p ))/2;
                  b = System.Math.sqrt(a);
                  c = System.Math.asin(b);
                  d = 12742 * c;
                  
                  mapOfAccountIdToDistance.put(accObj.Id,d);
              }
        }
        system.debug('map print*$ '+ mapOfAccountIdToDistance);
        
        List<Account> accListBilling = new List<Account>();
        accListBilling = [Select id,name,BillingGeocodeAccuracy,BillingLatitude, BillingLongitude, BillingStreet,BillingCity,BillingState,BillingCountry from Account where id in: mapOfAccountIdToDistance.keySet()];
        Decimal minValue = 100000000.0;
        Id idOfNearestAccount = null;
        Account accObjNearest = new Account();
        for(Account accObj : accListBilling){
            if((System.Math.sqrt(mapOfAccountIdToDistance.get(accObj.Id)) < minValue) && (mapOfAccountIdToDistance.get(accObj.Id) != null) ){
                minValue = mapOfAccountIdToDistance.get(accObj.Id);
                idOfNearestAccount = accObj.Id;
                accObjNearest = accObj;
            }
        }
        
        NearestAccountWrapper wrapObj = new NearestAccountWrapper(accObjNearest,minValue);
        if(accObjNearest != null){
            return wrapObj;
        }
        else {
            return null;
        }
    }
}

The above code calculates the distance between the latitude-longitude values and returns the distance and the nearest account record. Create a wrapper class which will encapsulate the nearest account record and it’s distance. Name it NearestAccountWrapper and paste the below code.

public class NearestAccountWrapper {
    @AuraEnabled public Account accObj;
    @AuraEnabled public Decimal distance;
    public NearestAccountWrapper(Account accObj , Decimal distance){
        this.accObj = accObj;
        this.distance = distance;
    } 
}

Once completed, add the component to the sales app and try it for yourself.

Design a site like this with WordPress.com
Get started
search previous next tag category expand menu location phone mail time cart zoom edit close