Node JS Streaming API examples

In this blog, I am going to explain the how to test the node js application with Salesforce Streaming API. Here I am going to use the nforce, express, and socket.io along with ejs views. Please refer this link to understand the streaming API .Salesforce Streaming API

Step1: – I am assuming you already created a push topic in Salesforce as per the above link.

Step 2: Create a Connect App for authentication from App menu as shown below

Capture

Step 3: – Clone the Complete Repository from the git hub. here is the link
https://github.com/rajamohanvakati/Node-Js-Steaming-
Open auth.js file from Auth folder and update the details as shown below .

exports.PORT = 3001;
exports.DEBUG = true
exports.ENVIRONMENT = ‘production’;
exports.CALLBACK_URL = ‘http://localhost:3001’;
exports.PUSH_TOPIC = ‘OpportunityChannel’;
exports.CLIENT_ID =””;
exports.CLIENT_SECRET = “”;
exports.USERNAME = “”;
exports.PASSWORD = “”

Here is the index.js file that contains the logic to connect the Salesforce push topic and establish the socket connection. Once Streaming API topic is receiving any message then socket.io emit that message to index.ejs where we are showing the push notification. This is completed index.js

var express = require('express');
var nforce = require('nforce');
var path = require('path');
var app = express();

var server = require('http').Server(app);
// attach socket.io and listen
var io = require('socket.io')(server);

var config = require('./Auth/auth.js');
var sfConn = nforce.createConnection({
  clientId: config.CLIENT_ID, //Connected app clientId
  clientSecret: config.CLIENT_SECRET, // Connected app clientSecret
  redirectUri: config.CALLBACK_URL + '/oauth/_callback', // call back URL
  environment: config.ENVIRONMENT // optional, sandbox or production, production default
});
sfConn.authenticate({
  username: config.USERNAME, //  salesforce User name
  password: config.PASSWORD // Salesforce password
}, function(error, oauth) {
  if (error) return console.log(error);
  if (!error) {
    console.log('*** Successfully connected to Salesforce ***');
  }
  var streamingConnect = sfConn.stream({
    topic: config.PUSH_TOPIC,
    oauth: oauth
  });
  streamingConnect.on('connect', function() {
    console.log('Connected to pushtopic: ' + config.PUSH_TOPIC);
  });
  streamingConnect.on('error', function(error) {
    console.log('Error received from pushtopic: ' + error);
  });
  streamingConnect.on('data', function(data) {
    console.log('Received the following from pushtopic:');
    console.log(data);
    io.sockets.emit('records', data);
    console.log('after sent to emilt');

  });
});
app.set('port', process.env.PORT || 3001);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.get('/', function(req, res) {
  res.render('index');

})

server.listen(app.get('port'), function() {
  console.log('Express server listening on port %d in %s mode', app.get(
    'port'), app.get('env'));
});

In index.js once your receive the notification, you can broadcasting it by using socket emit method as show below

streamingConnect.on('data', function(data) {
    console.log('Received the following from pushtopic:');
    console.log(data);
   <strong> io.sockets.emit('records', data);</strong>
    console.log('after sent to emilt');

  });

The emitted message is reviving in views as show below


var socket = io(url);
socket.on('records', function (data) {
console.log(data);
console.log(data.sobject );
console.log(data.sobject.Id );

//var results = JSON.parse(data.sobject);
var streamList = $('ul.streams');

streamList.prepend('<br/> <li>' +
  data.sobject.Name + ' : ' + data.sobject.StageName +
   data.sobject.Amount + ': ' + data.sobject.ExpectedRevenue +'</li>');
});

Now you can run the app by simply two commands

npm install

node index.js

after that you can open “http://localhost:3001/ ” in the browser you will see the notification on the browser

Capture

Step 4: Pushing it to Heroku
you can push this app to Heroku with simple steps
Heroku login
Heroku create
git push heroku master
heroku ps:scale web=1
heroku open

 

 

 

 

 

 

 

 

 

 

 

 

Platform Events in Salesforce

In this blog post, I am going to explain about platform events a new feature generally available from Summer ’17 release as part of the “Enterprise Message Platform” which provide event driven architecture.

Let’s talk about Event Driven Architecture 

Salesforce event-driven architecture is consists of event producers, event consumers, and channels.  Platform events simplify the process of communicating changes and responding to events. Publishers and subscribers communicate with each other through events. One or more subscribers can listen to the same event and carry out actions .with an Event-driven architecture each service publishes an event whenever it updates or creates a data. Other services can subscribe to events.It enables an application to maintain data consistency across multiple services without using distributed transactions.  Let us take an example of order management. When the Order management app creates an Order in a pending state and publishes an OrderCreated event.The Customer Service receives the event and attempts to process an Order. It then publishes an OrderUpdate event.Then OrderUpdate Service receives the event from the changes the state of the order to either approved or canceled or fulfilled.The following  diagram show the event driven architect

Capture

Terminology : –
Event
A change in state that is meaningful in a business process. For example, a placement o of an order is a meaningful event because the order fulfillment center requires notification to process the order.
Event Notifier 
A message that contains data about the event. Also known as an event notification.
Event producer
The publisher of an event message over a channel.
Channel
A conduit in which an event producer transmits a message. Event consumers subscribe to the channel to receive messages.
Event consumer
A subscriber to a channel that receives messages from the channel. A change in state that is meaningful in a business process.

Looks like Streaming API, But Really not 

But when you overlook at Platform events it makes similar to Streaming API and most of the futures including the replayID and durability but below makes the difference between with streaming API.

  • Platform  events are special kinds of entity similar to custom object custom object
  • You can publish and consume platform events by using Apex or a REST API or SOAP API. Platform events integrate with the Salesforce platform through Apex triggers. Triggers are the event consumers on the Salesforce platform that listen to event messages.Unlike custom objects, you can’t update or delete event records. You also can’t view event records in the Salesforce user interface, and platform events don’t have page layouts. When you delete a platform event definition, it’s permanently deleted.
  • Platform events may be published using declarative tools (Process Builder)
  • platform events can also be subscribed to using APEX  or decoratively process builder  and flows

Another major,off-course really impressive one is you can publish changes from apex trigger and you can consume from apex trigger trigger

Publishing and subscribing Platform events 

Publishing and subscribing the platform event are more flexible. You can publish event messages from a Force.com app or an external app using Apex or Salesforce APIs and you can subscribe from the Salesforce or external apps or use long polling with cometD as well.

Let’s take an Example:- 

Now I am going to explain step by step to set up, publish and consume events. What we are going to do it Employee Onboarding Process. Now Once an external app publishes the events, we are going to create an account and when Salesforce publish onboarding events another system is going to receive the platform events.

Step 1: – Define a Platform event
You can define platform event similar like custom object, go to setup –> develope –> Platform events –> create new platfomr events as shown below.

Capture

By seeing it looks like custom objects but here are the few major considerations.

  • Platform event is appended the __e suffix for API name of the event.
  • you can’t query Platform events through SOQL or SOSL.
  •  you can’t use Platform in reports, list views, and search.
  •  published platform events can’t be rolled back.
  • e methods aren’t supported with platform events.
  • All platform event fields are read-only by default
  • Platform events don’t have an associated tab
  • Only after insert Triggers Are Supported
  • You can access platform events both through API and declaratively
  • You can control platform events though Profiles and permissions

Step 2: – Publishing Platform Events

You can publish events using an Apex method or with declarative tools, such as Process Builder or the Cloud Flow Designer or you can publish events using Salesforce API. we are going to seeing all the ways how to publish the platform events.

 Publish Using Apex:-
you can publish platform events by using apex trigger or execute anonymous and batch Apex etc.But here I am going to publish by using Apex triggers. A trigger processes platform event notifications sequentially in the order they’re received and trigger runs in its own process asynchronously and isn’t part of the transaction that published the event.

trigger PlatformEventPublish on Account (after insert , after update ) {

    If(trigger.isAfter && trigger.isUpdate){
        List<Employee_On_boarding__e> publishEvents = new List<Employee_On_boarding__e>();
        for(Account a : Trigger.new){
            Employee_On_boarding__e eve = new Employee_On_boarding__e();
            eve.Name__c = a.Name ;
            eve.Phone__c = a.Phone ;
            eve.Salary__c = a.AnnualRevenue ;
            publishEvents.add(eve);
        }
        if(publishEvents.size()>0){
            EventBus.publish(publishEvents);
        }

    }

}

 Now if you can see, Salesforce has a special class to publish the platform events EventBus which are having methods publish method. once the event is published you can consume the events from the channel

Publish Using Process Builder 

You can publish platform events using the declarative tools like process builders and flows. Here is the image shows the platform events insert by using process builder.

Capture

Publish Events by Using API
Now I am going to see another way of publishing events from API. I am going to use the workbench to publish the events.
Capture

 

Step 3: – Subscribe for Platform events from the channel
You can now subscribe the platform events from the Platform events object trigger which is created in step 1. Here is the sample trigger show how you can handle the subscribed events.Here simply I am creating the new accounts from the platform even but you can implement your own business logic to update the data .

trigger OnBoaringTrigger on Employee_On_boarding__e (after insert) {
    List<Account> acc = new List<Account>();
    for(Employee_On_boarding__e oBording :trigger.new){
        acc.add(new Account(Name =oBording.Name__c , Phone =oBording.Phone__c , AnnualRevenue = oBording.Salary__c));
    }
    if(acc.size() >0){
        insert acc ;
    }
}

Here is the simple visual force page that consumes the platform events which you published. This page is built on cometD.
you can consume the platform events by using this  URI /event/Employee_On_boarding__e and the Complete code is here below.

 <apex:page standardStylesheets="false" showHeader="false" sidebar="false">

<apex:includeScript value=”{!$Resource.cometd}”/> <apex:includeScript value=”{!$Resource.jquery}”/> <apex:includeScript value=”{!$Resource.json2}”/> <apex:includeScript value=”{!$Resource.jquery_cometd}”/> (function($){ $(document).ready(function() { $.cometd.configure({ url: window.location.protocol+’//’+window.location.hostname+ (null != window.location.port ? (‘:’+window.location.port) : ”) +’/cometd/40.0/’, requestHeaders: { Authorization: ‘OAuth {!$Api.Session_ID}’} }); $.cometd.handshake(); $.cometd.addListener(‘/meta/handshake’, function(message) { $.cometd.subscribe(‘/event/Employee_On_boarding__e’, function(message) { var div = document.getElementById(‘content’); div.innerHTML = div.innerHTML + ‘

Notification

‘ + ‘Streaming Message ‘ + JSON.stringify(message) + ‘
‘; }); }); }); })(jQuery) </apex:page>

Key points:-
1 . Platform events are executed under ” Automated Process entity.” So you have set Automated Process in debug logs
2. You can control the Platform events on Profile and permission sets
3.You can see all the platform events that are subscribed under Platform events objects.
Capture
4. Platform events have lifecycles state like Running, Ideal, Suspended,, Error, Expired
5.Platform events are having retry mechanism.

if (EventBus.TriggerContext.currentContext().retries &lt; 4) {
// Condition isn't met, so try again later.
throw new EventBus.RetryableException(
'Condition is not met, so retrying the trigger again.');
} else {
// Trigger was retried enough times so give up and
// resort to alternative action.
// For example, send email to user.
}

 

 

 

 

 

 

 

 

 

Salesforce DocuSign Integration

In this blog, I am going to explain how to use DocuSign’s API in Salesforce. DocuSign is having support for both the SOAP and REST API support. This article is the target for DocuSign SOAP API only.
What you are going to learn in this article are.
 How to use DocuSign API
How to create a template for DocuSign signature requests / e-sign
How to integrate it with APEX

Pre Requisitions:

         DocuSign Account – Register from  (https://www.docusign.com)

         DocuSign For Salesforce Package installed and configured.

Let’s get started.

Step 1:  Download DocuSign WSDL.

        Go to the below URL and download the DocuSign WSDL file.

       https://www.docusign.net/api/3.0/schema/dsapi.wsdl

 Step 2: Generated Apex Class from WSDL.

        In order to create the Apex class from DocuSign WSDL, I am utilizing Salesforce WSDL to apex class features.

        Go to Setup – > Develop – > Apex Classes – >generate from WSDL -> Chose the downloaded DocuSign WSDL

Step 3: Remote Site Settings

        Add below URL to remote Site settings. Remote site settings URL will differ from the DocuSign Sandbox vs. DocuSign Production 

          https://www.docusign.net

Step 4: Generate template for your e-signature.

        You can able to use any of static documents or visual force pages for DocuSign e-sign documents. 

        Now you are going to create a visual force page pdf that needs to send for DocuSign signature.

The below code is the key are in a visual force page which used to capture the recipient signature and print name and date.

 

           

By Completeing DocuSign, You are agreed  terms and Conditions .

           

Customer Name: (Please print) cstnamtag

       

Signed: Signaturetag

       

Date: signdatetag

 

On the above code, three id tags are there namely cstnamtag , Signaturetag and signdatetag .We will use these tags to place signature and Date and print name on DocuSign e-copy document.  

Step 5: triggering the e- signature.

   Here is the sample button that used to send the DocuSign to the end user.

On Click of Send DocuSign, button end user will receive an email with attachment need to be signed. 

Step 6: Docu Sign Terminology and Code Walkthrough

  Some common terms you need to understand. 

Document

    A digital file that contains content to be reviewed and/or signed or initialed by one or more recipients. DocuSign accepts almost all document types – for example .pdf, .docx, .rtf, .png – and you can store multiple documents in a single envelope.

Envelope

      An envelope is a container or “package” that is used to send documents to recipients and manage transactions. Envelopes have statuses (i.e. sent, delivered, completed, voided) and typically contain documents, recipients, and tabs.  

Recipient

       Someone who receives an envelope and, depending on the settings, can sign the documents or add information where indicated by tabs. Recipients do not need a DocuSign account to sign or participate in transactions, and there are seven (7) different recipient types available in the platform. When you embed document signing into your UI your recipients are known as embedded recipients; users who sign through the DocuSign website are known as remote recipients.

Tab

        A DocuSign Tab – also called a Field or Tag – are used in several ways. First, they are used to indicate to a recipient where a signature or initials are required.

Second, tabs can be used to show data or information to recipients, such as dates, company names, titles, etc.

Third, tabs may be used as editable information fields where signers can add data to a document.

Code Walkthrough. 

 Below piece shows BLOB that will send as Document through DocuSign 

   Blob SignDocument= Blob.valueOf(' '); 
        PageReference pr = new PageReference('/apex/DocuSignDynamicGeneration') ;
        SignDocument = pr.getContentAsPDF();

Below piece of code shows the Authentication for DocuSign API. 

   DocuSignAPI.APIServiceSoap dsApiSend = new DocuSignAPI.APIServiceSoap();
        dsApiSend.endpoint_x = webServiceUrl;
        dsApiSend.timeout_x=120000;

        String auth = '&amp;amp;amp;amp;amp;lt;DocuSignCredentials&amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;lt;Username&amp;amp;amp;amp;amp;gt;'+ userId 
            +'&amp;amp;amp;amp;amp;lt;/Username&amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;lt;Password&amp;amp;amp;amp;amp;gt;' + password 
            + '&amp;amp;amp;amp;amp;lt;/Password&amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;lt;IntegratorKey&amp;amp;amp;amp;amp;gt;' + integratorsKey 
            + '&amp;amp;amp;amp;amp;lt;/IntegratorKey&amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;lt;/DocuSignCredentials&amp;amp;amp;amp;amp;gt;';

        dsApiSend.inputHttpHeaders_x = new Map&amp;amp;amp;amp;amp;lt;String, String&amp;amp;amp;amp;amp;gt;();
        dsApiSend.inputHttpHeaders_x.put('X-DocuSign-Authentication',auth);

Below piece of code shows  how to create an Envelope and Document for doucSIgn 


        DocuSignAPI.Envelope envelope = new DocuSignAPI.Envelope();
        envelope.Subject    = 'DocuSign from Raj'; 
        envelope.EmailBlurb = 'Review review the documnet and sign ';
        envelope.AccountId  = accountId;

        DocuSignAPI.Document document = new DocuSignAPI.Document();
        document.ID                     = 1;
        document.pdfBytes               = EncodingUtil.base64Encode(SignDocument);
        document.Name                   = 'Contract infomration';
        document.FileExtension          = '.pdf';
        envelope.Documents              = new DocuSignAPI.ArrayOfDocument();
        envelope.Documents.Document     = new DocuSignAPI.Document[1];
        envelope.Documents.Document[0]  = document;

Below piece of code shows the how to set recipient details 


        DocuSignAPI.Recipient recipient = new DocuSignAPI.Recipient();
        recipient.ID            = 1;
        recipient.Type_x        = 'Signer';
        recipient.RoutingOrder  = 1;
        recipient.Email         = 'aaaaaaaa@gmail.com';
        recipient.UserName      = 'aaaaaaaaaaaaaaaa';
        recipient.SignerName    = 'Raj ';

        DocuSignAPI.Recipient recipient1 = new DocuSignAPI.Recipient();
        recipient1.ID = 2;
        recipient1.Type_x = 'CarbonCopy';
        recipient1.RoutingOrder = 1;
        recipient1.UserName = 'mohan'; 
        recipient1.Email =  'aaaaaaaaaaaaaaa.v@gmail.com'; 

        DocuSignAPI.Recipient recipient2 = new DocuSignAPI.Recipient();
        recipient2.ID = 3;
        recipient2.Type_x = 'CarbonCopy';
        recipient2.RoutingOrder = 1;
        recipient2.UserName = 'Raj '; 
        recipient2.Email =  'aaaaaaaaaaaaaaaa@outloo.com'; 

Below code shows how to place the signed and Print name and date of DocuSign Documents that need to be signed by the user .


        DocuSignAPI.Tab tab1                = new DocuSignAPI.Tab();
        tab1.Type_x                         = 'SignHere';
        tab1.RecipientID                    = 1;
        tab1.DocumentID                     = 1;
        tab1.AnchorTabItem                  = new DocuSignAPI.AnchorTab();
        tab1.AnchorTabItem.AnchorTabString  = 'Signaturetag';

        DocuSignAPI.Tab tab2                = new DocuSignAPI.Tab();
        tab2.Type_x                         = 'DateSigned';
        tab2.RecipientID                    = 1;
        tab2.DocumentID                     = 1;
        tab2.AnchorTabItem                  = new DocuSignAPI.AnchorTab();
        tab2.AnchorTabItem.AnchorTabString  = 'signdatetag';

        DocuSignAPI.Tab tab4                = new DocuSignAPI.Tab();
        tab4.Type_x                         = 'FullName';
        tab4.RecipientID                    = 1;
        tab4.DocumentID                     = 1;
        tab4.AnchorTabItem                  = new DocuSignAPI.AnchorTab();
        tab4.AnchorTabItem.AnchorTabString  = 'cstnamtag';

finally creating envelop that will trigger an email to user and store in DocuSign Magamed Package object “dsfs__DocuSign_Status__c” to track the Status like Send, Completed and Voided or decline etc. 


        DocuSignAPI.EnvelopeStatus EnvStatus = dsApiSend.CreateAndSendEnvelope(envelope);
        String envelopeId = EnvStatus.EnvelopeID;

        dsfs__DocuSign_Status__c DocStatus      = new dsfs__DocuSign_Status__c();
        DocStatus.dsfs__DocuSign_Envelope_ID__c = envelopeId;
        DocStatus.dsfs__Sender__c               = userinfo.getusername();
        DocStatus.dsfs__Sender_Email__c         = userinfo.getuseremail();
        DocStatus.dsfs__Subject__c              = envelope.Subject;
        DocStatus.dsfs__Envelope_Status__c  = EnvStatus.status;
        insert DocStatus;

Step 7: tracking status for DocuSign.

Once DocuSign is sent to the User, you can track the DocuSign status on dsfs__DocuSign_Status__c t.

Complete code URL.

https://github.com/rajamohanvakati/DocuSign

 

 

 

 

Salesforce Apex Convert Lead

In many of the business cases, you may want control lead conversion process through apex trigger or your may need to build your own lead conversion process . in this post, we are going to see how to control the lead conversion from the apex trigger.

What happens when the lead is converted?

  • A contact, account, and opportunity are created and populated with the lead’s data
    The lead field “Converted” is changed from False to True.
  • The data within standard lead fields is automatically transferred to the contact, account, and/or opportunity. For Custom Field use Lead mapping
  • In general on lead conversion, if you wanted to perform any custom logics like then you will go for apex lead conversion.
    Here are some of the use cases.
    1.Checking Account Industry and SIC mapping against your company mapping
    2.On lead Conversion, if you wanted to auto subscribe specific user the record for chatter feed
    3. Sending new or updated account information to ERP or etc.
    Here is the simple job that will convert leads. You can schedule this class to perform the automatic lead conversion
  global class LeadConversionJob implements Schedulable {
    global void execute(SchedulableContext sc){
        List&amp;amp;lt;Lead&amp;amp;gt; leads = [Select Id , Name,Company  from lead where LeadSource='Web' ];

        List&amp;amp;lt;Database.LeadConvert&amp;amp;gt; lcList = new List&amp;amp;lt;Database.LeadConvert&amp;amp;gt;();
        for(Lead l :leads){
            Database.LeadConvert lc = new Database.LeadConvert();
            lc.setLeadId(l.id);
            lc.ConvertedStatus = 'Closed - Converted';
            lcList.add(lc);
        }
        List&amp;amp;lt;Database.LeadConvertResult&amp;amp;gt; lcr = Database.convertLead(lcList);      
        for(Database.LeadConvertResult lcrRes : lcr){
            if(lcrRes.isSuccess()){

            }else{
                //error handling here 
            }

        }

    }

}

If you would like to perform some of the operations on after lead is conversion or to perform some of the business requirements, you write apex trigger as shown below.

Apex Trigger:-

 trigger LeadConversion on Lead (after update) {

    LeadConversionHandler.convertLead(Trigger.newMap , Trigger.oldMap);

}

Apex Class

public class LeadConversionHandler {

    public static void convertLead(Map&lt;Id, Lead&gt; newLead , Map&lt;Id ,Lead&gt; oldLead){
        for(Id idNew :newLead.keySet()){
            If(newLead.get(idNew).isConverted== true &amp;&amp;  oldLead.get(idNew).isConverted== false){
                If(newLead.get(idNew).ConvertedAccountId!=null){
                    // Use your logics here
                    Account a = [Select a.Id, a.Description From Account a Where a.Id = :newLead.get(idNew).ConvertedAccountId];

                }     
                If(newLead.get(idNew).ConvertedContactId!=null){
                    // Use your logics here 
                    Contact c = [Select c.Id, c.Description, c.Name From Contact c Where c.Id = :newLead.get(idNew).ConvertedContactId];
                }
                If(newLead.get(idNew).ConvertedOpportunityId!=null){
                    // use your logics here 
                    Opportunity opp = [Select o.Id, o.Description from Opportunity o Where o.Id = :newLead.get(idNew).ConvertedOpportunityId];

                }
            } 

        }

    }

}

 

 

 

Inside Action Link Templates

In this blog post,  I am going to give an overview of the Action Link Templates and its conceptual knowledge. Action link is a button with some action on a feed element which is having a capability to a redirect Web page, initiate a file download, or invoke an API call to Salesforce or to an external server  like  when you want to post a survey link to salesforce chatter feed or you wanted to approve or reject travel or expense from the chatter feed are few use cases of action link templates .

Terminology :-  

Action Links: – An action link is a button on a feed element. Clicking an action link can take a user to a  Web page, initiate a file download, or invoke an API call to Salesforce or to an external server. Action links on chatter post can allow you to integrate your chatter feed with Salesforce and third-party services into the feed.

Action Link Templates: –  Action like the template is the place when you can define your server-side execute logic decoratively by using context variables and binding variables. You can use template binding keys in the Action URL, HTTP Request Body, and HTTP headers fields to make an APIcall. Suppose on click on button user need to send an SMS from the feed, in this case, you can defined the URL to send SMS and body and Header and other authentication parameters in Action link template by using binding variables and context variables.you can specify  binding variables in the template at the time of  instantiate the action link group. You can also specify context variables in the templates like who is executes the action link, Salesforce provides values for these variables, such as who executed the link and in which organization

Action Link Group Template: – To associate an action link with a feed element, you need to create an action link group template which is a collection of Action link templates. With the action link group template, you can able to control the Action links location on chatter feed like primary or overflow.

Types of Action Link: –With Action link template you can choose the different type of action as describes below .you can specify the action link type in the actionType property when you define an action link.

• Api—The action link calls a synchronous API at the action URL.

For example Approve Expenses, Travel request.

• ApiAsync—The action link calls an asynchronous API at the action URL.

For example  Upload Files, send SMS etc

• Download—The action link downloads a file from the action URL.

For example Download file from Dropbox, Box, etc.

• Ui—The action link takes the user to a Web page to the action URL.

For example View Map, open Visual Force Page, Canvas Page, etc.

Action link appearance: – While designing you action link templates you can specify the chatter feed item location by using Category property . it can be one of  Primary or Overflow.

If you specify the Category as Primary then action link will appear on Feed-item Body

If you specify the Category as  Overflow then Feed-item Detail Menu.

dtxY01494460173

Declarative Binding: –Not always you no need to pass the static data for the action link template while designing .you can identify the key areas where you need to make changes dynamically replace those by using Binding variables or context variables.

Use context variables to pass information about the user who executed the action link and the context in which it was invoked into the HTTP request made by invoking an action link. You can use context variables in the actionUrl, headers, and requestBody properties of the Action Link Definition Input request body or ConnectApi.ActionLinkDefinitionInput object.

Use binding variables in templates and set their values when you instantiate an action link group. Use binding variables to add sensitive information at run time.  You can define binding variables in the Action URL, HTTP Request Body, and HTTP Headers fields of an action link template. After a template is published, you can edit these fields, you can move binding variables between these fields, and you can delete binding variables. However, you can’t add new binding variables. Define a binding variable’s key in the template. When you instantiate the action link group, specify the key and its value.

Action link URL  with Bindings

https://www.example.com/!Bindings.ApiVersion/items/!Bindings.ItemId

Action Link Header with Bindings

Authorization: OAuth {!Bindings.OAuthToken}
Content-Type: {!Bindings.ContentType}

The lifetime of Action links: –  Setting up expiration data on action link template is easy to maintain suppose let’s consider you are posting a survey link to feed that should be available only specific time. these type of requirements you can set with hours until expiration value. The expiration date can be calculated based on a period provided in the template, or the action link group can be set not to expire at all. To set the hours until expiration in a template, enter a value in the Hours until Expiration field of the action link group template. This value is the number of hours from when the action link group is instantiated until it’s removed from associated feed elements and can no longer be executed. The maximum value is 8760, which is 365 days.

Who can Execute and how many times?

Choose a value from the User Visibility drop-down list to determine who can see the action link after it’s associated with a feed element. Among the available options are Only Custom User Can See and Everyone Except Custom User Can See. Choose one of these values to allow only a specific user to see the action link or to prevent a specific user from seeing it. Then enter a value in the Custom User Alias field. This value is a binding variable key. In the code that instantiates the action link group, use the key and specify the value as you would for any binding variable. You can decide how many time each user wanted to execute action link by setting execution allowed with any one of values as unlimited, Once Per User, Once.

 

 

 

Handling “MIXED_DML_OPERATION” with future calls

 You can run “MIXED_DML_OPERATION” error when you are trying to perform DML on setup and non-setup objects in the same transaction.This restriction exists because some sObjects affect the user’s access to records in the org.Non-Setup objects are standard objects like Account or any custom object.  here is the few Setup Object
  • ObjectPermissions
  • PermissionSet
  • PermissionSetAssignment
  • QueueSObject
  • ObjectTerritory2AssignmentRule
  • ObjectTerritory2AssignmentRuleItem
  • RuleTerritory2Association
  • SetupEntityAccess
  • Territory2
  • Territory2Model
  • UserTerritory2Association
  • User
  • GroupMember
  • FieldPermissions

Use case: – Once “Customer Satisfaction Survey” is completed we need to assign it to the  “Internal_Employee” group. Here is the simple trigger


 trigger ServeyTrigger on Customer_Satisfaction_Survey__c (after insert) {
    Group g=[select Id from Group Where DeveloperName='Internal_Employee'];

    List&amp;amp;amp;amp;lt;GroupMember&amp;amp;amp;amp;gt;listGroupMember =new List&amp;amp;amp;amp;lt;GroupMember&amp;amp;amp;amp;gt;();
    for (Customer_Satisfaction_Survey__c cs  : Trigger.new){
        GroupMember gm= new GroupMember();
        gm.GroupId=g.id;
        gm.UserOrGroupId = UserInfo.getUserId();
        listGroupMember.add(gm);
    }
    insert listGroupMember;

}

 

Once you try to insert the new records you will get the below error message

Review all error messages below to correct your data.
Apex trigger ServeyTrigger caused an unexpected exception, contact your administrator: ServeyTrigger: execution of AfterInsert caused by: System.DmlException: Insert failed. First exception on row 0; first error: MIXED_DML_OPERATION, DML operation on setup object is not permitted after you have updated a non-setup object (or vice versa): GroupMember, original object: Customer_Satisfaction_Survey__c: []: Trigger.ServeyTrigger: line 11, column 1

To solve this problem simply you can add the Second DML into future call

  1. Create a method that performs a DML operation on one type of sObject.
  2. Create a second method that uses the future annotation to manipulate a second sObject type.

Now update the trigger as shown below

trigger ServeyTrigger on Customer_Satisfaction_Survey__c (after insert) {
  ServeyAsyncCall.assignToUser(trigger.newMap.keySet());
}

Apex Class:

 

 public class ServeyAsyncCall {
    @future
    public static void assignToUser(Set&amp;lt;Id&amp;gt; setofIds){
        Group g=[select Id from Group Where DeveloperName='Internal_Employee'];
        List&amp;lt;Customer_Satisfaction_Survey__c&amp;gt; records =[Select Id , Name from Customer_Satisfaction_Survey__c where id in:setofIds];
        List&amp;lt;GroupMember&amp;gt;listGroupMember =new List&amp;lt;GroupMember&amp;gt;();
        for (Customer_Satisfaction_Survey__c cs  :records){
            GroupMember gm= new GroupMember();
            gm.GroupId=g.id;
            gm.UserOrGroupId = UserInfo.getUserId();
            listGroupMember.add(gm);
        }
        if (!Test.isRunningTest()) {
            insert listGroupMember;
        }
    }
}

Apex Test Class:- 

@isTest
private class ServeyAsyncCall_test {

    private static testMethod  void bypassMixedDML(){
        // You can insert the user with @future  for this test method . But in this test class simply i queried
        // InsertUser.callInsertfuture()
        User thisUser = [SELECT Id FROM User WHERE Id = :UserInfo.getUserId()];
        System.runAs (thisUser) {

            Customer_Satisfaction_Survey__c cs = new Customer_Satisfaction_Survey__c();
            cs.Comments__c='Hello' ;
            cs.Name='Test Class';
            insert cs ; 

        }
    }
}

Asynchronous calls with @Future

In this blog, I am going to how to make the asynchronous calls with @Future annotations .with the Future annotation you can make asynchronous Web service callout to an external service.A future method runs in the background, asynchronously. You can call a future method for executing long-running operations, such as callouts to external Web services or any operation you’d like to run in its own thread, on its own time.

What is Asynchronous Process in Salesforce 

An asynchronous process is a process or function which does not require interaction with a user. It can be used to execute a task “in the background” without the user having to wait for the task to finish. Force.com features such as Asynchronous Apex (@future), Batch Apex, Bulk API, Reports and other features use asynchronous processing to efficiently process requests.Each future method is queued and executes when system resources become available. That way, the execution of your code doesn’t have to wait for the completion of a long-running operation. A benefit of using future methods is that some governor limits are higher, such as SOQL query limits and heap size limits.

Use Case: – Upon Creation of Account Record, you need to validate the billing address of account and update latitude and longitude values.

Solution: – Create a trigger of account on after insert and after update.  Invoke  an asynchronous Webservice call with @future annotation to validate the address against google API and return latitude and longitude

Trigger :- 

trigger AccountTriger on Account (after insert) {

    AccountUpdateAsync.updateAccountAddress(Trigger.new[0].Id);

}

Apex Class:-

 public class AccountUpdateAsync {
    @future(callout=true)
    public static void updateAccountAddress(String accId){
        Account acc = [Select Id , Name ,Location__Latitude__s  , Location__Longitude__s, 
                       BillingStreet ,BillingCity ,BillingState ,BillingPostalCode,
                       BillingCountry from Account where id =:accId Limit 1];

        String httpReqURI = 'https://maps.googleapis.com/maps/api/geocode/json?address='+
            acc.BillingStreet+','+acc.BillingCity+','
            +acc.BillingState+','+acc.BillingPostalCode+','+
            acc.BillingCountry
            +'&amp;key=&lt;API_KEY&gt;';
        HttpResponse response = sendHttpReq(httpReqURI);

        if (response.getStatusCode() == 200) {
            JSONParser parser = JSON.createParser(response.getBody());
            Map &lt;String, Object&gt; root = (Map &lt;String, Object&gt;) JSON.deserializeUntyped(response.getBody());
            List &lt;Object&gt; childLevel = (List&lt;Object&gt;) root.get('results');
            for( Object o : childLevel){
                Map &lt;String, Object&gt; childLevel2 = (Map &lt;String, Object&gt;) o;
                Map &lt;String, Object&gt; grandChaildLevel= (Map &lt;String, Object&gt;) childLevel2.get('geometry');
                Object objFinal = grandChaildLevel.get('location');
                Map&lt;String, Object&gt; locs = (Map&lt;String, Object&gt;)objFinal;
                acc.Location__Latitude__s = (Decimal)locs.get('lat') ; 
                acc.Location__Longitude__s = (Decimal)locs.get('lng');
                update acc;
            }

        }

    }

    public static HttpResponse sendHttpReq(String url){
        Http http = new Http();
        HttpRequest request = new HttpRequest();
        request.setEndpoint(url);
        request.setMethod('GET');
        HttpResponse response = http.send(request);
        return response;

    }

    public static  void parseJson(String json){

    }

}

Future method Considerations:- 

Below are the future method considerations

  1. Methods with the future annotation must be static methods and can only return a void type.
  2. The specified parameters must be primitive data types, arrays of primitive data types, or collections of primitive data types. No sObjects or objects as arguments
  3. The future method does not necessarily execute in the same order it is called.
  4. Methods with the future annotation cannot be used in Visualforce controllers in either getMethodName or setMethodName methods, nor in the constructor.
  5. You cannot call a method annotated with future from a method that also has the future annotation
  6. future calls cannot be made from a batch job
  7. future calls can execute concurrently

 

Best Practices:-

future methods are having its own advantages.  Consider this below best practices while implementing the future calls

  1. Make @future  code is efficient as possible. Long execution times increase the chance of delays and extended delays.
  2.  Minimize the number of the asynchronous requests created to minimize the chance of delay and extended delays.
  3. Make sure you are not invoking too many future calls when you are invoking from the trigger . I would advice one future call for one trigger transaction.
  4. Avoid recursive behavior in future calls.Use a static variable to store the state of the trigger processing
  5. Consider using Batch Apex instead @future to process a large number of records asynchronously.
  6. asynchronous processing framework is queue-based, lower priority than real-time interaction Best practice – ensure @future requests execute as fast as possible and remember limits: 10 @futures each making at most 10 callouts.

 

Limits :-

Future calls have below limits

  1. No more than 10 @future method calls per Apex invocation.
  2. You’re limited to 50 future calls per Apex invocation, and there’s an additional limit on the number of calls in a 24-hour period.  The maximum number of future method invocations per a 24-hour period is 250,000 or the number of user licenses in your organization multiplied by 200, whichever is greater. Still, all salesforce licenses are not applicable fo this limits . for examples chatter licenses are not part of this.  More limits you can refer in salesforce limits guide.