April 11, 2021

How to prompt agents to link existing Contacts to the Voice Call in Salesforce Service Cloud Voice

 1. Go to Channel-Object Linking in Setup.

2. Click New Linking Rule. Select Phone under Phone tab.


3. Set the linking logic. In my case, I have set Prompt Agent so that Agent can link it.


4. Test it out. Agent should click Review and Link. 

 
Output:
 

April 9, 2021

Salesforce Identity connect

Identity Connect integrates Microsoft Active Directory (AD) user accounts with Salesforce user records. When a user account is created or updated in AD, Identity Connect pushes those updates to the Salesforce user record seamlessly and instantaneously. For example, when a user is created in AD, the Salesforce user record is created as part of the provisioning process. When de-provisioned, the user’s Salesforce session is revoked immediately. You can also use Identity Connect for single sign-on to Salesforce.
 
 
To download, go to Identity Connect in Setup.
 
 
1. It helps to keep users in Sync between your AD and Salesforce. No need to manually deactivate the users.
2. When a new user is added, we can configure Profile and Permission Sets.

April 8, 2021

Salesforce Standard Einstein Activity Capture

Sign up for a Developer Edition Org - https://developer.salesforce.com/
 
1. Go to Permission Set in Salesforce Setup.

2. Check for "Standard Einstein Activity Capture" Permission Set.

3. Select the "Standard Einstein Activity Capture" Permission Set and click Manage Assignment.


4. Click "Add Assignments" and add yourself to it.

5. Now go to Settings under Einstein Activity Capture.


6. Click "Get Started" to enable. Complete all the Steps.

7. Now go to Home page. Click "To start using it, connect your email and calendar to Salesforce".


8. Complete all the information and get connected.

Outlook Configuration:
 


Open link as sub tab in Salesforce Lightning Console

April 7, 2021

Date and DateTime Formating in Salesforce Visualforce

Visualforce Page:
<apex:page controller="Sample">
    <apex:pageBlock >
        <apex:pageBlockTable value="{!listAcc}" var="acc">
            <apex:column value="{!acc.Name}"/>
            <apex:column value="{!acc.Industry}"/>
            <apex:column headerValue="Created Date Time">
                <apex:outputText value="{0,date,MM'/'dd'/'yyyy HH:mm}" >        
                    <apex:param value="{!acc.CreatedDate}"/>        
                </apex:outputText>
            </apex:column>
            <apex:column headerValue="Created Date Only">
                <apex:outputText value="{0,date,MM'/'dd'/'yyyy}" >        
                    <apex:param value="{!acc.CreatedDate}"/>        
                </apex:outputText>
            </apex:column>
        </apex:pageBlockTable>
    </apex:pageBlock>
</apex:page>

Apex Class:
public class Sample {      

    public List < Account > listAcc { get; set; }
 
    public Sample() {
    
        listAcc = [ SELECT Id, Name, Industry, CreatedDate FROM Account Limit 10 ];
    
    }   
       
}


Output:


aura:if expression check inside aura:iteration in Salefsorce

 Apex Class:
public class AccountListController {
 
    @AuraEnabled
    public static List < Account > fetchAccts() {
        return [ SELECT Id, Name, Industry, Number_1__c, Number_2__c FROM Account LIMIT 10 ];
    }
    
}

Aura Component:
<aura:component implements="force:appHostable"  controller="AccountListController">
    
    <aura:attribute type="Account[]" name="acctList"/>    
    
    <aura:handler name="init" value="{!this}" action="{!c.fetchAccounts}"/>
    
    <table class="slds-table slds-table_bordered slds-table_cell-buffer">
        <thead>
            <tr class="slds-text-title_caps">
                <th scope="col">
                    <div class="slds-truncate" title="Account Name">Account Name</div>
                </th>
                <th scope="col">
                    <div class="slds-truncate" title="Industry">Industry</div>
                </th>
                <th scope="col">
                    <div class="slds-truncate" title="Number 1">Number 1</div>
                </th>
                <th scope="col">
                    <div class="slds-truncate" title="Number 2">Number 2</div>
                </th>
                <th scope="col">
                    <div class="slds-truncate" title="Number Check">Number Check</div>
                </th>
            </tr>
        </thead>
        <tbody>
            <aura:iteration items="{!v.acctList}" var="a">
                <tr>
                    <td data-label="Account Name">
                        <div class="slds-truncate" title="">{!a.Name}</div>
                    </td>
                    <td data-label="Industry">
                        <div class="slds-truncate" title="">{!a.Industry}</div>
                    </td>
                    <td data-label="Number 1">
                        <div class="slds-truncate" title="">{!a.Number_1__c}</div>
                    </td>
                    <td data-label="Number 2">
                        <div class="slds-truncate" title="">{!a.Number_2__c}</div>
                    </td>
                    <td data-label="Number Check">
                        <div class="slds-truncate" title="">
                            <!-- Expressions for number check -->
                            <aura:if isTrue="{!a.Number_1__c == a.Number_2__c}">
                                Same Numbers
                                <aura:set attribute="else">
                                    Not Same Numbers
                                </aura:set>
                            </aura:if>
                        </div>
                    </td>
                </tr>
            </aura:iteration>
        </tbody>
    </table>
</aura:component>

Aura JavaScript:

({
    fetchAccounts : function(component, event, helper) {
        var action = component.get("c.fetchAccts");
        action.setParams({
        });
        action.setCallback(this, function(response){
            var state = response.getState();
            if (state === "SUCCESS") {
                component.set("v.acctList", response.getReturnValue());
            }
        });
        $A.enqueueAction(action);
    }
})


Output:


Event Attendees in Salesforce Lightning

1. Add Attendees field in the Event Page layout.


2. Create a New Event to test it.


April 6, 2021

How to query all the Visualforce Pages the profile have access to in Salesforce?

1. Run the below SOQL to get the PermissionSet Id.
SELECT Id, Profile.Name FROM PermissionSet WHERE Profile.Name = 'System Administrator'

2. Use the PermissionSet Id from the step 1 and use it in the below SOQL for ParentId.
SELECT Name FROM ApexPage WHERE Id IN ( SELECT SetupEntityId FROM SetupEntityAccess WHERE ParentId = '0PS4x000003oZ9DGAU' AND SetupEntityType = 'ApexPage' )

 


How to query all the Apex Classes the profile have access to in Salesforce?

1. Run the below SOQL to get the PermissionSet Id.
SELECT Id, Profile.Name FROM PermissionSet WHERE Profile.Name = 'System Administrator'

2. Use the PermissionSet Id from the step 1 and use it in the below SOQL for ParentId.
SELECT Name FROM ApexClass WHERE Id IN ( SELECT SetupEntityId FROM SetupEntityAccess WHERE ParentId = '0PS4x000003oZ9DGAU' AND SetupEntityType = 'ApexClass' )
 

April 5, 2021

Salesforce Email Drafts

Draft emails let support agents who use the case feed write and save messages without having to send them immediately. 
 
 
1.   Enable "Email-to-Case" in Salesforce Setup.


2. Enable Email Drafts in Support Settings.


Output:
 
SOQL to query:
SELECT Id, Subject, TextBody FROM EmailMessage WHERE Status = '5'

All subscriptions used - To subscribe to this report, first unsubscribe from another one


Maximum number of reports or dashboards a User can subscribe to is 5.
 

Difference between ConnectApi.ChatterFeeds.FeedElement and FeedItem

FeedItem 
FeedItem represents an entry in the feed, such as changes in a record feed, including text posts, link posts, and content posts. This object is available in API version 21.0 and later. This object replaces FeedPost.
 
ConnectApi.FeedElement:
In API version 31.0, the definition of a feed expanded to include new objects that didn’t entirely fit the feed item model. The Chatter feed became a container of feed elements. The abstract class ConnectApi.FeedElement was introduced as a parent class to the existing ConnectApi.FeedItem class. The subset of properties that feed elements share was moved into the ConnectApi.FeedElement class. Because feeds and feed elements are the core of Chatter, understanding them is crucial to developing applications with Connect in Apex. 

April 2, 2021

How to get Topics created by me in Salesforce?

SOQL:
SELECT Id, Name, CreatedById FROM Topic WHERE CreatedById = '0054x000003WYaSAAW'


April 1, 2021

How to avoid transferring Messaging Session to an Agent when an exception occurs in Salesforce Einstein Bot?

1. Configure Error Handler Dialog.


2. Instead of Transfer to Agent use Show a Menu with Options. Add some user friendly message to the user.

Output:
 

March 31, 2021

Popover Dialog using Aura Lightning Component

Primary component:
<aura:component implements="force:appHostable" >
    <aura:attribute name="showBool" type="boolean" default="false"/>
    <lightning:card>
        <a onmouseover="{!c.show}">View</a><br/>
        <aura:if isTrue="{!v.showBool}">
            <section aria-describedby="dialog-body-id-98" aria-labelledby="dialog-heading-id-103" class="slds-popover slds-popover_pane slds-nubbin_top-left" role="dialog">
                <lightning:button class="slds-button slds-button_icon slds-button_icon-small slds-float_right slds-popover__close" title="Close dialog" onclick="{!c.hide}">
                    Close
                </lightning:button>
                <header class="slds-popover__header">
                    <h2 class="slds-text-heading_small" id="dialog-heading-id-103">Header Title</h2>
                </header>
                <div class="slds-popover__body slds-popover__body_small" id="dialog-body-id-98">
                    <c:contentComponent/>
                </div>
                <footer class="slds-popover__footer">
                    <p>Footer Item</p>
                </footer>
            </section>
        </aura:if>
    </lightning:card>
</aura:component>

Primary Component Controller:
({
    
show : function( component, event, helper ) {
        
        component.set( "v.showBool", true );
}, 
    
    hide : function( component, event, helper ) {
        component.set( "v.showBool", false );
}
    
})

contentComponent:
<aura:component >
    <lightning:card>
        <aura:set attribute="title">
            <lightning:icon iconName="standard:knowledge" size="small"/>
            Sample Title
        </aura:set>
        <div class="slds-text-longform">
            <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
            <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
            <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
            <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
            <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
        </div>
    </lightning:card>
</aura:component>

Output:


How to create Messaging End User using Apex in Salesforce?

Sample Code:

MessagingEndUser objMsgUser = new MessagingEndUser();
objMsgUser.ContactId = '<ContactId>';
objMsgUser.MessagingChannelId = '<Messaging Channel Id>';
objMsgUser.MessagingConsentStatus = 'ImplicitlyOptedIn';
objMsgUser.MessageType = 'Text';//For SMS Channel
objMsgUser.MessagingPlatformKey = '<Platform Key>';//Go to Messaging Settings to view
objMsgUser.Name = '<Name>';
insert objMsgUser;

How to add Knowledge widget in Salesforce Lightning Console?

1. In the Lightning Record Page, use the Knowledge component.


2. When you open a Case record, it will display the relevant Articles.

3. Attach Article can be use to attach the Article to the Case.

4. Once the Articles are attached, it will be available in Articles related list to the Case record.


March 30, 2021

How to create External object and relate it to Salesforce Object using Heroku?

1. Create a Heroku App.

2. Go to Resource Tab. Install Heroku Connect and Heroku Postgres add-ons.

3. Create a table in Heroku Postgres. Make sure to create a column to relate it to Salesforce object. In my example, I have used Account_Number column.

4. Create some data in Heroku Postgres table.

5. In Heroku Connect, go to External Objects tab. Select the table created in Step 3 under Data Sources.

6. Click Show Credentials to get the username and password.

7. Create External Data Source in Salesforce.


8. Click Validate and Sync.

9. Select the table so that it creates External object in Salesforce.

10. Create an External Id field in the object which is going to be the parent. In my Case, I have used Account object as parent Account Number field as External Id field.


11. Update the external object. Don't update API Name and Table Name.


12. Make the Account Number column as Indirect Lookup field to Account object. Don't update API Name and External Column Name.


13. Update the labels of the other fields. Don't update the API Names.


Sample Records:



Using FindOrCreate from Salesforce Chat to link Account to Chat Transcript

Sample Code:
/* Custom detail is to show it to the agent before accepting the Chat and for findOrCreate */
liveagent.addCustomDetail( "Company", "Disney" );
liveagent.addCustomDetail( "First Name", "Mickey" );
liveagent.addCustomDetail( "Last Name", "Mouse" );
liveagent.addCustomDetail( "Email", "mickey.mouse@test.com" );
liveagent.addCustomDetail( "Case Subject", "Test" );
liveagent.addCustomDetail( "Case Status", "New" );

/* FindOrCreate Account and linking to Chat Transcript */
liveagent.findOrCreate( "Account" ).map( "Name", "Company", true, true, true ).saveToTranscript( "AccountId" ).showOnCreate();
 
/*
    This does a non-exact search on cases by the value of the "Case Subject" custom detail.
    If no results are found, it will create a case and set the case's subject and status
    The case that's found or created will be associated to the chat and the case will open in
    the Console for the agent when the chat is accepted
*/
liveagent.findOrCreate( "Case" ).map( "Subject", "Case Subject", true, false, true ).map( "Status", "Case Status", false, false, true ).saveToTranscript( "CaseId" ).showOnCreate();
 
/*
    This searches for a contact whose first name, last name ane email exactly match the values in the custom details for First Name, Last Name and Email.
    If no results are found, it will create a new contact and set it's first name, last name, and Email to the values in the custom details
    
*/
liveagent.findOrCreate( "Contact" ).map( "FirstName", "First Name", true, true, true ).map( "LastName", "Last Name", true, true, true ).map( "Email", "Email", true, true, true );
 
/* The contact that's found or created will be saved or associated to the chat transcript.
The contact will be opened for the agent in the Console and the case is linked to the contact record */
liveagent.findOrCreate( "Contact" ).saveToTranscript( "ContactId" ).showOnCreate().linkToEntity( "Case", "ContactId" );

 
Output:


Using FindOrCreate from Salesforce Chat

Sample code:
        /* Custom detail is to show it to the agent before accepting the Chat and for findOrCreate */
        liveagent.addCustomDetail( "First Name", "Mickey" );
        liveagent.addCustomDetail( "Last Name", "Mouse" );
        liveagent.addCustomDetail( "Email", "mickey.mouse@test.com" );
        liveagent.addCustomDetail( "Case Subject", "Test" );
        liveagent.addCustomDetail( "Case Status", "New" );
         
        /*
            This does a non-exact search on cases by the value of the "Case Subject" custom detail.
            If no results are found, it will create a case and set the case's subject and status
            The case that's found or created will be associated to the chat and the case will open in
            the Console for the agent when the chat is accepted
        */
        liveagent.findOrCreate( "Case" ).map( "Subject", "Case Subject", true, false, true ).map( "Status", "Case Status", false, false, true ).saveToTranscript( "CaseId" ).showOnCreate();
         
        /*
            This searches for a contact whose first name, last name ane email exactly match the values in the custom details for First Name, Last Name and Email.
            If no results are found, it will create a new contact and set it's first name, last name, and Email to the values in the custom details
           
        */
        liveagent.findOrCreate( "Contact" ).map( "FirstName", "First Name", true, true, true ).map( "LastName", "Last Name", true, true, true ).map( "Email", "Email", true, true, true );
         
        /* The contact that's found or created will be saved or associated to the chat transcript.
        The contact will be opened for the agent in the Console and the case is linked to the contact record */
        liveagent.findOrCreate( "Contact" ).saveToTranscript( "ContactId" ).showOnCreate().linkToEntity( "Case", "ContactId" );
 
Code should be placed inside the Chat Button Code:
 

Output:



March 29, 2021

Agent Avatar in Salesforce Embedded Service Chat

Agent Avatar image in Static Resource:
Store the Avatar image in Salesforce Static Resource.
 
 
Sample Code Change:
embedded_svc.settings.avatarImgURL = '<URL of the Avatar Image>';
 
Output with Agent Avatar:
 

How to show Queue Position in Salesforce Chat?

Visualforce components can be used to customize the appearance and behavior of chat windows. Check the below example

Visualforce Page:
<apex:page showHeader="false">
    <style>
        body { overflow: hidden; width: 100%; height: 100%; padding: 0; margin: 0 }
        #waitingMessage {
            height: 50%;
            width: 50%;
            vertical-align: middle;
            text-align: center;
            display: none;
        }
        #liveAgentClientChat.liveAgentStateWaiting #waitingMessage { display: table; }
        #liveAgentSaveButton, #liveAgentEndButton { z-index: 2; }
        .liveAgentChatInput {
            height: 25px;
            border-width: 1px;
            border-style: solid;
            border-color: #000;
            padding: 2px 0 2px 4px;
            background: #fff;
            display: block;
            width: 99%;
        }
        .liveAgentSendButton {
            display: block;
            width: 60px;
            height: 31px;
            padding: 0 0 3px;
            position: absolute;
            top: 0;
            right: -67px;
        }
        #liveAgentChatLog {
            width: auto;
            height: auto;
            top: 0px;
            position: absolute;
            overflow-y: auto;
            left: 0;
            right: 0;
            bottom: 0;
        }
    </style>
    <div style="top: 0; left: 0; right: 0; bottom: 0; position: absolute;">
        <liveAgent:clientChat >
        <liveAgent:clientChatSaveButton />
        <liveAgent:clientChatEndButton />
        <div style="top: 25px; left: 5px; right: 5px; bottom: 5px; position: absolute; z-index:0;">
            <liveAgent:clientChatAlertMessage />
            <liveAgent:clientChatStatusMessage />
            <table id="waitingMessage" cellpadding="0" cellspacing="0">
                <tr>
                    <td colspan="2">
                        Please wait while you are connected to an available agent.
                    </td>
                </tr>
                <tr>
                    <td>Your current Queue position is</td>
                    <td><liveAgent:clientChatQueuePosition /></td>
                </tr>
            </table>
            <div style="top: 0; right: 0; bottom: 41px; left: 0; padding: 0; position: absolute;word-wrap: break-word; z-index: 0;">
                <liveAgent:clientChatLog />
            </div>
            <div style="position: absolute; height: auto; right: 0; bottom: 0; left: 0; margin-right:67px;">
                <liveagent:clientChatInput /><liveAgent:clientChatSendButton />
            </div>
        </div>
        </liveAgent:clientChat>
    </div>
</apex:page>

Use the Visualforce page in the Custom Chat Page in Chat Button.
 
 
Additional Resources:

 
Output:
 

March 27, 2021

JavaScript Closure

In JavaScript, closures are created every time a function is created, at function creation time.
 
Closure means that an inner function always have access to the variables and parameters of its outer function even after the outer function has returned. This is not common with other programming languages.

Sample Code:
function simpleFunc() {

  let strName = 'Magulan';
 
  function showName() {
 
    alert( strName);
    
  }
 
  return showName;
 
}


var myFunc = simpleFunc();
myFunc();//alerts Magulan which is outer function variable.


It shouldn't alert Magulan since the strName is a variable from outer function. It is alerting because of closures. A closure is the combination of a function and the lexical environment within which that function was declared. This environment consists of any local variables that were in-scope at the time the closure was created.

Another Sample Code:
function add( x ) {

  return function( y ) {
 
    return x + y;
    
  };
 
}

let obj = add( 2 );
alert( obj( 3 ) );//alerts 5

March 26, 2021

How to end Messaging Session from Salesforce Einstein Bot?

1. Create a Dialog or use the existing End Chat Dialog.

2. Use Rules and select End Chat in the Rule Action.


Output: