Wednesday, April 20, 2022

Considerations for using Platform Events

Platform really helps in setting up custom notifications within salesforce or for external system. While utilising the platform events in salesforce, you need to consider below things:

  • Record Owner considerations

Whenever you create record from after insert using triggers, then ownerid of those records will be Automated Process by default. If you have set current user as record owner, then specify ownerid of created records as createdbyId of event.

Account acc= new Account(name='test account through Demo platform event',OwnerId = event.createdById);

  • Platform Event Trigger do not provide Email Support
As automated process user does not have email address, sending an email message from a platform event trigger using the Messaging.SingleEmailMessage class is not supported. As a workaround, send emails via email alert where the From Email Address is NOT "Current User's Email Address" but rather some other organization-wide email or default workflow user. 

In Apex, use the SingleEmailMessage.setOrgWideEmailAddressId method to set the org-wide email. 

Hope this will help!!

Thursday, May 27, 2021

Useful system application events for lightning developement

Below is list of application events which is very useful and can be used frequently in lightning development.

Note: These events are supported in Lightning Experience, the Salesforce mobile app, and Aura-based Experience Builder sites.

  • force:closeQuickAction

To close a quick action panel, you can use force:closeQuickAction event
var navEvent = $A.get("e.force:closeQuickAction");

  • force:navigateToList
This event helps you to navigate to list view based on ListviewId specified.

var navEvent = $A.get("e.force:navigateToList");
"listViewId": listviews.Id,
"listViewName": null,
"scope": "Account"
How to get list view id using SOQL
SELECT Id FROM ListView WHERE SobjectType = 'Account' and Name='All Accounts' Limit 1

  • force:navigateToURL
This event helps you to navigate to URL specified in parameter.

var navEvent= $A.get("e.force:navigateToURL");
      "url": "/001/"

  • force:refreshView
To refresh or reload standard or custom component, use this event. This event ideally reload data without page refresh.

var navEvent= $A.get("e.force:refreshView");

Note: This event impact performance and should be avoided. Also avoid repeated firing of this event from same component

  • force:showToast
This event can be used to display message below the header at the top of a view. You can specify the message and type (warning, success, info, other) and based on that color of message panel will changes. Default is other which shows panel similar to info.

var toastEvent = $A.get("e.force:showToast");
"title": title,
"message": msg,
"type": type,
"mode": mode

Default value for mode is "dismissible" which display close icon. In duration you can specify the time in millisecond. Toast will remain in screen for this duration.

  • force:force:navigateToSObject
This event help you to navigate to record details page based on recordId specified:

var navEvent= $A.get("e.force:navigateToSObject");
"recordId": "003B0000000ybYX"

Hope this help!!

Saturday, March 20, 2021

System.TypeException: Cannot have more than 10 chunks in a single operation

 While working on requirement where we have to perform DML on multiple object dynamically by using sobject, we got below error:

"System.TypeException: Cannot have more than 10 chunks in a single operation. Please rearrange the data to reduce chunking."

This kind of error appears if your list of sobject contains more than 10 types of object records or record of objects are not ordered based on object. For example if you are adding lead, account and contact record to sobject list by using below format:


This will be considered as 12 chunks on sobject and while performing DML, you will get this error.

If you want to avoid it, then rearrange the records in below format:


This sequence of records will be considered as 3 chunks and is allowed in single DML operation.

Execute below script and you will get this error:

List<sObject>  sbList=new List<sObject>();

for(integer i=0;i<10;i++){

    sblist.add(new Lead(lastname='Test Leat'+i,company='test company'+i));

    sblist.add(new Account(name='Test Account'+i));

    sblist.add(new Contact (lastname='test name'+i,email=''+i));


insert sblist;

Ways to resolve this kind of error:

  • Rearrange the records in list so that all records belonging to one object are stored together in list.

List<sObject>  sbList=new List<sObject>();
for(integer i=0;i<10;i++){
    sblist.add(new Lead(lastname='Test Leat'+i,company='test company'+i));
for(integer i=0;i<10;i++){
    sblist.add(new Account(name='Test Account'+i));
for(integer i=0;i<10;i++){
    sblist.add(new Contact (lastname='test name'+i,email=''+i));
insert sblist;

  • Sort the sobject list before performing DML

List<sObject>  sbList=new List<sObject>();
for(integer i=0;i<10;i++){
    sblist.add(new Lead(lastname='Test Leat'+i));
    sblist.add(new Account(name='Test Account'+i));
    sblist.add(new Contact (lastname='test name'+i,email=''+i));
insert sblist;

Hope this will help!!

Sunday, July 26, 2020

Compare CRUD (Object Level Access) Permission for a Profile from 2 different Org

Through this blog, I am going to share a script through which you can compare object level permission for a profile in 2 different SFDC orgs. This script is very helpful when you want to compare CRUD level permission for a profile in 2 different sandbox or permission in sandbox and production.

When you run below script, you will receive email with csv file with CRUD permission comparison.
You need to specify the target org domain url and sessionid or access_token of target org and need to run below script in source org in execute anonymous window in developer console.

Below is script:

Below is snapshot of csv file:


This is just a prototype and it may work for small organization. You need to consider heap size and apex CPU time limit exceeded errors. You can refractor this code for your use based on number of objects that you have in your org.

Hope this will help!!

Friday, June 26, 2020

Creating Package.xml from Changeset and Retrieving zip file containing Metadata using Workbench

We can utilize workbench to retrieve the package.xml and complete metadata in zip file for a changeset.

Navigate to "migration" and then click retrieve.

Enter changeset name. If you want to download package.xml for different changeset, then enter names seperated by comma.

Click on "next" button and then retrieve button.

Download zip file and after extracting the files, you will get complete metadata and package.xml.

Benefit of generating package.xml

Before deploying changeset to target org, you can extract package.xml from changeset. Now you can utilize this package.xml to extract metadta from target org before deployment which will work as backup for target org metadata. 
Suppose you have to rollback after actual deployment, then you can utilize backup taken using package.xml to redeploy the old metadata in production.

Hope this will help!!

Monday, April 27, 2020

Javascript Promise.all : Way to perform action when Multiple Parallel enqueued Actions are Completed in Lightning Components

As we all know that all actions from Lightning components are sent to server in asynchronous manner and we can not predict the sequence about response from server.

If we have requirement to wait for all operations to complete and then perform some action on lightning components like hiding the spinner or displaying all data at once.

We can either queue the first server call and when we get response then we perform second server call. For this you can use Javascript Promise pattern to sequence the server call. Please refer below URL for complete understanding of sequencing of server call using javascript promise.

JavaScript Promises vs Callback Functions in Lightning Components

Now if we need to fire server calls in parallel and want to wait for all response, then you can utilize promise.all methods to achieve this. This will execute many promises in parallel and wait until all of them are ready. Below is syntax to use promise.all:
//create array of promise and pass it to promise.all 
var promiseArray =[promise1, promise2];
var combinedPromise = Promise.all(promiseArray);
//this return single promise. Now handle it with then and catch
 //handle success
 var promise1Results = results[0]; //Results from Promise 1
 var promise2Results = results[1]; //Results from Promise 2
.catch($A.getCallback(function () { 
 //Handle errors on any promise here
 console.log('Some error has occured'); 

  • Promise.all takes an array of promises and returns a new promise.
  • The new promise resolves when all listed promises are settled, and the array of their results becomes its result.
  • Order of the resulting array members is the same as in its source promises. Even though the first promise takes the longest time to resolve, it’s still first in the array of results.
  • If any of the promises is rejected, the promise returned by Promise.all immediately rejects with that error.
  • For example, if there are multiple fetch calls and one fails, the others will still continue to execute, but Promise.all won’t watch them anymore. They will probably settle, but their results will be ignored. Promise.all does nothing to cancel them, as there’s no concept of “cancellation” in promises.
  • This will help to improve the performance of lightning components as server operations are not performed in sequential order. Due to parallel call to server, lightning components will perform better.
I have created a sample lightning component which fetch Account and Task records from server and displays it in UI only when both operations are completed and response is returned to lightning components. below is gif image displaying the lightning component functionality:

Below is complete snippet for your reference:

Hope this will help!!

Friday, April 17, 2020

Get the Content (Blob) of File from Box and Store/Manipulate it in Salesforce

Through this blog, I am going to share sample apex script through which you can get content of file from box as blob and then store or manipulate it within salesforce.

I have already written a blog to explain how to get box access token (needed for handshake with Box) and to display file content in salesforce in VF page without storing it in salesforce. You can cosider it as Mashup inSalesforce. Please refer below URL to that:

Box and Salesforce Integration

In order to get box file content, we need to have box file Id and box access token.

Box does not provide direct API to get file content. First you need to do callout to get download URL and then you perform another API callout to get file content. Also you perform another API call to get file details like filename in order to store it in salesforce.

I am going to store box file in salesforce library for demo purpose. You can store it as attachments or read the content on the fly to perform some logic instead of saving it.

Add below URLs in remote site settings before performing the callouts:

Below is required code and it is self explainatory as comments are mentioned for each methods:

Now run below script in developer console:

string boxFileId='6542xxx28604';
string access_token='0xxxxxxxxxxxxxxxxxxxxxxxxxxxredx0P';
string sfdcLibraryName='Box_File_Library';
string boxFilename= SK_BoxAPIUtilityClass.findFileNameFromBox(boxFileId,access_token);

Use Case

During sandbox refresh, all custom settings data gets refreshed from production values. So before refresh, you have to take back up each custom settings data and after refresh, you need to update the custom setting records. In order to automate this, you can write script through which you can push all custom setting data to box folder. Code to upload the files from Salesforce to box is already shared in blog  Box and Salesforce Integration.

Now we need to get the content of all csv files stored in box and update the custom setting in salesforce. Once you get the content of file, you can parse csv file and update custom settings.

Hope this helps!!!