1public with sharing class exampleBatchGeocode {
2 public exampleBatchGeocode() {}
3
4 public exampleBatchGeocodeWithSFMaps(){
5 List<Account> accountList = [SELECT Id, Name, BillingAddress FROM Account WHERE Name like 'W%' AND BillingLongitude = Null];
6 Map<String, Account> accounts = new Map<String, Account>(); // Map of the Accounts to link the results back to
7 Map<String, Map<String, String>> addresses = new Map<String, Map<String, String>>();
8 for (Account acc : accounts) {
9 // It is recommended to prevent sending null fields. Not done here for illustrative purposes.
10 Map<String, String> address = new Map<String, String>{
11 'address' => acc.BillingAddress.getStreet() + ', ' + acc.BillingAddress.getCity() + ', ' + acc.BillingAddress.getPostalCode() + ', ' + acc.BillingAddress.getCountry()
12 };
13 String idstr = Id.valueOf(acc.id);
14 addresses.put(idstr, address);
15 accounts.put(idstr.toLowerCase(), acc);// Ids will be lowercase in results.
16 // Illustrative Sample: Three accounts in list.
17 // [{
18 // id: '005B0000005LDrUIA1',
19 // name: 'White House',
20 // address: '1600 Pennsylvania Ave NW, Washington, DC 20500, United States'
21 // }, {
22 // id: '005B0000005LDrUIA2',
23 // name: 'Washington Monument'
24 // address: '2 15th St NW, Washington, null, United States'
25 // }, {
26 // id: '005B0000005LDrUIA3',
27 // name: 'Wash and Ride',
28 // address: 'null, null, null, United States'
29 // }]
30 }
31
32 Map<String, Object> response; // Deserialized Untyped Response
33 try {
34 response = maps.API.BatchGeocode(new Map<String, Object> {
35 'version' => '2', // Required. Hardcode value to 2. Has no impact on results or process.
36 'address_info' => JSON.serialize(addresses)
37 });
38 }
39 catch (Exception ex) {
40 // Handle exception. Simple log for illustrative purposes.
41 System.debug(ex);
42 return;
43 }
44 List<Account> accountsWithBadData = new List<Account>();
45 Boolean callSuccess = (Boolean)response.get('success');
46 if(callSuccess != null){
47 Map<String, Object> results = (Map<String, Object>)response.get('results');
48 for(String accountId: results.keySet()){
49 Account acc = accounts.get(accountId);
50 Map<String, Object> record = (Map<String, Object>)results.get(accountId);
51 if((Boolean) record.get('success')){
52 Map<String, Object> data = (Map<String, Object>)record.get('data');
53 Map<String, Object> position = (Map<String, Object>) data.get('position');
54 acc.BillingLatitude = (Decimal) position.get('lat');
55 acc.BillingLongitude = (Decimal) position.get('lng');
56 if((Integer) data.get('score') < 50) {
57 // Low confidence in address match. Marking the accounts needed for review.
58 accountsWithBadData.add(acc);
59 }
60 }
61 else {
62 // Unable to match address provided.
63 accountsWithBadData.add(acc);
64 }
65 }
66 update accountList; // Update records with Latitude and Longitude.
67 reviewBadAccounts(accountsWithBadData); // Pushing accounts with bad data to another process to be handled.
68 }
69 else {
70 // Three primary types of failed requests.
71 String errorCode = (String) response.get('error_code');
72 if(errorCode == 'GC-0500'){
73 // Internal Server Error
74 // Retry the request at a later time and/or reach out to support.
75 return;
76 }
77 else if(errorCode == 'GC-0429'){
78 // Too many requests. Perform an exponential back off for the retries.
79 // Bad requests count against limits. Be sure to not waste calls on bad addresses and improperly created requests.
80 return;
81 }
82 else if(errorCode.startsWith('GC-1')){
83 System.debug(response);
84 // Improperly created requests. Fix errors before trying again.
85 return;
86 }
87 else {
88 // Fail safe catch for future error codes.
89 System.debug(response);
90 return;
91 }
92 }
93 }
94
95}