├── README.md └── src ├── classes ├── AddressAutocompleteController.cls ├── AddressAutocompleteController.cls-meta.xml ├── AddressAutocompleteControllerTest.cls └── AddressAutocompleteControllerTest.cls-meta.xml ├── components ├── AddressAutocomplete.component └── AddressAutocomplete.component-meta.xml ├── objects ├── Account.object ├── AddressAutocompleteGoogleKey__c.object ├── Contact.object └── Lead.object ├── package.xml ├── pages ├── AddressAutocompleteAccount.page ├── AddressAutocompleteAccount.page-meta.xml ├── AddressAutocompleteContact.page ├── AddressAutocompleteContact.page-meta.xml ├── AddressAutocompleteLead.page └── AddressAutocompleteLead.page-meta.xml └── staticresources ├── AddressAutocomplete.resource └── AddressAutocomplete.resource-meta.xml /README.md: -------------------------------------------------------------------------------- 1 | # Salesforce Address Autocomplete 2 | 3 | This package includes components to enable address autocomplete for objects in Salesforce using the Google Places API. 4 | 5 | This current package includes functionality for the following standard objects: 6 | - Account 7 | - Contact 8 | - Lead 9 | 10 | To add additional objects, simply copy the existing VisualForce pages, set the component parameters and create a Custom Button for the page. 11 | 12 | If looking to implement this package, be sure to read the Terms of Service for the Google Places API: 13 | https://developers.google.com/maps/terms 14 | 15 | And the usage limits: 16 | https://developers.google.com/places/webservice/usage 17 | 18 | ## Installation 19 | 20 | 1. Deploy this package to a Salesforce environment 21 | 22 | - [Deploy to Org](https://githubsfdeploy.herokuapp.com/app/githubdeploy/benedwards44/sf-address-autocomplete) 23 | - [Package Install for Production/Developer](https://login.salesforce.com/packaging/installPackage.apexp?p0=04tb00000001XtV) 24 | - [Package Install for Sandbox](https://test.salesforce.com/packaging/installPackage.apexp?p0=04tb00000001XtV) 25 | 26 | 2. Sign up for a Google Account and obtain your API key (https://code.google.com/apis/console), and enable the Google Maps JavaScript API v3. 27 | 3. Put your Google API key in the Address Autocomplete custom setting 28 | 4. Add Address Autocomplete buttons to page layouts as required 29 | 30 | ## Screenshots 31 | 32 | ![Screenshot](http://i.imgur.com/8j0AGas.png) 33 | 34 | ## Limits 35 | 36 | This application is bound by the Google Terms of Service, and its associated limits. These are also subject to change, so it's worth understanding this before implementing on any enterprise wide projects. Generally speaking, those Terms of Service that impact a Salesforce implementation are: 37 | - 1,000 address validations per day, or 150k per day for a paid service (ask Google for pricing) 38 | - You cannot use the free service if "Your site is only accessible within your company or on your intranet.". This is ultimately the deal-breaker for use within Salesforce. Contact Google to get pricing for the Google Maps for Work API. 39 | 40 | The most recent quote I had from Google (May '15) was £7,700 GDP / $11,000 USD per year for 500k queries. 41 | -------------------------------------------------------------------------------- /src/classes/AddressAutocompleteController.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Ben Edwards (Tquila) 3 | * Date: 12/05/2015 4 | * Description: Controller for the AddressValidation component 5 | * 6 | * ******************* Change Log ******************* 7 | * Modified by Change Date Change 8 | * Ben Edwards 12/05/2015 Initial creation. 9 | **/ 10 | public with sharing class AddressAutocompleteController { 11 | 12 | // Variables passed through from Component 13 | public Id recordId {get;set;} 14 | public String objName {get;set;} 15 | 16 | // Address one details 17 | public String streetOne {get;set;} 18 | public String cityOne {get;set;} 19 | public String stateOne {get;set;} 20 | public String postalcodeOne {get;set;} 21 | public String countryOne {get;set;} 22 | 23 | // Whether to include 2nd address 24 | public Boolean secondAddress {get;set;} 25 | 26 | // ADdress two details 27 | public String streetTwo {get;set;} 28 | public String cityTwo {get;set;} 29 | public String stateTwo {get;set;} 30 | public String postalcodeTwo {get;set;} 31 | public String countryTwo {get;set;} 32 | 33 | 34 | // CONSTRUCTOR 35 | public AddressAutocompleteController() {} 36 | 37 | // When save method is clicked from page 38 | public PageReference save() { 39 | 40 | try { 41 | // Save the sObject record 42 | update obj; 43 | 44 | // Return back to the standard record detail view 45 | return new PageReference('/' + obj.Id); 46 | } 47 | catch (Exception ex) { 48 | 49 | // Add error to page messages if none already exist. Some would exist if page validation fails, so no need to enter twice 50 | if (!ApexPages.hasMessages()) { 51 | 52 | ApexPages.addMessages(ex); 53 | } 54 | 55 | system.debug('### Error saving object: ' + ex); 56 | 57 | // Return null if an error exists - to display error on page. 58 | return null; 59 | } 60 | } 61 | 62 | // When Cancel method is clicked on page 63 | public PageReference cancel() { 64 | return new PageReference('/' + obj.Id); 65 | } 66 | 67 | // Object for the page 68 | public sObject obj { 69 | 70 | get { 71 | 72 | if (obj == null) { 73 | 74 | // Build query for address fields 75 | String objectQuery = 'Select Name,'; 76 | objectQuery += String.isNotBlank(streetOne) ? streetOne + ',' : ''; 77 | objectQuery += String.isNotBlank(cityOne) ? cityOne + ',' : ''; 78 | objectQuery += String.isNotBlank(stateOne) ? stateOne + ',' : ''; 79 | objectQuery += String.isNotBlank(postalcodeOne) ? postalcodeOne + ',' : ''; 80 | objectQuery += String.isNotBlank(countryOne) ? countryOne : ''; 81 | 82 | // If there is a 2nd address, add fields to query 83 | if (secondAddress != null && secondAddress) { 84 | 85 | objectQuery += ','; 86 | objectQuery += String.isNotBlank(streetTwo) ? streetTwo + ',' : ''; 87 | objectQuery += String.isNotBlank(cityTwo) ? cityTwo + ',' : ''; 88 | objectQuery += String.isNotBlank(stateTwo) ? stateTwo + ',' : ''; 89 | objectQuery += String.isNotBlank(postalCodeTwo) ? postalCodeTwo + ',' : ''; 90 | objectQuery += String.isNotBlank(countryTwo) ? countryTwo : ''; 91 | 92 | } 93 | 94 | // Add object and where clause 95 | objectQuery += ' From ' + objName + ' Where Id = \'' + recordId + '\''; 96 | 97 | // Execute query for record 98 | obj = database.query(objectQuery); 99 | } 100 | return obj; 101 | } 102 | set; 103 | } 104 | 105 | } -------------------------------------------------------------------------------- /src/classes/AddressAutocompleteController.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 32.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /src/classes/AddressAutocompleteControllerTest.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Ben Edwards (Tquila) 3 | * Date: 12/05/2015 4 | * Description: Test class for the AddressAutocompleteController 5 | * 6 | * ******************* Change Log ******************* 7 | * Modified by Change Date Change 8 | * Ben Edwards 12/05/2015 Initial creation. 9 | **/ 10 | @isTest 11 | public class AddressAutocompleteControllerTest { 12 | 13 | // Test ALL method for the controller 14 | // This test method is really only for test coverage. It's not really "unit testing" the logic 15 | // This is because the Google callout and validation is done from the VisualForce. Not worth re-implenmenting 16 | // in Apex just for testing purposes. 17 | static testMethod void addressAutocompleteControllerTest() { 18 | 19 | // Instantiate controller 20 | AddressAutocompleteController testCon = new AddressAutocompleteController(); 21 | 22 | // Create Account (this will need additional fields added if validation rules are in place) 23 | Account testAccount = new Account( 24 | Name = 'Test Account', 25 | Phone = 'Test Phone' 26 | ); 27 | insert testAccount; 28 | 29 | // Set variables (normally passed through from component) 30 | testCon.recordId = testAccount.Id; 31 | testCon.objName = 'Account'; 32 | 33 | // Set 1st address details 34 | testCon.streetOne = 'BillingStreet'; 35 | testCon.cityOne = 'BillingCity'; 36 | testCon.stateOne = 'BillingState'; 37 | testcon.postalcodeOne = 'BillingPostalCode'; 38 | testCon.countryOne = 'BillingCountry'; 39 | 40 | // Set Second Address to true. 41 | testCon.secondAddress = true; 42 | 43 | // Set 2nd address details 44 | testCon.streetTwo = 'ShippingStreet'; 45 | testCon.cityTwo = 'ShippingCity'; 46 | testCon.stateTwo = 'ShippingState'; 47 | testcon.postalcodeTwo = 'ShippingPostalCode'; 48 | testCon.countryTwo = 'ShippingCountry'; 49 | 50 | // Assert obj is returned 51 | system.assertEquals( 52 | testAccount.Id, 53 | testCon.obj.get('id'), 54 | 'The object Id in the controller should match the created Account Id.' 55 | ); 56 | 57 | // Test methods 58 | testCon.cancel(); 59 | testCon.save(); 60 | 61 | } 62 | 63 | } -------------------------------------------------------------------------------- /src/classes/AddressAutocompleteControllerTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 32.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /src/components/AddressAutocomplete.component: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 190 | 191 | -------------------------------------------------------------------------------- /src/components/AddressAutocomplete.component-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 32.0 4 | Address autocomplete component for populating addresses for objects in Salesforce. Uses the Google Places API to auto-complete. 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/objects/Account.object: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Address_Autocomplete 5 | online 6 | button 7 | page 8 | Address Autocomplete 9 | replace 10 | AddressAutocompleteAccount 11 | false 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/objects/AddressAutocompleteGoogleKey__c.object: -------------------------------------------------------------------------------- 1 | 2 | 3 | Hierarchy 4 | Protected 5 | Your Google API Key, used to authenticate with Google server. 6 | false 7 | 8 | Key__c 9 | The Google API key. Can be obtained from: 10 | https://console.developers.google.com/ 11 | false 12 | 13 | 255 14 | true 15 | false 16 | Text 17 | false 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/objects/Contact.object: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Address_Autocomplete 5 | online 6 | button 7 | page 8 | Address Autocomplete 9 | replace 10 | AddressAutocompleteContact 11 | false 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/objects/Lead.object: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Address_Autocomplete 5 | online 6 | button 7 | page 8 | Address Autocomplete 9 | replace 10 | AddressAutocompleteLead 11 | false 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | AddressAutocompleteController 5 | AddressAutocompleteControllerTest 6 | ApexClass 7 | 8 | 9 | AddressAutocomplete 10 | ApexComponent 11 | 12 | 13 | AddressAutocompleteAccount 14 | AddressAutocompleteContact 15 | AddressAutocompleteLead 16 | ApexPage 17 | 18 | 19 | AddressAutocompleteGoogleKey__c 20 | CustomObject 21 | 22 | 23 | AddressAutocomplete 24 | StaticResource 25 | 26 | 27 | Account.Address_Autocomplete 28 | Contact.Address_Autocomplete 29 | Lead.Address_Autocomplete 30 | WebLink 31 | 32 | 32.0 33 | 34 | -------------------------------------------------------------------------------- /src/pages/AddressAutocompleteAccount.page: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | -------------------------------------------------------------------------------- /src/pages/AddressAutocompleteAccount.page-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 32.0 4 | false 5 | false 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/pages/AddressAutocompleteContact.page: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | -------------------------------------------------------------------------------- /src/pages/AddressAutocompleteContact.page-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 32.0 4 | false 5 | false 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/pages/AddressAutocompleteLead.page: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 13 | -------------------------------------------------------------------------------- /src/pages/AddressAutocompleteLead.page-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 32.0 4 | false 5 | false 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/staticresources/AddressAutocomplete.resource: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benedwards44/sf-address-autocomplete/4efebb8dfb38f8007cd47e243c646c0caff98537/src/staticresources/AddressAutocomplete.resource -------------------------------------------------------------------------------- /src/staticresources/AddressAutocomplete.resource-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Public 4 | application/zip 5 | 6 | --------------------------------------------------------------------------------