• Travis McDonald
  • NEWBIE
  • 10 Points
  • Member since 2015

  • Chatter
    Feed
  • 0
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 4
    Questions
  • 8
    Replies
Hey guys, so I have a trigger than runs whenever an address is updated or saved, to do reverse geocode and write the latitude and logitude to a field. The problem is, when a lot of records are updated at once, I run into the future call limit governer.....

See the code below: Any help is much appreciated.
 
/*// 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);
}*/

// Trigger runs getLocation() on Accounts with no Geolocation

trigger SetGeolocation on Account (after insert, after update) {
    for (Account a : trigger.new){
        if(system.isFuture() == FALSE){
          LocationCallouts.getLocation(a.id);
        }
    }
}

that's the trigger, which then runs this apex class:
 
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) {
        }
    }
}

This works very well, until you try to update a lot of records at once....when you do you run into the @future calls limit.


I had read that using a batch apex class can solve this, any advice on how to do that is appreciated.

I had posted a previous thread where another developer suggested I use a list to get around this, and it seemed to work, but after testing it, it broke the writing of geocode to the location field. See this thread: https://developer.salesforce.com/forums/ForumsMain?id=906F0000000B2h8IAC



 
Hey guys, I have a trigger with code:
/*// 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);
}*/

// Trigger runs getLocation() on Accounts with no Geolocation

trigger SetGeolocation on Account (after insert, after update) {
    for (Account a : trigger.new){
        if(system.isFuture() == FALSE){
          LocationCallouts.getLocation(a.id);
        }
    }
}

This pulls an apex class that has this code:
 
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) {
        }
    }
}

The problem is, I am going above the 10 max limit of future calls in Apex...

can someone please explain how I would convert my apex class intoa batch apex class so it runs request one at a time? See this threaD:

https://developer.salesforce.com/forums/ForumsMain?id=906F000000091NoIAI
Hello,

I've got a trigger that is set to write geocode to a location field on the accounts page when an address is updated.

The trigger code is:
 
// 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);
}

This works great - but what I am running into is the trigger will not fire if the Location__Latitude__s isn't null - that is to say if it already has geocode in it from a previous address, it won't put new geocode in because the field isn't empty.

How can I set this trigger to clear the field whenever the address is updated?

 
Hello, There are many discussions on how to map locations with google maps prior to the spring 2015 release, but now that apex:map and apex:mapmarker are available, I would like to figure out how to modify the marker color using that to bring in a new map rather than the javascript methods that have been previously used.

I currently importing the map to account pages with this code on the visualforce page:
 
<apex:page standardController="Account" extensions="accountMapExtensionTwo">

  <!--This page must be accessed with an Account Id in the URL. -->
  
  <apex:map width="600px" height="400px" mapType="roadmap">

    <apex:repeat value="{!Accounts}" var="acct">
        <apex:mapMarker title="{!acct.name}" position="{!acct.loc}"/>
    </apex:repeat>

  </apex:map>
  

</apex:page>



<!--<apex:page standardController="Account" extensions="accountMapExtension">

  This page must be accessed with an Account Id in the URL. 
  
  <apex:map width="600px" height="400px" mapType="roadmap">

    <apex:repeat value="{!Accounts}" var="acct">
        <apex:mapMarker title="{!Accounts[acct].Name}" position="{!Accounts[acct].BillingStreet},{!Accounts[acct].BillingCity},{!Accounts[acct].BillingState}"/>
    </apex:repeat>

  </apex:map>
  

</apex:page>-->

I then have an apex class that uses this code:
 
public class accountMapExtensionTwo {

    private final Account account;
    
    public accountMapExtensionTwo(ApexPages.StandardController stdController) {
        this.account = (Account)stdController.getRecord();
    }
    
    List<DisplayAccounts> Accts;
    
    public List<DisplayAccounts> getAccounts() {
        
        Map<Id,Account> mapList = new Map<Id,Account>();
        Set<Account> childList = new Set<Account>();
        Set<Id> parentId = new Set<Id>();
        
        Accts = new List<DisplayAccounts>();

        for(Account a : [SELECT Name, Location__longitude__s, Location__latitude__s, Parent.Id, BillingStreet, BillingCity, BillingState, (SELECT Name, Location__longitude__s, Location__latitude__s, BillingStreet, BillingCity, BillingState FROM ChildAccounts) FROM Account WHERE Id = :ApexPages.currentPage().getParameters().get('Id')]){
            
            accts.add(new DisplayAccounts(a));
            
            mapList.put(a.id,a);
            
            parentId.add(a.Parent.id);
            
            for(Account acc : a.ChildAccounts){
            
                accts.add(new DisplayAccounts(acc));
                
                mapList.put(acc.id,acc);
            }
        }
        
        List<Account> mapValueList = new List<Account>();
        mapValueList = mapList.values();
        
        for(Account a : [SELECT Name, Location__longitude__s, Location__latitude__s, BillingStreet, BillingCity, BillingState, (SELECT Name, BillingStreet, BillingCity, BillingState  FROM ChildAccounts) FROM Account WHERE Id IN :mapValueList]){
            
            for (Account acc : a.ChildAccounts){
            
                accts.add(new DisplayAccounts(acc));
                
                mapList.put(acc.id,acc);
            }
        }
        
        for(Account a : [SELECT Parent.Id FROM ACCOUNT WHERE Id IN :parentId]){
            parentId.add(a.Parent.Id);
        }
        
        for(Account a : [SELECT Name, Location__longitude__s, Location__latitude__s, BillingStreet, BillingCity, BillingState FROM Account WHERE Id IN :parentId]){
            
            accts.add(new DisplayAccounts(a));
            
            mapList.put(a.id,a);
        }
        
        return accts;
        
    } 
    
    public class DisplayAccounts {
        private Account acct;
        public DisplayAccounts (Account a){
            this.acct = a;
        }
        
        public Map<String,Double> loc {
            get { return 
                new Map<String,Double>{
                    'latitude' => acct.Location__latitude__s,
                    'longitude' => acct.Location__longitude__s
               };
           }
       }
       
       public String name {
           get { return acct.Name;}
       }
       
    }
}
This works perfect for what I'm trying to do, I should note that I'm using geocode for the map marker location.

This code lets you map multple places on an account page, by selecting the parent/child relationship that the accounts are a part of, translating the address for those accounts to geocode, and then displaying the points on a map of a parent account and it's child accounts..

What I'm running into however, is there is almost no documentation on how to change the color of apex:mapmarker. What I would like to do is set it up so that I can change the color of the mapmarker based on a custom field variable. I would also like to potentially change the color of the markers based on the parent/child relationship. However, any help at all on how to change the color/marker icon of apex:mapmarker would be greatly appreciated.

Thank you!







 
Hey guys, I have a trigger with code:
/*// 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);
}*/

// Trigger runs getLocation() on Accounts with no Geolocation

trigger SetGeolocation on Account (after insert, after update) {
    for (Account a : trigger.new){
        if(system.isFuture() == FALSE){
          LocationCallouts.getLocation(a.id);
        }
    }
}

This pulls an apex class that has this code:
 
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) {
        }
    }
}

The problem is, I am going above the 10 max limit of future calls in Apex...

can someone please explain how I would convert my apex class intoa batch apex class so it runs request one at a time? See this threaD:

https://developer.salesforce.com/forums/ForumsMain?id=906F000000091NoIAI
Hello,

I've got a trigger that is set to write geocode to a location field on the accounts page when an address is updated.

The trigger code is:
 
// 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);
}

This works great - but what I am running into is the trigger will not fire if the Location__Latitude__s isn't null - that is to say if it already has geocode in it from a previous address, it won't put new geocode in because the field isn't empty.

How can I set this trigger to clear the field whenever the address is updated?

 
Hello, There are many discussions on how to map locations with google maps prior to the spring 2015 release, but now that apex:map and apex:mapmarker are available, I would like to figure out how to modify the marker color using that to bring in a new map rather than the javascript methods that have been previously used.

I currently importing the map to account pages with this code on the visualforce page:
 
<apex:page standardController="Account" extensions="accountMapExtensionTwo">

  <!--This page must be accessed with an Account Id in the URL. -->
  
  <apex:map width="600px" height="400px" mapType="roadmap">

    <apex:repeat value="{!Accounts}" var="acct">
        <apex:mapMarker title="{!acct.name}" position="{!acct.loc}"/>
    </apex:repeat>

  </apex:map>
  

</apex:page>



<!--<apex:page standardController="Account" extensions="accountMapExtension">

  This page must be accessed with an Account Id in the URL. 
  
  <apex:map width="600px" height="400px" mapType="roadmap">

    <apex:repeat value="{!Accounts}" var="acct">
        <apex:mapMarker title="{!Accounts[acct].Name}" position="{!Accounts[acct].BillingStreet},{!Accounts[acct].BillingCity},{!Accounts[acct].BillingState}"/>
    </apex:repeat>

  </apex:map>
  

</apex:page>-->

I then have an apex class that uses this code:
 
public class accountMapExtensionTwo {

    private final Account account;
    
    public accountMapExtensionTwo(ApexPages.StandardController stdController) {
        this.account = (Account)stdController.getRecord();
    }
    
    List<DisplayAccounts> Accts;
    
    public List<DisplayAccounts> getAccounts() {
        
        Map<Id,Account> mapList = new Map<Id,Account>();
        Set<Account> childList = new Set<Account>();
        Set<Id> parentId = new Set<Id>();
        
        Accts = new List<DisplayAccounts>();

        for(Account a : [SELECT Name, Location__longitude__s, Location__latitude__s, Parent.Id, BillingStreet, BillingCity, BillingState, (SELECT Name, Location__longitude__s, Location__latitude__s, BillingStreet, BillingCity, BillingState FROM ChildAccounts) FROM Account WHERE Id = :ApexPages.currentPage().getParameters().get('Id')]){
            
            accts.add(new DisplayAccounts(a));
            
            mapList.put(a.id,a);
            
            parentId.add(a.Parent.id);
            
            for(Account acc : a.ChildAccounts){
            
                accts.add(new DisplayAccounts(acc));
                
                mapList.put(acc.id,acc);
            }
        }
        
        List<Account> mapValueList = new List<Account>();
        mapValueList = mapList.values();
        
        for(Account a : [SELECT Name, Location__longitude__s, Location__latitude__s, BillingStreet, BillingCity, BillingState, (SELECT Name, BillingStreet, BillingCity, BillingState  FROM ChildAccounts) FROM Account WHERE Id IN :mapValueList]){
            
            for (Account acc : a.ChildAccounts){
            
                accts.add(new DisplayAccounts(acc));
                
                mapList.put(acc.id,acc);
            }
        }
        
        for(Account a : [SELECT Parent.Id FROM ACCOUNT WHERE Id IN :parentId]){
            parentId.add(a.Parent.Id);
        }
        
        for(Account a : [SELECT Name, Location__longitude__s, Location__latitude__s, BillingStreet, BillingCity, BillingState FROM Account WHERE Id IN :parentId]){
            
            accts.add(new DisplayAccounts(a));
            
            mapList.put(a.id,a);
        }
        
        return accts;
        
    } 
    
    public class DisplayAccounts {
        private Account acct;
        public DisplayAccounts (Account a){
            this.acct = a;
        }
        
        public Map<String,Double> loc {
            get { return 
                new Map<String,Double>{
                    'latitude' => acct.Location__latitude__s,
                    'longitude' => acct.Location__longitude__s
               };
           }
       }
       
       public String name {
           get { return acct.Name;}
       }
       
    }
}
This works perfect for what I'm trying to do, I should note that I'm using geocode for the map marker location.

This code lets you map multple places on an account page, by selecting the parent/child relationship that the accounts are a part of, translating the address for those accounts to geocode, and then displaying the points on a map of a parent account and it's child accounts..

What I'm running into however, is there is almost no documentation on how to change the color of apex:mapmarker. What I would like to do is set it up so that I can change the color of the mapmarker based on a custom field variable. I would also like to potentially change the color of the markers based on the parent/child relationship. However, any help at all on how to change the color/marker icon of apex:mapmarker would be greatly appreciated.

Thank you!