November 29, 2020

Partner Community Cloud in Salesforce

November 28, 2020

"This Status requires a Console Component that isn't available in this application" Error in setting up omni-channel for LiveMessage in Salesforce Classic

Custom Console Footer Component should be blank or LiveAgent_Hidden_Panel.


November 27, 2020

Salesforce Lightning User FAQ

November 26, 2020

Skills-Based Routing using Apex in Salesforce

1. Enable Skills-Based Routing


2. Setup Skills.
 
 
3. To determine the Skill dynamically, I am using the below Custom field.


4. Service Resource record for an Agent.
 

5. Sample Apex Class:
 
public class SkillsBasedRoutingController {
    
    /*
        Primary method to route records through Omni-Channel
    */
    public static void routeUsingSkills( List < sObject > listRecords, String strEntity ) {
    
        List < PendingServiceRouting > listPSRs = new List < PendingServiceRouting >();
        String strChannelId = getChannelId( strEntity );
        Map < String, Id > mapSkillId = getSkillId();
        Map < Id, sObject > mapObj = new Map < Id, sObject >( listRecords );
    
        for ( sObject obj : listRecords )        
            listPSRs.add( createPendingServiceRouting( obj, strChannelId ) );
        
        if ( listPSRs.size() > 0 ) {
        
            List < SkillRequirement > listSRs = new List < SkillRequirement >();
            insert listPSRs;
            
            for ( PendingServiceRouting objPSR : listPSRs ) {
            
                objPSR.IsReadyForRouting = TRUE;
                sObject obj = mapObj.get( objPSR.WorkItemId );
                String strSkill = ( String ) obj.get( 'Skill__c' );
                SkillRequirement objSR = new SkillRequirement(
                    RelatedRecordId = objPSR.id,
                    SkillId = mapSkillId.get( strSkill ),
                    SkillLevel = 5
                );
                listSRs.add( objSR );
            
            }
            
            insert listSRs;
            
            update listPSRs;
            
        }
                
    }
    
    /*
        Method to create Pending Service Routing record for each record
    */
    static PendingServiceRouting createPendingServiceRouting( sObject obj, String strChannelId ) {
    
        PendingServiceRouting psrObj = new PendingServiceRouting(
            CapacityWeight = 1,
            IsReadyForRouting = FALSE,
            RoutingModel = 'MostAvailable',
            RoutingPriority = 1,
            RoutingType = 'SkillsBased',
            ServiceChannelId = strChannelId,
            WorkItemId = obj.Id,
            PushTimeout = 0
        );
        return psrObj;
        
    }
    
    /*
        Method to get the Channel Id based on the Entity
    */
    static String getChannelId( String strEntity ) {
    
        ServiceChannel channel = [ SELECT Id From ServiceChannel Where RelatedEntity =: strEntity ];
        return channel.Id;
        
    }
    
    /*
        Method to get Skills. If you have several skills, use WHERE condition in the SOQL to limit it.
    */
    static Map < String, Id > getSkillId() {
    
        Map < String, Id > mapSkillId = new Map < String, Id >();
        
        for ( Skill objSkill : [ SELECT Id, DeveloperName From Skill ] )
            mapSkillId.put( objSkill.DeveloperName, objSkill.Id );
            
        return mapSkillId;
        
    }
    
}


6. Sample Code to call the method.
List < Case > listCases = [ SELECT Id, Skill__c FROM Case WHERE Id = '5004W00001a3bSXQAY' ];
SkillsBasedRoutingController.routeUsingSkills( listCases, 'Case' );

November 24, 2020

How to avoid routing Closed cases in Salesforce Omni-Channel?

1. Go to Omni-Channel Settings.



2. Enable Status-Based Capacity Model.


3. Use Status-Based Capacity Model in the Service Channel.


November 23, 2020

Can't assign permission set Messaging Setup Flow to user. The user license doesn't allow the permission: Messaging Agent

 1. Make sure the user is assigned to the Messaging Permission Set. 
 
 2. Make sure Messaging User is assigned under Permission Set License Assignments section.

 

November 22, 2020

Disabling Locker Service by lowering the API version to 39 or earlier in Salesforce

Disabling Locker Service by lowering the API version to 39 or earlier in Salesforce

Locker Service is a powerful security architecture for Lightning components. Locker Service enhances security by isolating Lightning components that belong to one namespace from components in a different namespace. Locker Service also promotes best practices that improve the supportability of your code by only allowing access to supported APIs and eliminating access to non-published framework internals.

1. It downgrades the security.
2. Features/Functionalities introduced after Spring'17 cannot be utilized since the API Version doesn't support it.
3. Don’t Mix Component API Versions
For consistency and ease of debugging, we recommend that you set the same Salesforce API version for all custom components in your app, containment hierarchy (component within component), or extension hierarchy (component extending component).
If you mix API versions in your containment or extension hierarchy and Lightning Locker is enabled for some components and disabled for other components, your app will be harder to debug.
https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/security_ls_api_version_mix.htm
4. Locker Service prevents Cross Site Scripting (XSS). So, your component becomes prone to it.

November 20, 2020

SOQL in VS Code for Salesforce


2. Click Install. 

3. It will open in VS Code 
 
4. Click "Install" to install it.

 
5. Right Click accounts.soql under Scripts --> SOQL. Select Open With..
 
6. Select SOQL Builder.

 

November 19, 2020

How to find components deployed using Deployment Id in Salesforce?

1. Use Workbench and navigate to Utilities --> Metadata API Process Status.

 

2. Enter the Deployment Id. Select Deploy or Retrieve.

3. Click "Get Status" button.


November 18, 2020

SOQL to find user part of Queues

Sample SOQLs:

SELECT UserOrGroupId, COUNT( Id ) FROM GroupMember WHERE GroupId IN ( SELECT Id FROM Group WHERE Type = 'Queue' ) GROUP BY UserOrGroupId
 
For User level
SELECT UserOrGroupId, COUNT( Id ) FROM GroupMember WHERE UserOrGroupId = '0055w00000BflFyAAJ' AND GroupId IN ( SELECT Id FROM Group WHERE Type = 'Queue' ) GROUP BY UserOrGroupId 
 
Or use
https://<domain>.my.salesforce.com/_ui/system/user/QueueMembershipPage/d?userId=<User Id>

November 17, 2020

Difference between lightningStylesheets, apex:slds and apex:includeLightning

lightningStylesheets, apex:slds and apex:includeLightning

lightningStylesheets="true"
Make Visualforce apps look better in Lightning.

<apex:slds/>
To use markup specified by SLDS in Visualforce page.

<apex:includeLightning/>
There are three steps to add Aura components to a Visualforce page.
1. Add the Lightning Components for Visualforce JavaScript library to your Visualforce page using the <apex:includeLightning/> component.

2. Create and reference a Lightning app that declares your component dependencies.

3. Write a JavaScript function that creates the component on the page using $Lightning.createComponent().

November 16, 2020

Asset Hierarchy using LWC in Salesforce

Sample Code:

HTML:

<template>
    
    <div class="slds-p-around_medium lgc-bg">
        <lightning-tree-grid columns={gridColumns}
                             data={gridData}
                             key-field="Name"
                             hide-checkbox-column=true>
        </lightning-tree-grid>
    </div>     
    

</template>

JavaScript:

import { LightningElement, api, track, wire } from 'lwc';
import fetchAssetHierarchy from '@salesforce/apex/AssetHierarchyController.fetchAssetHierarchy'; 

export default class AssetHierarchy extends LightningElement {

    @api recordId;
    @track gridColumns = [{
        type: 'text',
        fieldName: 'Name',
        label: 'Name'
    },
    {
        type: 'text',
        fieldName: 'SerialNumber',
        label: 'Serial Number'
    }];
    @track gridData;

    @wire(fetchAssetHierarchy, { assetId: '$recordId' })  
    AssetRecords( { error, data } ) {  
  
        console.log( 'Inside Wire Method' );
        if ( data ) {  
            
            console.log( 'Data is ' + JSON.stringify( data ) );
            this.gridData = JSON.parse( JSON.stringify( data ).split( 'children' ).join( '_children' ) );
  
        } else if ( error ) {
            console.log( 'Error is ' + JSON.stringify( error ) );
        }
          
    } 


}

Apex Class:

public with sharing class AssetHierarchyController {
    
    @AuraEnabled(cacheable=true)
    public static List < HierarchyWrapper > fetchAssetHierarchy( String assetId ) {

        Map < Id, HierarchyWrapper > mapAssetId = new Map < Id, HierarchyWrapper >();
        Map < Id, List < Asset > > mapParentId = new Map < Id, List < Asset > >();
        List < HierarchyWrapper > listWrap = new List < HierarchyWrapper >();
        Asset currentAsset = [ SELECT Id, RootAssetId FROM Asset WHERE Id =: assetId ];
        List < Asset > listAssets = [ SELECT Id, Name, SerialNumber, ParentId FROM Asset WHERE RootAssetId =: currentAsset.RootAssetId ORDER BY ParentId NULLS FIRST ];
        Asset rootAsset = [ SELECT Id, Name, SerialNumber FROM Asset WHERE Id =: currentAsset.RootAssetId ];
        HierarchyWrapper rootAssetWrap = new HierarchyWrapper();
        rootAssetWrap.Name = rootAsset.Name;
        rootAssetWrap.SerialNumber = rootAsset.SerialNumber;
        rootAssetWrap.children = findRelations( listAssets, currentAsset.RootAssetId );
        listWrap.add( rootAssetWrap );
        return listWrap;
        
    }

    public static List < HierarchyWrapper > findRelations( List < Asset > listAssets, Id rootAssetId ) {

        List < HierarchyWrapper > listWrap = new List < HierarchyWrapper >();

        for ( Asset objAsset : listAssets ) {

            if ( objAsset.ParentId == rootAssetId ) {

                HierarchyWrapper wrap = new HierarchyWrapper();
                wrap.Name = objAsset.Name;
                wrap.SerialNumber = objAsset.SerialNumber;
                wrap.children = findRelations( listAssets, objAsset.Id );
                listWrap.add( wrap );

            }

        }

        if ( listWrap.size() > 0 )
            return listWrap;
        else 
            return null;

    }
    

}

JavaScript-meta.xml:

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>48.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__RecordPage</target>
    </targets>

</LightningComponentBundle>


Output:


November 15, 2020

Highlight Panel in Salesforce

Compact layouts control which fields your users see in the highlights panel at the top of a record. The fields in the Highlight panel are rendered from the Compact layout.

In Salesforce Classic, the highlights panel is a customizable table of up to four columns at the top of every primary tab in a console. It helps console users see key information at a glance. To configure a highlights panel, edit any page layout.

In Lightning Experience, up to the first seven fields in a compact layout appear in the highlights panel of an object record. (On smaller screens, the highlights panel displays fewer fields.) When a user hovers over a lookup relationship field on the object record page, a highlights panel for that field displays the first five fields from the compact layout. Highlights panels display the first field from the compact layout at the top in an accented font.

Compact layouts support all field types except:
1. text area
2. long text area
3. rich text area
4. multi-select picklist

November 14, 2020

Searching for multiple field values in Splunk

Searching for multiple field values in Splunk
IN operator can be used to search for multiple field values in Splunk

Syntax:
field IN (value1, value2, value3)

Sample:
userId IN (123, 456, 789, 587)

November 13, 2020

Open record within the Console App in Salesforce Lightning

1. Use target as "_self".
 
2. Use "/lightning/r/" as the path.
 


Salesforce Platform Event Subscription in LWC

Sample code:
 
HTML:
<template>
    <lightning-card title="EmpApi Example" icon-name="custom:custom14">
        <div class="slds-m-around_medium">
            <p>Use the buttons below to subscribe and unsubscribe to a streaming channel!</p>
            <lightning-input label="Channel Name" value={channelName}
                onchange={handleChannelName}></lightning-input>
            <lightning-button variant="success" label="Subscribe" title="Subscribe"
                onclick={handleSubscribe} disabled={isSubscribeDisabled}
                class="slds-m-left_x-small"></lightning-button>
            <lightning-button variant="destructive" label="Unsubscribe" title="Unsubscribe"
                onclick={handleUnsubscribe} disabled={isUnsubscribeDisabled}
                class="slds-m-left_x-small"></lightning-button>
        </div>
    </lightning-card>
</template>

 
JavaScript:
import { LightningElement } from 'lwc';
import { subscribe, unsubscribe, onError, setDebugFlag, isEmpEnabled } from 'lightning/empApi';

export default class PlatformEventMonitor extends LightningElement {
    channelName = '/event/Sample__e';
    isSubscribeDisabled = false;
    isUnsubscribeDisabled = !this.isSubscribeDisabled;

    subscription = {};

    // Tracks changes to channelName text field
    handleChannelName(event) {
        this.channelName = event.target.value;
    }

    // Initializes the component
    connectedCallback() {       
        // Register error listener       
        this.registerErrorListener();      
    }

    // Handles subscribe button click
    handleSubscribe() {
        // Callback invoked whenever a new event message is received
        const messageCallback = function(response) {
            console.log('New message received: ', JSON.stringify(response));
            // Response contains the payload of the new message received
        };

        // Invoke subscribe method of empApi. Pass reference to messageCallback
        subscribe(this.channelName, -1, messageCallback).then(response => {
            // Response contains the subscription information on subscribe call
            console.log('Subscription request sent to: ', JSON.stringify(response.channel));
            this.subscription = response;
            this.toggleSubscribeButton(true);
        });
    }

    // Handles unsubscribe button click
    handleUnsubscribe() {
        this.toggleSubscribeButton(false);

        // Invoke unsubscribe method of empApi
        unsubscribe(this.subscription, response => {
            console.log('unsubscribe() response: ', JSON.stringify(response));
            // Response is true for successful unsubscribe
        });
    }

    toggleSubscribeButton(enableSubscribe) {
        this.isSubscribeDisabled = enableSubscribe;
        this.isUnsubscribeDisabled = !enableSubscribe;
    }

    registerErrorListener() {
        // Invoke onError empApi method
        onError(error => {
            console.log('Received error from server: ', JSON.stringify(error));
            // Error contains the server-side error
        });
    }
}

 
meta.xml: 
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>50.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__Tab</target>
    </targets>
</LightningComponentBundle>


Sample Platform Event:

 
 
 
Apex Code:
Sample__e objEvent = new Sample__e( Name__c = 'Testing' );
EventBus.publish( objEvent ); 

Execute the above code in Anonymous apex window.


November 12, 2020

Edit and Delete button in Event/Task object in Salesforce

1. Check whether the user has the necessary Edit and Delete permissions, either via a profile or permission set.

2. If it is in Lightning Experience, make sure the page layout includes the expected buttons in the Salesforce Mobile and Lightning Experience Actions.


November 11, 2020

Visualforce page to make it available in the Lightning App Builder/Lightning Page

1. Enable "Available for Lightning Experience, Lightning Communities, and the mobile app" for a Visualforce page to make it available in the Lightning App Builder.


2.Enable My Domain in your Org.
http://www.infallibletechie.com/2013/08/domain-registration-in-salesforce.html

3. Add <apex:slds /> in the VF Page.

November 10, 2020

Subscribe and show PushTopic events notifications using Lightning Web Component

Sample Push Topic:

  1. PushTopic pushTopic = new PushTopic();  
  2. pushTopic.Name = 'AccountUpdates';  
  3. pushTopic.Query = 'SELECT Id, Name, Phone FROM Account WHERE BillingCity=\'San Francisco\'';  
  4. pushTopic.ApiVersion = 48.0;  
  5. insert pushTopic; 

Sample LWC:

HTLML:


  1. <template>  
  2.   
  3.     <lightning-card title="EmpApi Example" icon-name="custom:custom14">  
  4.   
  5.         <div class="slds-m-around_medium">  
  6.   
  7.             <p>Use the buttons below to Subscribe and Unsubscribe!!!</p>  
  8.             <lightning-input label="Channel Name" value={channelName}  
  9.                              onchange={handleChannelName}></lightning-input><br/>  
  10.             <lightning-button variant="success" label="Subscribe" title="Subscribe"  
  11.                               onclick={handleSubscribe} disabled={isSubscribeDisabled}  
  12.                               class="slds-m-left_x-small"></lightning-button>  
  13.             <lightning-button variant="destructive" label="Unsubscribe" title="Unsubscribe"  
  14.                               onclick={handleUnsubscribe} disabled={isUnsubscribeDisabled}  
  15.                               class="slds-m-left_x-small"></lightning-button><br/><br/>  
  16.             <b>Response:</b> <br/>{strResponse}  
  17.   
  18.         </div>  
  19.   
  20.     </lightning-card>  
  21.   
  22. </template

JS:

  1. import { LightningElement, track } from 'lwc';  
  2. import { subscribe, unsubscribe, onError, setDebugFlag, isEmpEnabled } from 'lightning/empApi';  
  3.   
  4. export default class PushTopicLWC extends LightningElement {  
  5.   
  6.     @track channelName = '/topic/AccountUpdates';  
  7.     @track isSubscribeDisabled = false;  
  8.     @track isUnsubscribeDisabled = !this.isSubscribeDisabled;  
  9.     @track strResponse = '';  
  10.   
  11.     subscription = {};  
  12.   
  13.     // Tracks changes to channelName text field  
  14.     handleChannelName(event) {  
  15.         this.channelName = event.target.value;  
  16.     }  
  17.   
  18.     // Handles subscribe button click  
  19.     handleSubscribe() {  
  20.         // Callback invoked whenever a new event message is received  
  21.         const messageCallback = ( response ) => {  
  22.             console.log( 'New message received : ', JSON.stringify( response ) );  
  23.             // Response contains the payload of the new message received  
  24.             this.strResponse = JSON.stringify( response );  
  25.             console.log( this.strResponse );  
  26.         };  
  27.   
  28.         // Invoke subscribe method of empApi. Pass reference to messageCallback  
  29.         subscribe( this.channelName, -1, messageCallback ).then(response => {  
  30.             // Response contains the subscription information on successful subscribe call  
  31.             console.log( 'Successfully subscribed to : ', JSON.stringify( response.channel ) );  
  32.             this.subscription = response;  
  33.             this.toggleSubscribeButton( true );  
  34.         });  
  35.     }  
  36.   
  37.     // Handles unsubscribe button click  
  38.     handleUnsubscribe() {  
  39.         this.toggleSubscribeButton( false );  
  40.   
  41.         // Invoke unsubscribe method of empApi  
  42.         unsubscribe(this.subscription, response => {  
  43.             console.log( 'unsubscribe() response: ', JSON.stringify( response ) );  
  44.             // Response is true for successful unsubscribe  
  45.         });  
  46.     }  
  47.   
  48.     toggleSubscribeButton( enableSubscribe ) {  
  49.   
  50.         this.isSubscribeDisabled = enableSubscribe;  
  51.         this.isUnsubscribeDisabled = !enableSubscribe;  
  52.   
  53.     }  
  54.   
  55.     registerErrorListener() {  
  56.   
  57.         // Invoke onError empApi method  
  58.         onError(error => {  
  59.             console.log( 'Received error from server: ', JSON.stringify( error ) );  
  60.             // Error contains the server-side error  
  61.         });  
  62.   
  63.     }  
  64.   

JS-Meta.xml:

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">  
  3.     <apiVersion>48.0</apiVersion>  
  4.     <isExposed>true</isExposed>        
  5.     <targets>      
  6.         <target>lightning__Tab</target>      
  7.     </targets>  
  8. </LightningComponentBundle> 

Output: