REST – ABSYZ https://absyz.com Salesforce Gold Consulting and Implementation Partner Fri, 27 Nov 2020 10:52:20 +0000 en-US hourly 1 https://absyz.com/wp-content/uploads/2020/06/cropped-favicon-1-1-32x32.png REST – ABSYZ https://absyz.com 32 32 REST API call from Einstein Analytics Dashboard https://absyz.com/rest-api-call-from-einstein-analytics-dashboard/ https://absyz.com/rest-api-call-from-einstein-analytics-dashboard/#comments Tue, 26 May 2020 06:22:34 +0000 http://blogs.absyz.com/?p=11219

In Einstein Analytics we can create a lens and dashboard with the dataset available in your analytics studio. You have a dataset that is created from the dataflow which is scheduled every hour to update the dataset. Here your dataset might not have the updated data for every second or minute. What if you want to get the live data from Salesforce or any external system or handling complex solution when it is not possible in analytics to be shown on your dashboard. Using the apex step type in Dashboard JSON we can achieve displaying the manipulated data or real-time data.

Using SOQL from Dashboard

Scenario 1: The user wanted to show the real-time data from salesforce on the analytics dashboard. It is simple to achieve, just follow the steps mentioned. So we create an apex step in the dashboard and using ‘@restresource’ in apex call we fetch the data to the dashboard. Create an apex class as AnalyticsDashboardStep with restResource name as accountdata. Define a @HttpPost method that will return the value to the dashboard JSON. So your code will look as shown below.

@RestResource(urlMapping='/accountdata')
global with sharing class AnalyticsDashboardStep {
    @HttpPost 
    global static String fetchAccount(String selectedIndustry) { 
         //selectedIndustry - attribute value passed from the analytics Dashboard
         //return the output
    } 
}

Define a wrapper that parses the data to the dashboard JSON. The WrappedData wrapper creates a mapping between the parameters defined and the queried fields of account. The ReturnMetadata wrapper is to define the data type for each returned column. The ChartFormatJSON wrapper is to combine the data(rows) and header(columns).

    public class WrappedData{
        public String Account_Name;
        public String Account_Id;
        public String Account_Industry;
        public String Account_AccountSource;
        public Decimal Account_AnnualRevenue;
        public WrappedData(){}
        public WrappedData(Account data){
            this.Account_Name = data.name;
            this.Account_Id = data.Id;
            this.Account_Industry = data.Industry;
            this.Account_AccountSource = data.AccountSource;
            this.Account_AnnualRevenue = data.AnnualRevenue;
        }
    }
    public class ReturnMetadata {
        public List<String> strings; // columns that return as text
        public List<String> numbers; // columns that return as numeric
        public List<String> groups;  // columns that return as groups
        public ReturnMetadata(List<String> strings, List<String> numbers, List<String> groups) {
            this.strings = strings;
            this.numbers = numbers;
            this.groups = groups;
        }
    }
    public class ChartFormatJSON {
        public List<WrappedData> data;
        public ReturnMetadata metadata;
        public ChartFormatJSON(List<WrappedData> data) {
            this.data = data;
            this.metadata = new ReturnMetadata(new List<String>{'Account_Id','Account_Name','Account_Industry'}, 
                                                new List<String>{'Account_AnnualRevenue'}, new List<String>{'Account_Name'});
        }   
    }

Since your wrapper parameters are set up, now pass the values in the @HttpPost fetchAccount method as stated above. In the below method we have a queried List of accounts as a return statement to the Dashboard. For the complete class check this link.

    @HttpPost 
    global static String fetchAccount(String selectedIndustry) {
        List<Account> dataDisplay = new List<Account>();
        List<WrappedData> wrpData = new List<WrappedData>();
        // If the Industry is not selected from the interaction step
        if (selectedIndustry == null) {
            dataDisplay = [select Id,Name,Industry,AnnualRevenue,AccountSource from account order by AnnualRevenue desc];
        }else{
            dataDisplay = [select Id,Name,Industry,AnnualRevenue,AccountSource from account where industry=:selectedIndustry order by AnnualRevenue desc];
        }
        for(Account acc : dataDisplay){
            wrpData.add(new WrappedData(acc));
        }  
        //Serialize the wrapper that you have created with account data
        return JSON.serialize(new ChartFormatJSON(wrpData));
    }

Once your apex class is ready, move to the analytics studio to create a dashboard with an apex step. Create a toggle with filter values as Account Industry. Follow the below steps to create a dashboard.

In the new dashboard if you have completed the above steps, click ctrl + E in windows or command + E in Mac to edit your Dashboard JSON. Add the apex step as shown below. The GetChartData is the query name in the dashboard. In the query parameter, you set the body value as an apex input parameter named selectedIndustry that holds the value selected from the dashboard. Define the apex class name in the path parameter and apex in the type parameter.

"GetChartData": {
	"query": {
		"body": {
			"selectedIndustry": "Agricultrue"
		},
		"path": "accountdata"
	},
	"type": "apex"
},

If you want to pass the selected industry value dynamically then use interaction syntax that can be generated from the advance editor of the GetChartData query. Edit your query value with “{{cell(Industry_1.selection, 0, \”Industry\”).asString()}}” to pass the value dynamic. You can use both Result or Selection type of interaction.

"GetChartData": {
     "query": {
          "body": {
                "selectedIndustry": "{{cell(Industry_1.selection, 0, \"Industry\").asString()}}"
          },
          "path": "accountdata"
     },
     "type": "apex"
},

Click on Done after completing the JSON edit. You can see the GetChartData query in the query list on your right-hand side of the dashboard. Drag the query to the dashboard building area. To get the full dashboard JSON click here.

Dashboard Output:

dashboard output1

REST API call from Dashboard

Scenario 2: Similarly, the user wanted to show the live updates from an external system to your analytics dashboard, then we do an apex REST API call to fetch the details whenever the dashboard is loading or refreshing. Here we have taken an example of COVID ’19 to show the number of updated cases in India. So we are using https://api.covid19india.org API to fetch the COVID updated details. Similarly, you can choose your API according to your necessity.

It is similar to scenario 1, whereas here we are creating an apex class with REST API callout and passing the parameters in the same format that is required for the dashboard. Add the URL in remote site settings.

Create two custom labels with the details mentioned below:

  • Custom Label 1
    • Name: CovidBaseEndpoint
    • Value: https://api.covid19india.org/
  • Custom Label 2
    • Name: CovidStateWise
    • Value: /data.json

CustomLabel

The next step is to create an apex class to make an Http request and get the response. The getStateWiseData method makes an API request and is serialized to the dashboard through the data_val method. Notice PackagedReturnItem wrapper where we have categorized the columns as a string, number, and group in ReturnMetadata.

@RestResource(urlMapping='/covid')
global with sharing class CovidData {
    @HttpPost  // Annotation Specified to highlight that this method needs to be called.
    global static String data_val() {
    	CovidStatusCoreData1 data = getStateWiseData();
        return JSON.serialize(new PackagedReturnItem(data.statewise));
    }
    
    public static CovidStatusCoreData1 getStateWiseData() {
        String BaseEndpoint = System.Label.covidBaseEndpoint; //Retrieve the endpoint and statewise variable from custom label
        String StateWise = System.Label.covidStateWise;
        HttpResponse resp = makeAPICallout(BaseEndpoint,StateWise);
        CovidStatusCoreData1 response = (CovidStatusCoreData1)System.JSON.deserialize(resp.getbody(), CovidStatusCoreData1.class);
        if (response != null) {
            return response;
        }
        return null;
    }
    public static HttpResponse makeAPICallout(String BaseEndpoint,String StateWise) {
        Http h = new Http();			//Make a request with the parameters set
        HttpRequest req = new HttpRequest();
        String endpoint = BaseEndpoint + StateWise;
        req.setEndpoint(endpoint);
        req.setMethod('GET');
        HttpResponse res = h.send(req);		// Send the request, and return a response
        if (res.getStatusCode() == 200 ) {
            return res;
        }
        return null;
    }
    public class ReturnMetadata {
        public List<String> strings; 
        public List<String> numbers; 
        public List<String> groups;  
        public ReturnMetadata(List<String> strings, List<String> numbers, List<String> groups) {
            this.strings = strings;
            this.numbers = numbers;
            this.groups = groups;
        }
    }
    public class PackagedReturnItem {
        public List<StateWiseData> data;
        public ReturnMetadata metadata;
        public PackagedReturnItem(List<StateWiseData> data) {
            this.data = data;
            this.metadata = new ReturnMetadata(new List<String>{'state','statecode','lastupdatedtime'}, 
                                               new List<String>{'active','recovered','deaths','confirmed','deltaconfirmed','deltadeaths','deltarecovered'}, 
                                               new List<String>{'state'});
        }   
    }  
    public class CovidStatusCoreData1 {
        public List<DailyKeyValues> key_values;
        public List<StateWiseData> statewise;
    }
    public class DailyKeyValues {
        public String confirmeddelta;
        public String counterforautotimeupdate;
        public String deceaseddelta;
        public String lastupdatedtime;
        public String recovereddelta;
        public String statesdelta;
    }
    public class StateWiseData {
        public Integer active;
        public String confirmed;
        public String deaths;
        public String recovered;
        public String state;
        public String statecode;
        public String lastupdatedtime;
        public String deltaconfirmed;
        public String deltadeaths;
        public String deltarecovered;
    }
}

Create an apex step GetChartData in dashboard JSON to display the data. After placing the apex step click on done from the dashboard. Place the query on top of the table widget as shown below.

"GetChartData": {
	"query": {
		"body": {},
		"path": "covid"
	},
	"type": "apex"
},

covid states

In the final step, we have created a Static step to filter by states in India. To show a different type of output chart in the dashboard pass the wrapper from the apex class. Set the ReturnMetadata string, number, and group by columns correctly so that you could see the correct output when you place the query in the chart widget. Likewise, create the apex classes to fetch the data and display it in different chart types as shown in the below dashboard. Refer to the link for the apex classes and dashboard JSON. Using the dashboard inspector we can check the output for each lens that helps us to identify the performance and time taken for the query. Click on show details for a query that will show the details on your right-hand side panel.

There you go! you are on the last step to verify your dashboard, check the clip below.

[wpvideo RHIjNB4j]

NOTE: When you work with API apex step in analytics dashboard remember you have certain limits provided by salesforce that you can refer here. Firstly, Maximum concurrent Analytics API calls per org limit as 100. Secondly, Maximum Analytics API calls per user per hour limit as 10,000.

]]>
https://absyz.com/rest-api-call-from-einstein-analytics-dashboard/feed/ 3
How to schedule a report from an apex class https://absyz.com/how-to-schedule-a-report-from-an-apex-class/ https://absyz.com/how-to-schedule-a-report-from-an-apex-class/#respond Wed, 19 Sep 2018 09:28:55 +0000 http://blogs.absyz.com/?p=9339

In this blog, I am going to take you through the process of how to schedule a report from apex class. While I was working on my last project I came across a scenario where I need to schedule a report from the apex. This blog takes you through the simplest way possible to achieve this requirement.

Using analytics REST API we can do the following things :

  1. Create, update and retrieve the Salesforce Report and Dashboard.
  2. Modify and schedule trends in Analytics report snapshot.
  3. Retrieve a list of dataset versions.
  4. Retrieve a list of dependencies for an application.

In order to schedule a report first, we need to understand ‘reports’ namespace.

Reports namespace contain a number of classes through which we can avail the same level of data access as in case of using Salesforce Reports and DashBoards REST API.

There are two ways of running a report through apex.

  1. Synchronously
  2. Asynchronously

Synchronous Way of running  reports:

If you want to run reports synchronously we have to use ReportManager class. In this, we need to use runreport() Method. The Return type of this report must be ReportResult class. This class contains results after running a report.

Check the below code for running report synchronously.

[sourcecode language=”java”]
public class ScheduleReport {

public ScheduleReport(){

list reportList=[select id, name from report where name=’DemoReport’’];

// To get the report Id.

string reportId=(string) reportList.get(0).get(‘Id’);

//To Run the report.

reports.ReportResults reportResult=reports.ReportManager.runReport(reportId, true);

system.debug(‘reportResult—&gt;’+reportResult);

}

}
[/sourcecode]

Asynchronously way of running reports:

If you want to run reports asynchronously we have to use ReportManager class similar to Synchronous way of running reports. Here you need to use runAsyncReport() method instead of runReport() method.

Advantages of running reports Asynchronously:

  1. We can lower the risk of reaching the timeout limit when we run reports.
  2. Salesforce API timeout limit does not apply for asynchronous runs.
  3. Salesforce Reports and dashboards API can handle higher number of asynchronous run requests at a time.

Check the below code to Schedule a report Asynchronously

[sourcecode language=”java”]
public class ScheduleReport {

public ScheduleReport(){

list reportList=[select id, name from report where name=’DemoReport’’];

string reportId=(string) reportList.get(0).get(‘Id’);

Reports.ReportInstance instance = Reports.ReportManager.runAsyncReport(reportId, true);

System.debug(‘Asynchronous instance: ‘ + instance);

}

}
[/sourcecode]

Now we need to write a schedulable class to schedule our report.

Below is the code for schedule class.

[sourcecode language=”java”]
global class ScheduleReportClass implements Schedulable{

global void Execute(SchedulableContext context){

ScheduleReport sch=new ScheduleReport();

}

}
[/sourcecode]

Let us consider a scenario where I need to schedule a report every weekday at 1PM.

Below is the code for scheduling

[sourcecode language=”java”]
ScheduleReportClass sch=new ScheduleReportClass();
string cronExp=’0 0 13 ? * MON-FRI’;
system.schedule(‘schedule report’, cronExp, sch);

[/sourcecode]

]]>
https://absyz.com/how-to-schedule-a-report-from-an-apex-class/feed/ 0
Google Assistant Integration with Salesforce – Part 2 https://absyz.com/google-assistant-integration-with-salesforce-part-2/ https://absyz.com/google-assistant-integration-with-salesforce-part-2/#comments Fri, 07 Sep 2018 06:13:16 +0000 http://blogs.absyz.com/?p=9202

Let suppose when the Intent creation is ready, you want the custom data as a reply in Google assistant, we overwrite the intent from Apex call. You can add a custom response from Salesforce to Google assistant. We fetch the record names from the Salesforce org and overwrite the response in the intent.

[sourcecode language=”java”]
@RestResource(urlMapping=’/Dialogflow’)
global class restCall {
@HTTPPost
global static string fetchRecords(){
//response from Google Assistant as a JSON
String request = RestContext.request.requestBody.toString();
mapurl orp = (mapurl)JSON.deserialize(request, mapurl.class);
string str=orp.result.metadata.intentName;
string givenInt=orp.result.parameters.number1;
string outputstring=”;
String accountList=”;
if((str.contains(‘New’)||(str.contains(‘Add’)) ||(str.contains(‘Create’))) &&(str.contains(‘Account’))){
outputstring=’Congratulations Account is created successfully’;
postWebhook.postCallout(outputstring);
string lastname=orp.result.parameters.Name;
string phone=orp.result.parameters.phone;
string email=orp.result.parameters.Email;
account acc= new account();
acc.name=lastname;
acc.Phone=phone;
acc.Email__c=email;
insert acc;
}
else if((str.contains(‘get ‘)) && (str.contains(‘Account’))){
Integer num = Integer.valueof(givenInt);
accList = [select name from Account order by createddate limit :num];
for(Account a: accList)
{
accountList=accountList+ ‘ ‘ + a.name;
}
postWebhook.postCalloutquery(accountList);
}
String s= ‘Success’;
return s;
}
global class mapurl{
global result result;
}
global class result{
global parameters parameters;
global metadata metadata;
global string resolvedQuery;
}
global class parameters{
global String number1;
global String Phone;
global String Name;
global String Email;
}
global class metadata{
global String intentName;
}
}
[/sourcecode]

Access token to be used in salesforce org is as shown below:

Capture34.PNG

So when a response is received from Google assistant we make a call to an apex method to edit the intent. The below class is to edit the intent with our data from salesforce.

In the below code you can see a string that is passed to request.setBody where you can try to get it from postman or some related apps. In the JSON we edit our intent data that should overwrite the data in the Google Intent.

[sourcecode language=”java”]
global class postWebhook {

global static void postCallout(string outputstring){
string accessToken=’Here we have to use the developer Access token’;
//The below Text is the response from postman. dont use the same it will throw error
string text = ‘{“id”: “332b2bf0-a53e-4b3e-b03c-986cbe8ee00e”,”name”: “yes”,”auto”: true,”contexts”: [],”responses”: [{“resetContexts”: false,”affectedContexts”: [],”parameters”: [],”messages”: [{“type”: 0,”speech”: “‘+str1+'”}],”defaultResponsePlatforms”: {},”speech”: []}],”priority”: 500000,”cortanaCommand”: {“navigateOrService”: “NAVIGATE”,”target”: “”},”webhookUsed”: false,”webhookForSlotFilling”: false,”lastUpdate”: 1526896421,”fallbackIntent”: false,”events”: [],”userSays”: [{“id”: “1ff25907-2b72-4866-ae96-c1dca66e9747″,”data”: [{“text”: “sure”}],”isTemplate”: false,”count”: 0,”updated”: 1526896421,”isAuto”: false},{“id”: “b95c226f-4b36-4ba3-849d-824fb44a0bc0″,”data”: [{“text”: “yes”}],”isTemplate”: false,”count”: 0,”updated”: 1526550631,”isAuto”: false}],”followUpIntents”: [],”endInteraction”: True,”templates”: []}’;
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setEndPoint(‘Here you have to set the endpoint URL which is Dialogflow Api URL’);
request.setMethod(‘PUT’);
request.setHeader(‘content-type’, ‘application/json’);
request.setHeader(‘Accept-Language’, ‘application/json’);
request.setHeader(‘Authorization’, ‘Bearer ‘+accessToken);
request.setBody(text);
HTTPResponse response = new HTTP().send(request);
}
global static void postCalloutquery(string accountList){
string accessToken=’241b07a2d7eb4f82a31158bb6e310d35’;
string text = ‘{“id”: “2b641bce-bdf7-4b6c-8637-0388a05f71af”,”name”: “True”,”auto”: true,”contexts”: [],”responses”: [{“resetContexts”: false,”affectedContexts”: [],”parameters”: [],”messages”: [{“type”: 0,”speech”: “‘+ listOf +'”}],”defaultResponsePlatforms”: {},”speech”: []}],”priority”: 500000,”cortanaCommand”: {“navigateOrService”: “NAVIGATE”,”target”: “”},”webhookUsed”: false,”webhookForSlotFilling”: false,”lastUpdate”: 1526900788,”fallbackIntent”: false,”events”: [],”userSays”: [{“id”: “06833ebd-5581-4b35-b23b-c655231605ad”,”data”: [{“text”: “True”}],”isTemplate”: false,”count”: 0,”updated”: 1526900594,”isAuto”: false}],”followUpIntents”: [],”endInteraction”: True,templates”: []}’;
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setEndPoint(‘https://api.dialogflow.com/v1/intents/2b641bce-bdf7-4b6c-8637-0388a05f71af’);
request.setMethod(‘PUT’);
request.setHeader(‘content-type’, ‘application/json’);
request.setHeader(‘Accept-Language’, ‘application/json’);
request.setHeader(‘Authorization’, ‘Bearer ‘+accessToken);
request.setBody(text);
HTTPResponse response = new HTTP().send(request);
}
}
[/sourcecode]

So create an intent as shown below and you find the intent will be changed when the method is called.

You can test it from the Google assistant Simulator as shown below.

Capture4.PNG

Now you are all set with your Google assistant intent that your action is ready to deploy into production. Few more steps to be followed. Click on overview in the Actions on Google page.

Capture21.PNG

This is to setup your app and upload it to the production. When it is uploaded to production, everyone will be able to access the custom app. The first step is the quick setup:

 

The second step is to build you App:

The third step is get ready for Deployment:

The final step is to submit your application to the production as shown below.

If any doubts feel free to reach out to us.

]]>
https://absyz.com/google-assistant-integration-with-salesforce-part-2/feed/ 13
Google Assistant Integration with Salesforce – Part 1 https://absyz.com/google-assistant-integration-with-salesforce-part-1/ https://absyz.com/google-assistant-integration-with-salesforce-part-1/#comments Thu, 30 Aug 2018 09:56:57 +0000 http://blogs.absyz.com/?p=9171

Everyone has come across Google Assistant which help people in communication that is a Google’s voice-controlled AI smart assistant. Google Assistant is integrated with Salesforce, to make communication easy and reduce the work. Here we do a simple integration with Salesforce to create, delete and fetch details of a particular record.

First, we should sign up Dialogflow.api with your Gmail account. Click on signup for free. You will be redirected to a page asking for the sign in with Google. Sign up with existing Gmail account and you can see the redirected page that logins into dialogflow.com. And create an agent (a project) for a custom development.

Four terminologies to know:

  1. Intent
  2. Entities
  3. Fulfillment
  4. Integrations

Intent:

Intent maps the user input commands with related actions for your app. Intent allows the users to specify what they wanted to do and figures out what activity matches what was said. Click on Intent that is on your left and click on create new Intent as shown below.

Absyz

Entities:

Entities are used for extracting parameter values from the user inputs and any important data that you wanted to get from the user, you will create the corresponding entity. It is not necessary to create all possible concepts as entities, entities are created only for the actionable data that is needed. To create an Entity check the below images.

Absyz

Fulfillment:

Fulfillment allows us to decide our responses to our conversations. It is a conversational interface between your application and the logic to fulfill the action. For example, we integrate with Salesforce and Google Assistant. We need to create a site from salesforce org as shown below (Site -Custom URL is used because we need to get a public access to the apex class from our org). Enter the domain URL in Fulfillment Webhook URL and append the URL with the rest resource name.

Absyz cloud

Integration:

Integration is to use Dialogflow’s Actions on Google integration to test your Dialogflow agent in the Actions on Google simulator. Click on Integration in the left menu and select Integration Settings. Enable Auto-Preview changes as the dialogflow will propagate changes to the Actions Console and Assistant Simulator automatically. Now you are all set to test your custom app.

Absyz

We create an apex class with the annotation @RestResource in the class because we expose an apex class as a REST resource. If we use RestResource, that particular class should be defined as global. In the brackets, we provide the rest resource name. We are extracting the data from the JSON so you can get the key terms whether you want to insert, update or delete records.

[sourcecode language=”java”]
@RestResource(urlMapping=’/Dialogflow’)
global class restCall {
@HTTPPost
global static string createRecords(){
//response from Google Assistant as a JSON
String request = RestContext.request.requestBody.toString();
//deserialize the JSON
mapurl orp = (mapurl)JSON.deserialize(request, mapurl.class);
string str=orp.result.metadata.intentName;

//check whether it is an account
if((str.contains(‘New’)||(str.contains(‘Add’)) ||(str.contains(‘Create’))) &&(str.contains(‘Account’))){
account acc= new account();
acc.name=orp.result.parameters.Name;
acc.Phone=orp.result.parameters.phone;
acc.Email__c=orp.result.parameters.Email;
insert acc;
}
//check whether it is a contact
else if((str.contains(‘New’)||(str.contains(‘Add’)) ||(str.contains(‘Create’))) &&(str.contains(‘Contact’))){
contact con= new contact();
con.LastName = orp.result.parameters.Name;
con.Phone = orp.result.parameters.phone;
con.Email = orp.result.parameters.Email;
insert con;
}
String s= ‘Success’;
return s;
}
//wrapper to get the values from the JSON
global class mapurl{
global result result;
}
global class result{
global parameters parameters;
global metadata metadata;
global string resolvedQuery;
}
global class parameters{
global String Phone;
global String Name;
global String Email;
}
global class metadata{
global String intentName;
}
}
[/sourcecode]

On click of Test from Integration setting, it will redirect to a page called simulator. Google allows you to test in a browser without an actual google home device named Google Home Web Simulator. You have not yet named your custom App so initially, the command will be: “Talk to Test app”. The setup to create your application name and use the app live will be continued in our next blog.

]]>
https://absyz.com/google-assistant-integration-with-salesforce-part-1/feed/ 7
Salesforce Integration with LinkedIn https://absyz.com/salesforce-integration-with-linkedin/ https://absyz.com/salesforce-integration-with-linkedin/#comments Thu, 15 Mar 2018 09:52:57 +0000 https://teamforcesite.wordpress.com/?p=8633

Posting message to social media through Salesforce makes it easy as Salesforce provide all flexibility in developing customer relationships. Posting and getting information from one of the social media helps to increase the number of customers and achieve targets.

Let suppose any company is having their LinkedIn page where users should log in and upload status or image. Instead, we can promote, improve sales, hire people and much more through Salesforce. Here we can upload and retrieve posts from LinkedIn to Salesforce using REST API. LinkedIn provides API calls for developers that can be referred in the documentation (https://developer.linkedin.com/docs). Developers can also test the callouts using LinkedIn REST Console.

First, create a LinkedIn account and proceed to create a company page as shown below.

Now to access LinkedIn we need to create an app. For that, you need to keep your account active.

link4.PNG
click on My Apps to create an app

Fill in the details and submit.

After submitting go to Application settings -> Authorization where you will get the client key and client secret key. Provide permissions for the application and authorized redirect link to OAuth 2.0 as shown below.

link9.PNG

To register the user go to the REST API console and click on the drop-down menu Authentication select OAuth 2.0. On clicking on it you are asked to redirect to user to access your basic LinkedIn profile information. Click on allow to access basic information. If you are unable to get the page then refer the link given (https://developer.linkedin.com/docs/oauth2). Enter the URL in the console to get access token. Currently, all access tokens are issued with a 60-day lifespan.

We have a different way of accessing the LinkedIn like to Sign In with LinkedIn,  post on LinkedIn, Manage company pages and added details to Profiles. Here we are doing POST and GET method to an XXX company page. In this link, we have all the details how to manage our company page (https://developer.linkedin.com/docs/company-pages).

From Salesforce I provide status, link, and image fields to do a POST method to LinkedIn. The image is given in an URL format. When the button is clicked it gets posted to LinkedIn.

POST Method

First, add the link to remote site settings as specified in the code. Identify your company id in the URL of that page like this – https://www.linkedin.com/company/12345678/. Send these parameters through callout to LinkedIn as a JSON format. In the response, we get the status updated Id.

[sourcecode language=”java”]
public static void postRequest(String post,String link,String image){
String NewLine=’\n’;
String NewLinereplace=’ ‘;
String newPost=post.replace(NewLine, NewLinereplace);
if(image!=null)
{
// pass the values in JSON format
String text = ‘{“visibility”: { “code”: “anyone” },”comment”: “‘+newPost+'”,”content”: {“submitted-url”: “‘+link+'”,”submitted-image-url”:”‘+image+'”}}’;
HttpRequest req = new HttpRequest();
//https://api.linkedin.com – add the link to remote site settings
//12345678 – give your company id
//oauth2_access_token – provide your access token
req.setEndpoint(‘https://api.linkedin.com/v1/companies/12345678/shares?format=json&oauth2_access_token=AQW…QQqA&format=json’);
req.setMethod(‘POST’);
req.setHeader(‘Content-Type’ , ‘application/json’);
req.setBody(text);
//Make request
Http http = new Http();
HTTPResponse res = http.send(req);
system.debug(‘response’+res.getBody());//in response we get posts id
}
else
{
//pass the values in JSON format
String text = ‘{“visibility”: { “code”: “anyone” },”comment”: “‘+newPost+'”,”content”: {“submitted-url”: “‘+link+'”}}’;
HttpRequest req = new HttpRequest();
//https://api.linkedin.com – add the link to remote site settings
//12345678 – give your company id
//oauth2_access_token – provide your access token
req.setEndpoint(‘https://api.linkedin.com/v1/companies/1234567/shares?format=json&oauth2_access_token=AQW…QQqA&format=json’);
req.setMethod(‘POST’);
req.setHeader(‘Content-Type’ , ‘application/json’);
req.setBody(text);
//Make request
Http http = new Http();
HTTPResponse res = http.send(req);
system.debug(‘response’+res.getBody());//in response we get posts id
}
}
[/sourcecode]

GET Method

To GET, we make an API call out to with company Id and access token

[sourcecode language=”java”]
public static void getRequest(){
HttpRequest req = new HttpRequest();
//https://api.linkedin.com – add the link to remote site settings
//12345678 – give your company id
//oauth2_access_token – provide your access token
req.setEndpoint(‘https://api.linkedin.com/v1/companies/12345678/updates?oauth2_access_token=AQW…QQqA&format=json’);
req.setMethod(‘GET’);
//Make request
Http http = new Http();
HTTPResponse res = http.send(req);
//resopnse body we get the information in JSON format containing id and message
system.debug(‘response’+res.getBody());
}
[/sourcecode]

From Salesforce

We get Status, Link, and Image URL from the user.

[sourcecode language=”java”]
<aura:component controller=”PosttoSocialMediaEXT” implements=”force:appHostable, flexipage:availableForAllPageTypes, flexipage:availableForRecordHome, force:hasRecordId, forceCommunity:availableForAllPageTypes, force:lightningQuickAction” access=”global”>
<aura:attribute name=”status” type=”String”/>
<aura:attribute name=”link” type=”String”/>
<aura:attribute name=”image” type=”String”/>
<aura:attribute name=”LinkedIn” type=”Boolean” default=”false”/>
<lightning:card title=”Social Media Post”>
<div class=”slds-align_absolute-center”>
<aura:set attribute=”title”>
<div style=”width:40%;”>
<div class=”slds-align_absolute-center”>
<p style=”font-family:serif;font-size: 40px;”>Social Media Post</p>
</div>
</div>
</aura:set>
<div style=”width:40%;”>
Post Message:
<lightning:textarea label=”” name=”myTextArea” value=”{!v.status}”
maxlength=”1000″ />
Post Link:
<lightning:textarea label=”” name=”myTextArea” value=”{!v.link}”
maxlength=”300″ />
Post Image Link:
<lightning:textarea label=”” name=”myTextArea” value=”{!v.image}”
maxlength=”300″ /><br/>
<div>
<lightning:input type=”checkbox” label=”Add To LinkedIn” name=”LinkedId” checked=”{!v.LinkedIn}” />
</div>
<div class=”slds-align_absolute-center”>
<lightning:button variant=”brand” label=”Submit” onclick=”{! c.handleClick }” />
</div>
</div>
</div>
</lightning:card>

</aura:component>
[/sourcecode]

From Salesforce, through javascript controller, we pass the values to apex methods.

[sourcecode language=”java”]
({
handleClick : function(component, event, helper) {

var action = component.get(“c.postStatus”);
action.setParams({ Post : component.get(“v.status”),
link : component.get(“v.link”),
image : component.get(“v.image”),
linkdIn : component.get(“v.LinkedIn”),
});
action.setCallback(this,function(response){
var State = response.getState();
if(State = ‘SUCCESS’){
var toastEvent = $A.get(“e.force:showToast”);
toastEvent.setParams({
“title”: “Success!”,
“message”: “The Status has been updated successfully.”
});
toastEvent.fire();
}
});
$A.enqueueAction(action);
}
})
[/sourcecode]

OUTPUT

User fill the details

link12

The post on LinkedIn as shown below.

If you have any questions please feel free to post it in the comment.

]]>
https://absyz.com/salesforce-integration-with-linkedin/feed/ 2
Einstein Intent and Einstein Sentiment Analysis on Facebook Posts https://absyz.com/einstein-language-facebook-integration/ https://absyz.com/einstein-language-facebook-integration/#comments Thu, 01 Mar 2018 06:58:09 +0000 https://teamforcesite.wordpress.com/?p=8594

Einstein Language

Einstein Language Is used to build natural language processing into your apps and unlock insights within text. Einstein Language contains two NLP services:

Einstein Intent

—Categorize unstructured text into user-defined labels to better understand what users are trying to accomplish. Leverage the Einstein Intent API to analyze text from emails, chats, or web forms to

  • Determine which products prospects are interested in, and send customer inquiries to the appropriate sales person.
  • Route service cases to the correct agents or departments, or provide self-service options.
  • Understand customer posts to provide personalized self-service in your communities.
Einstein Sentiment

—Classify the sentiment of text into positive, negative, and neutral classes to understand the feeling behind text. You can use the Einstein Sentiment API to analyze emails, social media, and text from chat to:

  • Identify the sentiment of a prospect’s emails to trend a lead or opportunity up or down.
  • Provide proactive service by helping dissatisfied customers first or extending promotional offers to satisfied customers.
  • Monitor the perception of your brand across social media channels, identify brand evangelists, and monitor customer satisfaction.

 

Lets suppose I have a Facebook Page for an E-Commerce site. If any user sharing their feedback through posts or comments on the page, We can retrieve the post and comments to Salesforce and find Intent of the post and the Sentiment of the comments.

This can be achieved by following these steps:

step 1. Create a Facebook page.

step 2. Create a Facebook app using Facebook Developers account.

To Connect with Facebook we Should use Graph API, To use Graph API we need to Create a Facebook Developers account using Facebook credentials,

To create a Facebook app

  • login to https://developers.facebook.com/
  • click on My Apps -> Add a New App.

Enter basic information and make the App Live, If the app is not Live we can’t use it for Communicating with Facebook.

Now click on Tools & Support and go to Graph API Explorer, here we can generate Access token and test the app.

Steps to create Access token:
  • select you app from Application drop down.
  • click on Get Token and select Get User Access Token.
  • select the permissions required and click Get Access Token.
  • To get Page Access token click on Get Token and select you Page from Page Access Tokens.
  • Now you can see your page name on the drop down list, click on that and select Request publish_pages.

 

step 3. Create an Object on Salesforce to save posts and their comments.

Create an object with fields to store posts, comments, Sentiment, Intent.

step 4. Create remote site setting on Salesforce.

Go to Remote Site Settings -> New Remote Site

enter site name, remote site URL as https://graph.facebook.com , check Active checkbox and Save.

step 5. Make a callout to Facebook to retrieve posts and comments.

In Einstein_Facebook class we are getting post and comments from Facebook, and extracting posts and comments from returned JSON and creating records.

 

[sourcecode language=”java”]
public class Einstein_Facebook {

public static void sendRequest(){

//getting accesstoken from custom lable.
String accessToken = Label.Facebook_Access_Token;
HttpRequest request = new HttpRequest();
request .setEndpoint(‘https://graph.facebook.com/v2.12/391648194596048?fields=posts{message,comments,type}&access_token=’+accessToken);
request .setMethod(‘GET’);
//Making request
Http http = new Http();
HTTPResponse response= http.send(request );
//getting post and comments in response.
String data=response.getBody();

//getting post and comments from JSON rceived in response.
List line=data.split(‘,’);
List posts=new List();
List postAndComments=new List();
for(String l:line){
posts.add(l.substringBetween(‘{“message”:”‘,'”‘));
string substring=l.substringBetween(‘”message”:”‘,'”‘);
if(substring!=null)
postAndComments.add(substring);
}
//creating a Map of posts and comments.
Map PostComments =new Map();
for(String p:posts){
if(p!=null){
List empty=new List();
PostComments.put(p,empty);
}
}
String key;
Listcomments=new List();
for(string messages : postAndComments){

//checking if the message exists in posts and adding as key.
if(messages!=null){
if(PostComments.containsKey(messages)){
key = messages ;
}

//else adding to comments to corresponding post.
else{
comments=PostComments.get(key);
comments.add(messages);
PostComments.put(key, comments);
}
}
}

//querying all the Posts and comments
List existingPosts = [SELECT id,Comments__c,Posts__c FROM Einstein_Facebook__c];
List listDelete = new List();
for(Einstein_Facebook__c Post:existingPosts){

//checking if post already exists and adding to a list.
if(PostComments.containsKey(Post.Posts__c)){
listDelete.add(Post);
}
}

//deleting the list.
delete listDelete;

List  PostCommentList=new List();
//Iterating through Map to create records.
for(string post : PostComments.keySet()){
for(string comments : PostComments.get(post)){
Einstein_Facebook__c Facebookcomment=new Einstein_Facebook__c();
Facebookcomment.Posts__c=post;
Facebookcomment.Comments__c=comments ;
PostCommentList.add(Facebookcomment);}
}

//Inserting List of  posts and comments.
insert PostCommentList;

}

}
[/sourcecode]

step 6. Write a trigger to get Intent and sentiment of post and comments.

Trigger to fire after insert on Facebook posts and comments:

[sourcecode language=”java”]

trigger EinsteinFB_Trigger on Einstein_Facebook__c (after insert) {    For(Einstein_Facebook__c post : Trigger.New)

{

String  postId = post.Id;

Einstein_Handler.getProbabilityforFB(postId);

}

}

[/sourcecode]

Handler for the trigger:

Here we are using EinsteinVision_Admin EinsteinVision_Sentiment classes to get Intent and Sentiment of posts and comments which we explained in detail in our previous blog on Einstein Intent and Einstein Sentiment.

[sourcecode language=”java”]
global class Einstein_Handler{

@future(callout=true)
Public static void getProbabilityforFB(String body){
Einstein_Facebook__c fd=[select Posts__c, Comments__c from Einstein_Facebook__c where id=:body];

String intentLabel = EinsteinVision_Admin.getPrediction(fd.Posts__c);
String sentimentLabel = EinsteinVision_Sentiment.findSentiment(fd.Comments__c);

fd.Feedback_Type__c=intentLabel;
fd.Sentiment__c=sentimentLabel;
update fd;
}

}
[/sourcecode]

This is a report to show analysis of Facebook post and comments.

facebook report

]]>
https://absyz.com/einstein-language-facebook-integration/feed/ 4
Dynamically Changing Filters in Reports using Analytical API https://absyz.com/dynamically-changing-filters-in-reports-using-analytical-api/ https://absyz.com/dynamically-changing-filters-in-reports-using-analytical-api/#comments Fri, 30 Sep 2016 06:49:52 +0000 https://teamforcesite.wordpress.com/?p=3252
Scenario :-

Let us Assume there are 3  representatives  working under the same territory . Now based on the selection of each representative in VisualForce page , his data should be displayed in the report  .

The Reports and Dashboards REST API gives you programmatic access to your report and dashboard data and to visualize the  data.

The Analytics API has been made available in Apex in the Spring ’14 release (API version 30).  and available for use in pages with an API version of 29 and above.

Here, in this case, we would use Analytical API to access the reports and make some changes(Update the report)  in report names ,filters ,folder etc.. for above scenario whenever the representative is changed ,we will change the filter value as that selected representative and  save changes to a report through  HTTP callouts  by sending a PATCH request to the Report resource.

This PATCH request /services/data/v29.0/analytics/reports/****000000JgMf to the Report resource ,updates and saves the report.

Filter a report chart by fields in addition to field filters already in the report to get specific data. Note that a report can have up to 20 field filters. A filter has these attributes in the form of a JSON string:

  • column: The API name of the field that you want to filter on.
  • operator:The API name of the condition you want to filter a field by. For example, to filter by “not equal to,” use the API name “notEqual.”
  • value: The filter criteria.

{column:’ OWNER ’,

operator:’ equals ’,

value:’ Representative Name ’}

While using the Reports and Dashboards, REST API with a POST request body, we  must use content-type: application/JSON. We might get unexpected results if we don’t use this content type.

Check the below sample code :
  Callout for getting report data

[sourcecode language=”java”]
Httprequest req= new HttpRequest();
req.setEndpoint(URL.getSalesforceBaseUrl().toExternalForm()+
‘/services/data/v29.0/analytics/reports/*****000000JgMf/’);
req.setMethod(‘GET’);
req.setHeader(‘Content-Type’,’application/json’);
req.setHeader(‘Authorization’,’Bearer’+UserInfo.getSessionID());
Http httpReq = new Http();
HttpResponse res =httpReq.send(req);
string body =res.getBody();
[/sourcecode]

Callout for updating the Report:

 

[sourcecode language=”java”]
Httprequest reqt =new HttpRequest();
reqt.setEndpoint(URL.getSalesforceBaseUrl().toExternalForm()+’/services
/data/v34.0/analytics/reports/*****000000JgMf?_HttpMethod=PATCH’);
reqt.setMethod(‘POST’);
reqt.setbody(newbody);
reqt.setHeader(‘Content-Type’,’application/json’);
reqt.setHeader(‘Authorization’,’Bearer ‘+UserInfo.getSessionID());
Http httpReq2= new Http();
HttpResponse ress=httpReq2.send(reqt);
[/sourcecode]

Before making any callouts please add Endpoint URL in Remote site settings, please check Setup->Security->Remote site settings

Select Satish lokin from the list of Representatives and now refresh the report to view the changes in Account owner filter value.

VF Page

 

screen-shot-2016-09-29-at-23-47-58

Check the Logic for the above example

[sourcecode language=”java”]
public with sharing class DynamicController {

public String RepName { get; set; }
public PageReference changeOwer() {
//Getting the report data
Httprequest req= new HttpRequest();
req.setEndpoint(URL.getSalesforceBaseUrl().toExternalForm()+’/services/data/v29.0/analytics/reports/00O90000009BCxY/’);
req.setMethod(‘GET’);
req.setHeader(‘Content-Type’,’application/json’);
req.setHeader(‘Authorization’,’Bearer ‘+UserInfo.getSessionID());
Http httpReq = new Http();
HttpResponse res =httpReq.send(req);
string body =res.getBody();
system.debug(‘ReportStr’+body);

//The Logic will be changed based on te requirement
body = body.subStringBetween(‘”reportMetadata”‘, ‘}}’);
string subString = body.subStringBetween(‘”column”:”USERS.NAME”,’, ‘}’);
System.debug(‘Chek’+subString);
string newBody = ‘”operator”:”equals”,”value”:”‘+RepName+'”‘;
string LatestBody = body.replace(subString, newBody);
string PostBody = ‘{“reportMetadata”‘+LatestBody+’}}}’;
System.debug(‘PostBody’+PostBody);
//Updating the Report
Httprequest reqt =new HttpRequest();
reqt.setEndpoint(URL.getSalesforceBaseUrl().toExternalForm()+’/services/data/v34.0/analytics/reports/00O90000009BCxY?_HttpMethod=PATCH’);
reqt.setMethod(‘POST’);
reqt.setbody(PostBody);
reqt.setHeader(‘Content-Type’,’application/json’);
reqt.setHeader(‘Authorization’,’Bearer ‘+UserInfo.getSessionID());
Http httpReq2= new Http();
HttpResponse ress=httpReq2.send(reqt);

return null;
}
}
[/sourcecode]

[sourcecode language=”HTML”]
<apex:page controller=”DynamicController”>
<apex:form >
<h> Select any Representative</h>
<apex:selectList multiselect=”false” value=”{!RepName}” size=”1″>
<apex:actionSupport event=”onchange” action=”{!changeOwer}”/>
<apex:selectOption itemLabel=”–None–” itemValue=”–None–“/>
<apex:selectOption itemLabel=”Alex” itemValue=”Alex”/>
<apex:selectOption itemLabel=”Shar” itemValue=”Shar”/>
<apex:selectOption itemLabel=”Satish Lokin” itemValue=”Satish lokin”/>
</apex:selectList>
</apex:form>
</apex:page>
[/sourcecode]

All limits that apply to reports created in the report builder also apply to the API,  For more information, see “Salesforce Reports and Dashboards Limits”

Related links:

View Code in GitHub

Analytical API Documentation

]]>
https://absyz.com/dynamically-changing-filters-in-reports-using-analytical-api/feed/ 2