July 30, 2021

How to use LWC Lightning Record Form in Salesforce Experience Cloud?

Sample Code:
 
HTML:
<template>
    Test from Record Detail Page - {recordId}.
    <lightning-record-form
        object-api-name="Account"
        record-id={recordId}
        layout-type="Compact"
        columns="1"
        mode="readonly">
    </lightning-record-form>
</template>
 
JavaScript:
import { LightningElement,api } from 'lwc';

export default class RecordDetailComponent extends LightningElement {

    @api recordId;

}
 
js-meta.xml:
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>52.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightningCommunity__Page</target>
        <target>lightningCommunity__Default</target>
    </targets>
    <targetConfigs>
        <targetConfig targets="lightningCommunity__Default">
            <property
                name="recordId"
                type="String"
                label="Record Id"
                description="Automatically bind the page's record id to the component variable"
                default="{!recordId}" />
        </targetConfig>
    </targetConfigs>
</LightningComponentBundle>

 
Output:
 

How to get updated wired data in lightning-tree-grid with row level action in Salesforce Lightning on click of a button?

Apex Class:
public with sharing class ExampleController {

    @AuraEnabled(cacheable=true)
    public static List < Account > fetchAccounts() {

        return [ SELECT Id, Name, Industry, ( SELECT Id, FirstName, LastName FROM Contacts ) FROM Account LIMIT 10 ];
      
    }
 
}

LWC HTML:
<template>
    <lightning-card>
        <div class="slds-m-bottom_small">
            <lightning-button
                label="Collapse All"
                onclick={clickToCollapseAll}>
            </lightning-button>
            <lightning-button
                label="Expand All"
                onclick={clickToExpandAll}>
            </lightning-button>          
        </div>      
        <lightning-tree-grid
            columns = {gridColumns}
            data = {gridData}
            key-field = "Id"
            hide-checkbox-column = true
            onrowaction={handleRowAction}>
        </lightning-tree-grid>
        <p slot="footer">
            <lightning-button
                label="Get Updated Data"
                onclick={fetchUpdatedData}>
            </lightning-button>
        </p>
    </lightning-card>  
</template>

LWC JS:
import { LightningElement, track, wire } from 'lwc';
import { NavigationMixin } from 'lightning/navigation';
import fetchAccounts from '@salesforce/apex/ExampleController.fetchAccounts';
import { refreshApex } from '@salesforce/apex';

export default class TreeGrid extends NavigationMixin( LightningElement ) {

    gridData;
    wireData;
    gridColumns = [{
        type: 'text',
        fieldName: 'Name',
        label: 'Name'
    },
    {
        type: 'text',
        fieldName: 'Industry',
        label: 'Industry'
    },
    {
        type: 'text',
        fieldName: 'FirstName',
        label: 'FirstName'
    },
    {
        type: 'text',
        fieldName: 'LastName',
        label: 'LastName'
    },
    {
        type: 'button',
        typeAttributes: {
            label: 'View'
        }
    }];    

    @wire(fetchAccounts)
    accountTreeData( value ) {

        console.log( 'Inside wire' );
        this.wireData = value;     
        const { data, error } = value;

        if ( data ) {
            
            let tempData = JSON.parse( JSON.stringify( data ) );
            console.log( 'Data is ' + JSON.stringify( tempData ) );
            /*let tempjson = JSON.parse( JSON.stringify( data ).split( 'Contacts' ).join( '_children' ) );
            console.log( 'Temp JSON is ' + tempjson );*/
            for ( let i = 0; i < tempData.length; i++ ) {
    
                tempData[ i ]._children = tempData[ i ][ 'Contacts' ];
                delete tempData[ i ].Contacts;
    
            }
            this.gridData = tempData;

        } else if ( error ) {
         
            if ( Array.isArray( error.body ) )
                console.log( 'Error is ' + error.body.map( e => e.message ).join( ', ' ) );
            else if ( typeof error.body.message === 'string' )
                console.log( 'Error is ' + error.body.message );

        }

    }

    clickToExpandAll( e ) {
        const grid =  this.template.querySelector( 'lightning-tree-grid' );
        grid.expandAll();
    }

    clickToCollapseAll( e ) {

        const grid =  this.template.querySelector( 'lightning-tree-grid' );
        grid.collapseAll();
     
    }

    handleRowAction( event ) {
       
        const row = event.detail.row;
        this[NavigationMixin.Navigate]({
            type: 'standard__recordPage',
            attributes: {
                recordId: row.Id,
                actionName: 'view'
            }
        });

    }

    fetchUpdatedData() {

        refreshApex( this.wireData );

    }

}

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


Output:


After clicking "Get Updated Data" button:
Test Acc 45 is changed to Testing Acc 45.
Contact first name and last names are also updated in the tree grid.

July 29, 2021

End Salesforce Chat Conversation using Einstein Bot

In the BOT, use End Chat Rule.


Output:
 


July 22, 2021

"ConversationDefinitionEventLog" missing in Tableau CRM

If you face the below exception, check the steps to assign the required Permission.
 
Something went wrong while executing the BotEvent node: Object ConversationDefinitionEventLog is not available. Verify that the object exists and that the Analytics Cloud Integration User profile has Read level access on the object.
 
1. Create a new Permission Set.

2.  Enable "Manage Bots" under System Permissions.
 

3. Assign the Permission Set to Analytics Integration User.

Note:
If you face any issues while adding permission set, disable Analytics and enable it back on again. This will delete anything in your default dataflow so take a copy of that first. This will only delete items in your default data flow of  "Default Salesforce Dataflow". You can download the JSON for "Default Salesforce Dataflow" that way you can upload it after enabling Analytics. All other Dataflows will not be impacted.

July 19, 2021

Salesforce History Tracking Related List Missing


1. Enable "Track Field History".


2. Check in Related Lists after enabling it.


How to open new window using Quick Action using LWC in Salesforce?

HTML:
<template>
    
</template>

JavaScript:
import { LightningElement, api } from 'lwc';
import { NavigationMixin } from 'lightning/navigation';

export default class OpenAccountQuickAction  extends NavigationMixin( LightningElement ) {

    @api recordId;

    @api invoke() {

        console.log( "Inside Invoke Method" );
        console.log( "Record Id is " + this.recordId );

        this[ NavigationMixin.GenerateUrl ]( {

            type: 'standard__recordPage',
            attributes: {
                recordId: this.recordId,
                actionName: 'view',
            },

        } ).then( url => {

            console.log( 'URL is ' + url );
            let completeURL = window.location.origin + url;
            let windowFeatures = "menubar=no,resizable=yes,scrollbars=yes";
            windowFeatures  = "width=" + screen.width;
            windowFeatures += ",height=" + screen.height;
            console.log( 'Complete URL is ' + completeURL );
            window.open( completeURL, "_blank", windowFeatures );

        } );


    }

}

js-meta.xml:
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>52.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__RecordAction</target>
        <target>lightning__RecordPage</target>
    </targets>
    <targetConfigs>
        <targetConfig targets="lightning__RecordAction">
            <actionType>Action</actionType>
        </targetConfig>
    </targetConfigs>
</LightningComponentBundle>


July 16, 2021

Validation in Salesforce Embedded Service Deployment Pre-Chat

 HTML:
<template>
    <lightning-card title="Prechat Form">       
        <template if:true={errorMessage}>
            <div style="color:red;font-weight:bold;">
                {errorMessage}<br/>
            </div>
        </template>
        <template class="slds-m-around_medium" for:each={fields} for:item="field">
            <div key={field.name}>
                <lightning-input
                    key={field.name}
                    name={field.name}
                    label={field.label}
                    value={field.value}
                    max-length={field.maxLength}
                    required={field.required}>
                </lightning-input>
            </div>
        </template>
    </lightning-card>
    <br/><br/>
    <lightning-button
        label="Start Chat"
        title="Start Chat"
        onclick={handleStartChat}
        class="slds-m-left_x-small"
        variant="brand">
    </lightning-button>
</template>

JavaScript:
import BasePrechat from 'lightningsnapin/basePrechat';
import { api } from 'lwc';

export default class Prechat extends BasePrechat {

    @api prechatFields;
    fields;
    namelist;
    errorMessage;

    /**
     * Set the button label and prepare the prechat fields to be shown in the form.
     */
    connectedCallback() {
        
        this.fields = this.prechatFields.map( field => {
            const { label, name, value, required, maxLength } = field;

            return { label, value, name, required, maxLength };
        });
        this.namelist = this.fields.map( field => field.name );

    }

    /**
     * On clicking the 'Start Chatting' button, send a chat request.
     */
    handleStartChat() {

        this.template.querySelectorAll( "lightning-input" ).forEach( input => {
            this.fields[ this.namelist.indexOf( input.name ) ].value = input.value;
        });
        if ( this.validateFields( this.fields ).valid ) {
            
            let checkBool = true;

            for ( let field of this.fields ) {

                console.log( JSON.stringify( field ) );
                console.log( 'Field Value is ' + field.value );

                if ( !field.value ) {
                    
                    checkBool = false;
                    this.errorMessage = 'Please fill ' + field.label + ' to Start the Chat';
                    break;
                    
                }


            }

            if ( checkBool === true ) {

                console.log( 'Starting Chat' );
                this.startChat( this.fields );

            }

        } else {
            console.log( 'Some error in initiating the Chat' );
        }

    }

}

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


Pre-Chat Config in Embedded Service:
 

Output:


July 14, 2021

How to show a component only in Mobile in Salesforce Lightning

1. Select the Component.

2. Click Add Filter.

3. Select Device.

4. Select Form Factor in field, Equal as Operator and Phone as Value.
 

July 13, 2021

How to hide and show a component in Mobile in Salesforce Experience Cloud?

1. Change the View to Mobile.


2. Select the Component.
 
3. Click Hide On Mobile if you would like to hide it in Mobile view.
 

How to pass Pre-Chat data from Chat to Einstein Bot in Salesforce?

1.  Create a custom field in Case object to get the values from Pre-Chat.


2. Create a custom field in Chat Transcript object to store the values from Pre-Chat.


3. Create a custom field in Opportunity object to fetch the opportunity record based on the Tracking Number from Pre-Chat and show the Status to the Chat Visitor.


4. Add the Custom Field created in Step 1 to the Embedded Service Deployment.


5. Add the below code to your Embedded Service Code. This is will store the Tracking Number from Pre-Chat to the Chat Transcript record.

        embedded_svc.settings.extraPrechatFormDetails = [{
            "label":"Tracking Number",
            "transcriptFields": ["Tracking_Number__c"]
        }];

Note:
If you are using Experience/Community Cloud, you have to add it to your Snippet JavaScript Static Resource.

6. Create a Simple Flow to fetch Opportunity Stage based on Tracking Number.

Variables:
 


Fetch Opportunity:
 

Assign Opportunity Stage:
 
 

7. Update the BOT.

Package.xml to retrieve the BOT:
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <types>
        <members>Chat_Bot</members>
        <name>Bot</name>
    </types>
    <types>
        <members>*</members>
        <name>MlDomain</name>
    </types>
    <version>52.0</version>
</Package>

Context Variable to BOT to store Tracking Number from Chat Transcript:
Add the below to the retrieved BOT and deploy it.

    <contextVariables>
        <contextVariableMappings>
            <SObjectType>LiveChatTranscript</SObjectType>
            <fieldName>LiveChatTranscript.Tracking_Number__c</fieldName>
            <messageType>WebChat</messageType>
        </contextVariableMappings>
        <dataType>Text</dataType>
        <developerName>TrackingNumber</developerName>
        <label>Tracking Number</label>
    </contextVariables>


Create Variables in the BOT and check the Context Variable:


Create a Dialog to handle when Tracking Number is Entered:
 
 
Welcome Dialog Updates:
 
a. Set Variable Rule to store the Tracking Number from Chat Transcript to Tracking Number variable.
b.  Another Rule action to check if Tracking Number is entered and calling the Dialog to check the Opportunity Status.


Output:
 
 

How to deploy Path Settings using Ant Tool in Salesforce?

 package.xml:
 
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
  <types>
        <members>Opportunity.Easy Deal</members>
        <name>BusinessProcess</name>
    </types>
    <types>
        <members>Opportunity.StageName</members>
        <name>CustomField</name>
    </types>
    <types>
        <members>Easy_Deal</members>
        <name>PathAssistant</name>
    </types>
    <types>
        <members>Opportunity.Easy_Deal</members>
        <name>RecordType</name>
    </types>
    <types>
        <members>PathAssistant</members>
        <name>Settings</name>
    </types>
    <version>52.0</version>
</Package>

July 12, 2021

How to avoid redirect when using iframe tag?

Use sandbox attribute.

<iframe src="Site_URL" sandbox=""> - Full Protection.

<iframe src="Site_URL"  sandbox="allow-forms allow-scripts"> - Allow form submission and scripts to run.

July 8, 2021

How to assign the Chat to other available agents when the agent is not accepting the Chats in Salesforce?

Use Push Time-Out to assign the Chat to other available agents when the agent is not accepting the Chats in Salesforce.
 

Push Time-Out is the amount of time given to an agent to respond to an assigned item (Chats or other records when using Omni-Channel) before it’s pushed to another agent. This can be set with Chat Routing Information and with Omni-Channel Routing Configurations. If both are configured with a different a value (time in seconds) the time set for Chat takes precedence over Omni-Channel routing configuration.

https://help.salesforce.com/articleView?id=000313054&mode=1&sfdcIFrameOrigin=null&type=1

July 7, 2021

How to create ODATA and External Data source using Heroku for Salesforce?

1. Create a Heroku Project.

2. Install Heroku Connect and Heroku Postgres add-ons.

3. Create a table in Heroku Postgres.

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 a tab for the External Object.


July 6, 2021

Salesforce To Salesforce External Sharing related list in Lightning

Sample Code:

Apex Class:

public class ExternalSharingController {
    
    @AuraEnabled( cacheable = true )
    public static List < ConnectionWrapper > fetchConnections( String recId ) {
        
        List < ConnectionWrapper > listConnections = new List < ConnectionWrapper >();
        List < PartnerNetworkRecordConnection > listPNRCs = [
            SELECT Id, ConnectionId, StartDate, EndDate, Status
            FROM PartnerNetworkRecordConnection WHERE LocalRecordId =: recId
        ];
        
        if ( listPNRCs.size() > 0 ) {
            
            Set < Id > setConnectionIds = new Set < Id >();
            Map < Id, String > mapConnectionName = new Map < Id, String >();
            
            for ( PartnerNetworkRecordConnection objPNRC : listPNRCs )
                setConnectionIds.add( objPNRC.ConnectionId );
            
            for ( PartnerNetworkConnection objPNC : [ SELECT Id, ConnectionName FROM PartnerNetworkConnection WHERE Id IN: setConnectionIds ] )
                mapConnectionName.put( objPNC.Id, objPNC.ConnectionName );
            
            for ( PartnerNetworkRecordConnection objPNRC : listPNRCs ) {
                
                ConnectionWrapper wrap = new ConnectionWrapper();
                wrap.connectionName = mapConnectionName.get( objPNRC.ConnectionId );
                wrap.startDate = objPNRC.StartDate;
                wrap.endDate = objPNRC.EndDate;
                wrap.status = objPNRC.Status;
                listConnections.add( wrap );
                
            }
            
        }
        
        return listConnections;
        
    }
    
    public class ConnectionWrapper {
        
        @AuraEnabled
        public String connectionName;
        @AuraEnabled
        public DateTime startDate;
        @AuraEnabled
        public DateTime endDate;
        @AuraEnabled
        public String status;
        
    }

}

HTML:
<template>  
    <lightning-card>
        <template if:true={displayBool}>
            <lightning-datatable
                    key-field="Id"
                    data={records}
                    columns={columns}
                    hide-checkbox-column="true">
            </lightning-datatable>
        </template>  
        <template if:false={displayBool}>
            Record is not transferred to the other org(s).
        </template>
        <template if:true={error}>
            {error}
        </template>
    </lightning-card>
</template>

JavaScript:
import { LightningElement, wire, api } from 'lwc';
import fetchConnections from '@salesforce/apex/ExternalSharingController.fetchConnections';
const COLUMNS = [
    { label: 'Connection Name', fieldName: 'connectionName' },
    {
        label: 'Start Date', fieldName: 'startDate', type: "date-local",
        typeAttributes: {
            month: "2-digit",
            day: "2-digit"
        }
    },
    {
        label: 'End Date', fieldName: 'endDate', type: "date-local",
        typeAttributes: {
            month: "2-digit",
            day: "2-digit"
        }
    },
    { label: 'Status', fieldName: 'status' }
];
export default class ExternalSharing extends LightningElement {
    
    @api
    recordId;
    records;
    error;
    columns = COLUMNS;
    displayBool = false;

    @wire( fetchConnections, { recId: '$recordId' } )  
    wiredRecords( value ) {
        
        console.log( 'Data received ' + JSON.stringify( value ) );
        const { data, error } = value;

        if ( data ) {
            
            this.records = data;
            this.error = undefined;

            if ( this.records.length > 0 )
                this.displayBool = true;

        } else if ( error ) {

            this.error = error;
            this.records = undefined;
            this.displayBool = false;

        }

    }
}

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


Output:



July 5, 2021

Report on records shared by Salesforce to Salesforce?

 In my implementation, I have shared Account records to another Salesforce org.

1. Create a Custom Report type with Account as primary object and Connection Histories as related object..


2. Now create a report with the Custom Report Type.


How to forward records using Apex in Salesforce to Salesforce

Sample Code:

PartnerNetworkConnection network = [ SELECT Id FROM PartnerNetworkConnection WHERE ConnectionStatus = 'Accepted' LIMIT 1 ];
List < PartnerNetworkRecordConnection > listConnections = new List < PartnerNetworkRecordConnection >();
PartnerNetworkRecordConnection connection = new PartnerNetworkRecordConnection();
connection.ConnectionId = network.Id;
connection.LocalRecordId = '0015Y00002dfRIF';//Id of the record to be shared to the other Salesforce Org
listConnections.add( connection );
insert listConnections;

Passing URL Parameters or Query Parameters to Salesforce Lightning Web Component Tab

1. Create the below Lightning Web Component for a Tab.

HTML:
<template>
    <iframe src={strURL} width="100%" height="100%"></iframe>
</template>

JavaScript:
import { LightningElement, wire } from 'lwc';
import { CurrentPageReference } from 'lightning/navigation';

export default class LightningTab extends LightningElement {

    @wire( CurrentPageReference )
    currentPageReference;

    strURL;

    connectedCallback() {

        this.strURL = 'https://www.test-cors.org/?server_tabs=remote#?client_headers=';
        let recId = this.currentPageReference.state.c__recId;
        console.log( 'RecId is ' + recId );

        if ( recId )
            this.strURL += recId;

    }

}

JavaScript-meta.xml:
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>52.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__Tab</target>
    </targets>
</LightningComponentBundle>
 
2. Create a Tab for the above Lightning Web Component.
 
 
3. Create this Lightning Web Component for Quick Action.
 
HTML:
<template>
    
</template>

JavaScript:

import { LightningElement, api } from 'lwc';
import { NavigationMixin } from 'lightning/navigation';

export default class OpenLightningTab  extends NavigationMixin( LightningElement ) {

    @api recordId;

    @api invoke() {

        console.log( "Inside Invoke Method" );
        console.log( "Record Id is " + this.recordId );
        this[ NavigationMixin.Navigate ]( {
            type: 'standard__navItemPage',
            attributes: {
                apiName: 'Lightning_Tab'
            },
            state: {
                c__recId: this.recordId
            }
        } );

    }

}

JavaScript-meta.xml:
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>52.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__RecordAction</target>
        <target>lightning__RecordPage</target>
    </targets>
    <targetConfigs>
        <targetConfig targets="lightning__RecordAction">
            <actionType>Action</actionType>
        </targetConfig>
    </targetConfigs>
</LightningComponentBundle>
 
4.  Create a Quick action and add it to the Page Layout.


Output:
 
 

July 4, 2021

INVALID_PARTNER_NETWORK_STATUS, invalid status for partner network operation: []

"INVALID_PARTNER_NETWORK_STATUS, invalid status for partner network operation: []" exception occur if the "LocalRecordId" attribute of "PartnerNetworkRecordConnection" is incorrect.
 
Sample Code:
PartnerNetworkConnection network = [ SELECT Id FROM PartnerNetworkConnection WHERE ConnectionStatus = 'Accepted' LIMIT 1 ];
List < PartnerNetworkRecordConnection > listConnections = new List < PartnerNetworkRecordConnection >();
PartnerNetworkRecordConnection connection = new PartnerNetworkRecordConnection();
connection.ConnectionId = network.Id;
connection.LocalRecordId = '0015Y00002dfRIF';//Id of the record to be shared to the other Salesforce Org
listConnections.add( connection );
insert listConnections;

Salesforce to Salesforce record forward in Salesforce Lightning

Sample Code:

Apex Class:
public class ForwardRecordToSFController {
    
    @AuraEnabled  
    public static String forwardRecord( String recId ) {
        
        List < PartnerNetworkRecordConnection > checkConnection = [ SELECT Id FROM PartnerNetworkRecordConnection WHERE LocalRecordId =: recId ];
        
        if ( checkConnection.size() > 0 ) {
            
            return 'Record is already shared to the other org';
        
        } else {
            
            PartnerNetworkConnection network = [ SELECT Id FROM PartnerNetworkConnection WHERE ConnectionStatus = 'Accepted' LIMIT 1 ];
            PartnerNetworkRecordConnection connection = new PartnerNetworkRecordConnection();
            connection.ConnectionId = network.Id;
            connection.LocalRecordId = recId;
            insert connection;
            return 'Record forwarded successfully';
            
        }
        
    }

}

Aura Component:
<aura:component implements="force:hasRecordId,force:lightningQuickActionWithoutHeader"
                access="global"
                controller="ForwardRecordToSFController">
    <aura:handler name = "init" value = "{!this}" action = "{!c.onInit}"/>
</aura:component>

Aura Controller:
({
    
    onInit : function( component, event, helper ) {  
          
        var action = component.get( "c.forwardRecord" );  
        action.setParams({  
            recId: component.get( "v.recordId" )
        });  
        action.setCallback(this, function( response ) {              
            var state = response.getState();  
            if (state === "SUCCESS") {  
                
                $A.get( "e.force:closeQuickAction" ).fire();  
                $A.get( 'e.force:refreshView' ).fire();  
                
                let showToast = $A.get( "e.force:showToast" );
                showToast.setParams({
                    title : 'Record Forward',
                    message : response.getReturnValue(),
                    type : 'info',
                    mode : 'dismissible'
                });
                showToast.fire();
                  
            }  
        });  
        $A.enqueueAction(action);  
          
    }
    
})


Quick Action:


Add the Quick Action to the page layout and test it out.


July 3, 2021

How to find records with most filled field Values in Salesforce?

Sample Code:

public class Utility {
    
    public static Map < Integer, List < SObject > > constructFieldCountListSObjs( List < SObject > listSObjs ) {
    
        Map < Integer, List < SObject > > mapFieldCountSObjList = new Map < Integer, List < SObject > >();
        
        for ( SObject obj : listSObjs ) {
            
            String JSONContent = JSON.serialize( obj );
            JSONParser parser = JSON.createParser( JSONContent );
            Integer intCount = 0;
            
            while ( parser.nextToken() != null ) {
                
                    
                /*  Ignoring Start and End Objects */
                if ( parser.getCurrentToken() != JSONToken.START_OBJECT
                    && parser.getCurrentToken() != JSONToken.END_OBJECT ) {
                    
                    /*  Ignoring attributes and it related contents like type and url.
                        Ignoring Id and it value.    
                    */
                    if ( parser.getCurrentName() == 'attributes' ) {
                        
                        parser.nextToken();
                        parser.nextToken();
                        parser.nextToken();
                        parser.nextToken();
                        parser.nextToken();
                        parser.nextToken();
                        continue;
                        
                    } else if ( parser.getCurrentName() == 'Id' ) {
                        
                        parser.nextToken();
                        continue;
                        
                    } 
                        
                    intCount += 1;
                    parser.nextToken();
                    
                }
                
            }
            
            if ( !mapFieldCountSObjList.containsKey( intcount ) )
                mapFieldCountSObjList.put( intcount, new List < Account >() );
            mapFieldCountSObjList.get( intcount ).add( obj );
                
        }
    
        return mapFieldCountSObjList;
    
    }
            
}

Output:

List < Account > listAccs = [ SELECT Name, Industry, Site, AccountSource, AnnualRevenue, Phone, Rating FROM Account LIMIT 10 ];
Map < Integer, List < SObject > > mapFieldCountSObjList = Utility.constructFieldCountListSObjs( listAccs );

for ( Integer i : mapFieldCountSObjList.keySet() ) {
    
    System.debug( 'Field Count is ' + i );
    
    for ( SObject acc: mapFieldCountSObjList.get( i ) ) {
        
        System.debug( 'Account is ' + JSON.serialize( acc ) );
        
    }
    
}


To print the values in sorted order.

List < Account > listAccs = [ SELECT Name, Industry, Site, AccountSource, AnnualRevenue, Phone, Rating FROM Account LIMIT 10 ];
Map < Integer, List < SObject > > mapFieldCountSObjList = Utility.constructFieldCountListSObjs( listAccs );
List < Integer > listKeys = new List < Integer >();
listKeys.addAll( mapFieldCountSObjList.keySet() );
listKeys.sort();
    
for ( Integer i : listKeys ) {
    
    System.debug( 'Field Count is ' + i );
    
    for ( SObject acc: mapFieldCountSObjList.get( i ) ) {
        
        System.debug( 'Account is ' + JSON.serialize( acc ) );
        
    }
    
}