If your company is already using Salesforce for Case Management, you probably want to set up a synchronization from Salesforce to CustomerGauge. That way, your Salesforce users can continue working in their system, while your CustomerGauge users will not be left out.


You can achieve this by setting up an APEX class and trigger, that will call CustomerGauge's PUT Close the Loop API, to post notes or status changes.


Disclaimer: This is a highly technical solution. Use only if you're well versed in Salesforce APEX classes and triggers.


Requirements


Before you start: Whitelist the CustomerGauge API Suite in Salesforce

In order to call our APIs from Salesforce, you will first need to let Salesforce know you trust us.

To do this, you'll need to whitelist our API Suite;

  1. Go to Setup → Remote Site Settings
  2. Check if "https://api.eu.customergauge.com" (change "eu" to your region) is already whitelisted
  3. Check if "https://auth.eu.customergauge.com" (change "eu" to your region) is already whitelisted
  4. If it doesn't exist yet, hit the "New Remote Site" button
    1. Remote Site Name: give a descriptive name for future reference
    2. Remote Site URL: add in the API domain applicable to your region
      1. https://api.eu.customergauge.com and https://auth.eu.customergauge.com for EU
      2. https://api.us.customergauge.com and https://auth.us.customergauge.com for US
      3. https://api.au.customergauge.com and https://auth.au.customergauge.com for AU
    3. Active: Make sure the checkbox is in an enabled state


Overview of APEX classes

  • SyncCaseWorkflowCG: the Apex Trigger that will initiate the API request
  • CGWorkflowAPI: the engine that calls the POST Workflow API
  • testSyncWorkflowCG: the Test class used to test the code after changes are made
  • MockHttpResponseGenerator: A helper class for unit testing that mocks the API requests
  • stoprecursion: A helper class that prevents recursion


Building the Main Class

  1. In Salesforce → Setup, go to the "Apex Classes" page
  2. Hit the "New" button
  3. Name the class "CGWorkflowAPI"
  4. Add the following code
  5. global class CGWorkflowAPI {
    
        private static String clientID = 'XXXXXXXX'; 
        private static String clientSecret = 'XXXXXXXXXX'; 
        public static String generatedToken {set; get;}
        public static String errorMessage {set; get;}
    
        public static void authenticate() {
            
            try{
                
                String url = 'https://auth.eu.customergauge.com/oauth2/token';
    
                String idSecret = clientID + ':'+ clientSecret;  
                String authorization = EncodingUtil.base64Encode(Blob.valueof(idSecret));
                String body = 'client_id=' + clientID + '&grant_type=client_credentials' + '&client_secret=' + clientSecret;
                
                
                
                HttpRequest objReq = new HttpRequest();
                objReq.setEndpoint(url);
                objReq.setMethod('POST');
                String authHeadParam = 'Basic ' + authorization;
                objReq.setHeader('Authorization', authHeadParam);
                objReq.setHeader('Content-Type', 'application/x-www-form-urlencoded');
    
                objReq.setBody(body);
                Http objHttp = new Http();
                HTTPResponse objRes = objHttp.send(objReq);
    
                JSONParser objParse = JSON.createParser(objRes.getBody());
    
                while (objParse.nextToken() != null) 
                {
                    
                    if (objParse.getCurrentToken() == JSONToken.FIELD_NAME && objParse.getText() == 'access_token')
                    {
                        objParse.nextToken();
                        generatedToken = objParse.getText();
                        System.debug(generatedToken);
                    }
                }
             }
             catch(Exception ex)
             {  errorMessage = ex.getMessage();
                System.debug('Exception :' + ex.getMessage());
             }
        }
    
        @future (callout=true)
        WebService static void syncCase(String CGID, String workflowStatus, String workflowNote, String workflowDate){
            
            // do authentication first to get the token
            authenticate();
    
            
            
            // Map Workflow Statuses to CG equivalents
            String wfStatus = workflowStatus;
            if( wfStatus == 'Closed' ) { wfStatus = 'closed'; }
            else if( wfStatus == 'Open' || wfStatus == 'New' ) { wfStatus = 'open'; }
            else { wfStatus = 'progress'; }
            
            
            
            String body = 'number_customergauge=' + CGID + '&status=' + wfStatus + '&note=' + workflowNote + '&happened_at=' + workflowDate;
    
            
            //Construct HTTP request and response
            HttpRequest req = new HttpRequest();
            HttpResponse res = new HttpResponse();
            Http http = new Http();
     
            req.setHeader('Content-Type','application/x-www-form-urlencoded');
            req.setHeader('Authorization', 'Bearer ' + generatedToken);
    
    
            //Construct Endpoint
            String endpoint = 'https://api.eu.customergauge.com/v7/rest/close-loop/status';
            
            
            //Set Method and Endpoint and Body
            req.setMethod('PUT');
            req.setEndpoint(endpoint);
    
            req.setBody(body);
    
    
            try {
                //Send endpoint to CG
                res = http.send(req);
                System.debug('Success' + res.getBody());
            } catch(System.CalloutException e) {
                System.debug('failed' + res.toString() + ' - details ' + e);
            }        
            
            
        }
        
    }


  6. Make a few changes to the above code to make it applicable to your CG system
    1. Change the API Key value to your API Key
    2. Change the region to your region ("eu", "us", or "au)
    3. Add additional If/Else statements for each Case Status available in your Salesforce system, mapping them to "OPEN", "PROGRESS", or "CLOSED"
  7. Make sure to Save (File > Save)


Setting up the Trigger

  1. In Salesforce → Setup, go to the "APEX Triggers" page
  2. Hit the Developer Console button
  3. Go to File > New > Apex Trigger
    1. Give it the name "SyncCaseWorkflowCG"
    2. Select the sObject "Case"
  4. Add the following code;

    trigger SyncCaseWorkflowCG on Case (after insert, after update) {
        
        List<Case> case2Update = new List<Case>();
        
        // SOQL Query to get applicable fields
        for(Case[] cases : [SELECT Id, CG_ID__c, Status, Owner.Email, Description, (SELECT Id, ParentId, CommentBody, LastModifiedDate FROM CaseComments ORDER BY LastModifiedDate DESC LIMIT 1) FROM Case WHERE id IN :Trigger.New LIMIT 1 ]){
            
            for(Integer i=0 ; i<cases.size() ; i++){
                
                String CaseId = String.valueof(cases[i].id);
                String CaseIdCG = String.valueof( cases[i].CG_ID__c );
                String wfComment = String.valueof( cases[i].Description );
                String CaseStatus = cases[i].Status;
                String CaseOwnerEmail = cases[i].Owner.Email;
               
                DateTime dt = DateTime.now();
                String happened_at = dt.format('yyyy-MM-dd hh:mm:ss');
                
                //for(CaseComment comm : cases[i].CaseComments) {
                  //  wfComment = comm.CommentBody;
                //}
                
          CGWorkflowAPI.syncCase( CaseIdCG, CaseStatus, wfComment, happened_at );
            }
            
         }
        
    }


  5. Make adjustments to the SOQL Query where applicable.

  6. Make sure to Save (File > Save)


Writing the Test Code

Mock Class

  1. In the Developer Console, go to File > New > Apex Class
  2. Name it "MockHttpResponseGenerator"
  3. Add the following code;

    @isTest
    global class MockHttpResponseGenerator implements HttpCalloutMock {
        // Implement this interface method
        global HTTPResponse respond(HTTPRequest req) {
            // Optionally, only send a mock response for a specific endpoint
            // and method.
            //System.assertEquals('http://api.salesforce.com/foo/bar', req.getEndpoint());
            //System.assertEquals('GET', req.getMethod());
            
            // Create a fake response
            HttpResponse res = new HttpResponse();
            res.setHeader('Content-Type', 'application/json');
            
            res.setStatusCode(200);
            return res;
        }
    }


  4. Make sure to Save (File > Save)

Recursion Class

  1. In the Developer Console, go to File > New > Apex Class
  2. Name it "stoprecursion"
  3. Add the following code;

    public class stoprecursion{
    public static boolean flag=true;
    public static boolean runonce(){
    if(flag){
       flag=false;
      }
    else {
       return flag;
      }
       return true;
     }
    }


  4. Make sure to Save (File > Save)


Test Class

  1. In the Developer Console, go to File > New > Apex Class
  2. Name it "testSyncWorkflowCG"
  3. Add the following code;

    @isTest(seeAllData=true)
    public class testSyncWorkflowCG {
        static testMethod void testCaseAPI() {
            
            if(stoprecursion.runonce()){
                Test.setMock(HttpCalloutMock.class, new MockHttpResponseGenerator());
            
                Case c = new Case(CG_ID__c='1',Status='Completed',Description='Test',OwnerId = '005f4K3us3RId' );
                test.startTest();
                insert c;
                test.stopTest();
            }
            
        }
    }
    
    
    
    
    
    
    
    
    
    
    
    


  4. Replace the value of OwnerId to any existing Salesforce user in your Salesforce system.

  5. Make sure to Save (File > Save)


Running Test Code

  1. When in testSyncWorkflowCG, hit the "Run Test" button at the top-right of the screen
  2. If all is OK, you should have more than 70% Code Coverage


Finishing

That's it! You should now have an automatic Workflow synchronisation from Salesforce to your CustomerGauge system.

You may need to publish your APEX classes when this is built in a Sandbox environment.