Tuesday 18 June 2019

Salesforce to Salesforce Integration

The Salesforce to Salesforce integration is very powerful to share the data's among the orgs.

In this post, we are using OAuth authorization type and connected app to connect the two different salesforce organizations. In this process, we are connecting two different developer orgs. If you are looking to connect sandboxes, you can replace the endpoint URL with the test.salesforce.com instead of login.salesforce.com.

Use Case: Fetch and display the contacts for the Account from another salesforce org.
Detailed Requirement: In an Org A, place a button on the Account detail page, when the user clicks on the button, retrieve and display the contacts available for the same account from another salesforce org B. It should look for the same Account Name to retrieve the contacts.

Step 1: Create a connected app in destination org(Salesforce org B from where you want to fetch data).


In the callback URL, replace the ap15 with your salesforce org instance.

Once saved, the Client Id and Client Secret will be generated. Copy these informations for later purpose.

Step 2: Create a @RestResource class to expose the data


@RestResource(urlMapping='/displayContacts/*')
global class ExposeContactsForAccountName {

    @HTTPGET
    global static List<Contact>  exposeContacts(){
        List<Contact> conList = new List<Contact>();
        
        RestRequest reqRequest = RestContext.request;
        RestResponse resResponse = RestContext.response;
        
        //Get the Account Name from the URL
        //urlDecode to remove get the exact Account Name from the URL
        string getAccName =  EncodingUtil.urlDecode(reqRequest.requestURI.substringAfterLast('/'), 'UTF-8');
        
        //Query the Contacts for the Account name and return the list
        conList = [Select id, Name, FirstName, LastName, Email, Phone from Contact where Account.Name =: getAccName];
        return conList;
    }
}

Step 3: Create a custom button in the source org (Salesforce org A where you want to display the contacts).


Once created, place this button on the page layout.



Step 4: In the source org(Salesforce org A where you want to display the contacts on button click), create custom settings to store the callout parameters like endpoint URL, Username, Password, Client Id, Client Secret and any other hardcode values.

Create "Hierarchy" type custom settings and necessary fields.

Once completed, click on Manage to store the values.

End Point URL: https://login.salesforce.com/services/oauth2/token  (it should be 'https://test.salesforce.com/services/oauth2/token' in case of sandbox)
Username: The destination org (Org B) username
Password: The destination org (Org B) password
Client Id: Paste the client id of the connected app (Org B)
Client Secret: Paste the client secret of the connected app (Org B)

Step 5: Create a visulaforce page in the source org (Org A). Give name as "DisplayContactsFromConnected" and past the below code.

<apex:page extensions="DisplayContactsFromConnectedOrgCont" sidebar="false" showHeader="false" standardController="Account">
    <apex:slds >
        <apex:form >
            <apex:pageMessages ></apex:pageMessages>
            <apex:pageBlock >
                <apex:pageBlockButtons
location="top" >
                    <div
style="float:right;">
                        <apex:commandButton
value="Create Contacts" title="Create Contacts" oncomplete="self.close();" action="{!insertSelectedContacts}"/>
                        <apex:commandButton
value="Cancel" title="Cancel" onclick="self.close();" />
                    </div>
                </apex:pageBlockButtons>
             
                <apex:pageBlockTable
value="{!conWrapper}" var="con">
                    <apex:column
headerValue="Select">
                        <center><apex:inputCheckbox
value="{!con.selectToInsert}"  /></center>
                    </apex:column>
                    <apex:column
headerValue="First Namevalue="{!con.FirstName}"/>
                    <apex:column 
headerValue="Last Namevalue="{!con.LastName}"/>
                    <apex:column 
headerValue="Emailvalue="{!con.Email}"/>
                    <apex:column 
headerValue="Phone Numbervalue="{!con.Phone}"/>
                </apex:pageBlockTable>
             
            </apex:pageBlock>
        </apex:form>
    </apex:slds>
</apex:page>


Step 6: Create an apex class "DisplayContactsFromConnectedOrgCont".

This class will get the current page id and retrieve the account name. Once account name received, do the callout to destination salesforce org and fetch the contacts list.

public with sharing class DisplayContactsFromConnectedOrgCont {

    Public ID accountID {get;set;} //to store the account id
    Public Account acc {get;set;} //to store the account details
    Public ApexPages.StandardController accountController;
    public string endPointURL; //to store the endpointurl
    public string clientID; //to store the client id
    public string clientSecretKey; //to store the client secret key
    public string userName; //to store the username
    public string password; //to store the password
    public string access_token; //to store the access token
    public List<contactsWrapper> conWrapper {get;set;} //wrapper class list
 
    public DisplayContactsFromConnectedOrgCont(ApexPages.StandardController controller){
     
        //save the values from custom settings
        endPointURL = SFToSF__c.getInstance().End_Point_URL__c;
        clientID = SFToSF__c.getInstance().Client_Id__c;
        clientSecretKey = SFToSF__c.getInstance().Client_Secret__c;
        userName = SFToSF__c.getInstance().Username__c;
        password = SFToSF__c.getInstance().Password__c;
     
     
        accountID = ApexPages.currentPage().getParameters().get('id'); //store the current page id (Account id)
        this.acc = (Account)controller.getRecord();
        this.accountController = controller;
        conWrapper = new List<contactsWrapper>(); //initialize the wrapper class list
        Account accRec = [Select id, Name from Account where ID =: accountID]; //Query to get the Account Nae
        //do the callout and fetch the contacts from another org and load into the wrapper class list to display
        fetchContacts(accRec.Name);
    }
 
    public void fetchContacts(string AccountName){
        //Login into the destination salesforce org
        Login();
        //Once access token is recieved, call the rest api and fetch the contact details
        if(access_token != null){
            Http ht = new Http();
            HttpRequest httpReq = new HttpRequest();
            //urlEncode the Account name to send in url format. For ex: If Account Name is "Test Account", it should send as "Test+Account"
            httpReq.setEndpoint('https://ap15.salesforce.com/services/apexrest/displayContacts/'+EncodingUtil.urlEncode(AccountName, 'UTF-8'));
            httpReq.setMethod('GET');
            httpReq.setHeader('Authorization', 'Bearer '+access_token);
            httpReq.setHeader('Content-Type', 'application/json');
            httpReq.setHeader('Accept', 'application/json');
            HttpResponse httpRes = ht.send(httpReq);
            //If callout is success, then deserialize the recieved JSON data with the Wrapper Class variables
            if(httpRes.getStatusCode() == 200){
                conWrapper = (List<contactsWrapper>)JSON.deserialize(httpRes.getBody(), List<contactsWrapper>.class);
            }
        }
    }
 
    //Login and get the access token
    public void Login(){
     
        string reqBody = 'grant_type=password&client_id='+clientID+'&client_secret='+clientSecretKey+'&username='+username+'&password='+password;
        Http ht = new Http();
        HttpRequest httpReq = new HttpRequest();
        httpReq.setEndpoint(endPointURL);
        httpReq.setMethod('POST');
        httpReq.setBody(reqBody);
        HttpResponse httpRes = ht.send(httpReq);
     
        if(httpRes.getStatusCode() == 200){
            string responseBody = httpRes.getBody();
            LoginWrapper logWrap = (LoginWrapper)JSON.deserialize(responseBody, LoginWrapper.class);
            access_token = logWrap.access_token;
        }
    }
    //Insert the selected contacts into the source org under the Same Account
    Public void insertSelectedContacts(){
       List<Contact> conList = new List<Contact>();
        for(contactsWrapper cow : conWrapper){
            if(cow.selectToInsert == true){
                Contact con = new Contact();
                con.FirstName = cow.FirstName;
                con.LastName = cow.LastName;
                con.Email = cow.Email;
                con.Phone = cow.Phone;
                con.Description = 'Added from another salesforce org';
                con.AccountId = accountID;
                conList.add(con);
            }
        }
        if(!conlist.isEmpty()){
            insert conlist;
        }
    }
 
    //Wrapper class to store the access token
    Public class LoginWrapper{
        public string access_token;
    }
    //Wrapper class to store the contacts informations
    Public class contactsWrapper{
        Public boolean selectToInsert {get;set;}
        Public string FirstName {get;set;}
        Public string LastName {get;set;}
        Public string Email {get;set;}
        public string Phone {get;set;}
    }
}


We are done!. Now, go to any Account detail page and click on Display Contacts from Connected Org.



One more feature!. Select the contacts and click on Create Contacts button to insert the selected contacts under this account 💪

Comments are welcome 😉