Apex – 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 Apex – 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
Displaying standard report data in Lightning component https://absyz.com/displaying-standard-report-data-in-lightning-component/ https://absyz.com/displaying-standard-report-data-in-lightning-component/#respond Mon, 30 Dec 2019 15:37:25 +0000 http://blogs.absyz.com/?p=10822

Sometime we might end up the slow performance of showing custom charts by querying the object data- if the data is in millions. The best way to improve the performance is by creating a standard report and getting data of report to apex with ReportManager class.
we can also pass the filter values based on your requirement and display charts in the Lightning component with the help of Javascript chartCanvas class.

 

blog-4

FYI : The above charts are constructed with standard reports- Matrix and Summary type.

 

 

 

 

 

 

 

 

 

We need to consider some standard classes.

ReportManager class helps to run a report synchronously or asynchronously.

ReportResults class contains the results of running a report.

ReportFilter class contains information about a report filter, including column, operator, and value.

and some Methods of above classes

 

describeReport(reportId) Retrieves report, report type, and extended metadata for a tabular, summary, or matrix report.

Example:Reports.ReportDescribeResult describe =  Reports.ReportManager.describeReport(reportId);

getReportMetadata() Returns metadata about the report, including grouping and summary information.

Example:Reports.ReportMetadata reportMd = describe.getReportMetadata();

getReportFilters() Returns a list of each custom filter in the report along with the field name, filter operator, and filter value.

Example: Reports.ReportFilter filterlist = reportMd.getReportFilters()[0];
filterlist .setValue(filterId);

Apex code

 

[sourcecode language=”java”]
@AuraEnabled
public static string Getreportplanned(String AccId){
Report repRec=[SELECT Id,Name,DeveloperName from Report where DeveloperName=:system.Label.CLNOV19SLS04];
string reportPlannedId=repRec.Id;
string filterId=String.valueOf(AccId).substring(0, 15);
// Retrieves report metadata
Reports.ReportDescribeResult describe = Reports.ReportManager.describeReport(reportPlannedId);
Reports.ReportMetadata reportMd = describe.getReportMetadata();
// Add/Override filters
Reports.ReportFilter filterlist = reportMd.getReportFilters()[0];
filterlist .setValue(filterId);
//and Run report
Reports.ReportResults reportResult = Reports.ReportManager.runReport(reportPlannedId,reportMd);
system.debug(‘ReportResultsJSON’+JSON.serialize(reportResult));
return JSON.serialize(reportResult);
}

[/sourcecode]

Aura component

To load chart on page load.

 

<ltng:require scripts="{!$Resource.chartjs}" afterScriptsLoaded="{!c.createPlannedchart}"/>

For displaying the report

 

 <canvas id="chartCanvas" height="300" width="300"></canvas>

To view standard report

[sourcecode language=”java”]
View Report
[/sourcecode]


Js Code

[sourcecode language=”java”]
var urlPlannedreport = ‘/lightning/r/Report/’+getPlannedReportId+’/view?queryScope=userFolders&fv0=’+accIdsub;

createPlannedchart: function(component) {
var chartCanvas = component.find(“plannedChart”).getElement();
var action = component.get(“c.getreportplanned”);

action.setParams({
“AccId”: component.get(“v.accrecId”)
});
action.setCallback(this, function(response) {
var state = response.getState();
if (state === “SUCCESS”) {
var reportResultData = JSON.parse(response.getReturnValue());
// alert(JSON.stringify(reportResultData));
var chartData = [];
var chartLabels = [];
var nullcheck = reportResultData.groupingsDown.groupings;
if (nullcheck !== null) {
for (var i = 0; i < (reportResultData.groupingsDown.groupings.length); i++) {
//Iterate and prepare the list of Labels for the chart
var labelItem = reportResultData.groupingsDown.groupings[i].label;
chartLabels.push(labelItem);
var keyTemp = reportResultData.groupingsDown.groupings[i].key;
//Prepeare the chart data to be plotted.
var valueTemp = reportResultData.factMap[keyTemp + “!T”].aggregates[0].value;
chartData.push(valueTemp);
}
}
//Construct chart-doughnut/bar
var chart = new Chart(chartCanvas, {
type: ‘bar’,
data: {
labels: chartLabels,
datasets: [{
label: “Count”,
data: chartData,
backgroundColor: [
“#52BE80”,
“#76D7C4”,
“#1E8449”,
“#2ECC71”,
“#FFB74D”,
“#E67E22”,
“#F8C471”,
“#3498DB”,
“#00BCD4”,
“#D32F2F”,
“#82E0AA”,
“#AFB42B”
]
}]
},
options: {
responsive: true,
title: {
display: true,
text: ‘Planned Visits’
},
scales: {

yAxes: [{
ticks: {
// max: 100,
stepSize: 25,
beginAtZero: true
},
scaleLabel: {
display: true,
labelString: ‘Visits Count’
},
}],
xAxes: [{
scaleLabel: {
display: true,
labelString: ‘Created Date’
}
}]
},
maintainAspectRatio: false,
legend: {
display: false,
position: “right”,
fullWidth: false,
}
}
});

} else(state === “ERROR”) {
console.log(‘Problem, response state: ‘ + state);
}

});
$A.enqueueAction(action);
}
[/sourcecode]

You can change the look of charts with the help of chartcanvas methods.

 

 

 

]]>
https://absyz.com/displaying-standard-report-data-in-lightning-component/feed/ 0
Send ICS calendar invitations for Outlook meetings https://absyz.com/send-ics-calendar-invitations-for-outlook-meetings/ https://absyz.com/send-ics-calendar-invitations-for-outlook-meetings/#comments Wed, 18 Dec 2019 10:13:40 +0000 http://blogs.absyz.com/?p=10675

Here we are going to send the meeting invites from salesforce using ICS calendar to our outlook. In general ICS is the  iCalendar/.ics/.ical file and it is used to store the calendar information. Whenever you export anything a outlook, google, etc., calendar  it will automatically save as .ics file.

New and updated meetings are sent to participants using an email notification from particular person. This requires diligent effort from all participants to update their local calendars manually.  The idea is to automatically generate an ICS file with the meeting details and attach it to the notification email whenever an meeting is scheduled or rescheduled. This would allow participants to see the appointment into their calendars.

Let’s assume we have Meeting object in our Org with the following fields

 

  • Subject  – text field
  • Meeting Leader – email field
  • Objective of meeting – picklist field
  • start – Date/Time field
  • End – Date/Time field

Now we are trying to send the meeting invite after inserting or updating the record in salesforce. For that i was using the trigger whenever the record in inserted or updated.

Check the below code to send the ICS calendar invite..!!

 

[sourcecode language="java"]
 trigger meeting on Meeting__c (after Insert,after Update) {
    list<Meeting__c> meetList= new list<Meeting__c>();
    for(Meeting__c meet:trigger.new){
        meetList.add(meet);
    }
    AP_Meeting.sendInvite(meetList);
 }

[/sourcecode]

Below is the helper class..!!

 

[sourcecode language="java"]
public class AP_Meeting{
    public static void sendInvite(list<Meeting__c> meetingList) {
        list<string> UserEmailList = new list<string> ();
        string title;
        string meetingTitle;

        for(Meeting__c meet:meetingList){
            UserEmailList.add(meet.MeetingLeader__c);
            meetingTitle=meet.name+': '+meet.Subject__c;
            title=meet.Subject__c;
            Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
            mail.setToAddresses(UserEmailList);
            mail.setPlainTextBody('This to inform that we have meeting related to particular problem');
            mail.setSubject(title);
            Messaging.EmailFileAttachment attach = new Messaging.EmailFileAttachment();
            attach.filename = 'meeting.ics';
            attach.ContentType = 'text/calendar; charset=utf-8; method=REQUEST'; //PUBLISH';//
            attach.inline = true;

            /***************************/
            attach.body = invite(UserEmailList, meet.MeetingLeader__c, 'Harish Lingam', meet.Subject__c, meet.start__c, meet.end__c, meet.createdDate, system.now(), meet.ObjectiveOfMeeting__c, meet.LastModifiedDate);
            mail.setFileAttachments(new Messaging.EmailFileAttachment[] {
                attach
                    });
            Messaging.SendEmailResult[] er = Messaging.sendEmail(new Messaging.Email[] {
                mail
                    });
        }
    }

    public static Blob invite(List<String> emailsList, String Organiser, string name, string subject, dateTime startDate, dateTime endDate, dateTime createdDate, string description, dateTime lastmodifiedDat) {
        String txtInvite = '';
        string startdateTime;
        string enddateTIme;
        string createdDateTime;
        string lastmodifiedDatTime;

        startdateTime = startDate.formatGMT('yyyyMMdd\'T\'HHmmss\'Z\'');
        enddateTIme = endDate.formatGMT('yyyyMMdd\'T\'HHmmss\'Z\'');
        createdDateTime = createdDate.formatGMT('yyyyMMdd\'T\'hhmmss\'Z\'');
        lastmodifiedDatTime = lastmodifiedDat.formatGMT('yyyyMMdd\'T\'hhmmss\'Z\'');

        txtInvite += 'BEGIN:VCALENDAR\n';
        txtInvite += 'PRODID:-//Microsoft Corporation//Outlook 16.0 MIMEDIR//EN\n';
        txtInvite += 'VERSION:2.0\n';
        txtInvite += 'CALSCALE:GREGORIAN\n';
        txtInvite += 'METHOD:REQUEST\n';
        txtInvite += 'REPLAY:ACCEPTED\n';
        txtInvite += 'BEGIN:VEVENT\n';
        txtInvite += 'ATTENDEE\n';
        txtInvite += 'CN=' + subject + '\n';
        for (String email: emailsList) {
            txtInvite += 'ATTENDEE:' + email + '\n';
        }
        txtInvite += 'X-MS-OLK-FORCEINSPECTOROPEN:TRUE\n';
        txtInvite += 'X-WR-RELCALID:{0000002E-9CDF-9CE8-AD4C-66FC0A5A25F7}\n';
        txtInvite += 'CLASS:PUBLIC\n';
        txtInvite += 'CREATED:' + createdDateTime+'\n';
        txtInvite += 'DTEND:' + enddateTIme+'\n';
        txtInvite += 'DTSTART:' + startdateTime+'\n';
        txtInvite += 'LAST-MODIFIED:' + lastmodifiedDatTime+'\n';
        txtInvite += 'ORGANIZER;CN=' + name + ':mailto:' + Organiser + '\n';
        txtInvite += 'RSVP=TRUE\n';
        txtInvite += 'ROLE=REQ-PARTICIPANT\n';
        txtInvite += 'PARTSTAT=NEEDS-ACTION\n';
        txtInvite += 'CN=' + subject + ':mailto:' + Organiser + '\n';
        txtInvite += 'LOCATION:Skype\n';
        txtInvite += 'PRIORITY:5\n';
        txtInvite += 'SEQUENCE:0\n';
        txtInvite += 'SUMMARY:\n';
        txtInvite += 'STATUS:NEEDS-ACTION\n';
        txtInvite += 'LANGUAGE=en-us:\n';
        txtInvite += 'TRANSP:OPAQUE\n';
        txtInvite += 'UID:4036587160834EA4AE7848CBD028D1D200000000000000000000000000000000\n';
        txtInvite += 'X-ALT-DESC;FMTTYPE=text/html:<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"><HTML><HEAD><META NAME="Generator" CONTENT="MS Exchange Server version 08.00.0681.000"><TITLE></TITLE></HEAD><BODY><!-- Converted from text/plain format --></BODY></HTML>\n';
        txtInvite += 'X-MICROSOFT-CDO-BUSYSTATUS:BUSY\n';
        txtInvite += 'X-MICROSOFT-CDO-IMPORTANCE:1\n';
        txtInvite += 'BEGIN:VALARM\n';
        txtInvite += 'TRIGGER:-PT15M\n';
        txtInvite += 'ACTION:DISPLAY\n';
        txtInvite += 'STATUS:CONFIRMED\n';
        txtInvite += 'DESCRIPTION:Reminder\n';
        txtInvite += 'END:VALARM\n';
        txtInvite += 'END:VEVENT\n';
        txtInvite += 'END:VCALENDAR';
        return Blob.valueOf(txtInvite);
     }
 }
[/sourcecode]

Now lets create a record in the org.  fill the information needed…!!

Now it will directly create a meeting calendar invite in outlook with the details provided. Make sure the all the details filled whatever it is we have used in the code.

 

m5-e1576651434409.png

 

m2

Now we can check calendar for invite.

Now if you want to reschedule the meeting, for that we need to update the record, by updating Start and End time. Now we have rescheduled the meeting to the next day and now the calendar is updated,

 

m6.png

So now you will receive new email with the updated calendar info. Now check the calendar for the updated information.

 

m4

Finally you can add the email template in what ever format you need it, you can also send to the bunch of the people by adding them to the public groups.

 

]]>
https://absyz.com/send-ics-calendar-invitations-for-outlook-meetings/feed/ 1
Blockchain for Salesforce https://absyz.com/blockchain-for-salesforce/ https://absyz.com/blockchain-for-salesforce/#comments Fri, 12 Jul 2019 07:10:28 +0000 http://blogs.absyz.com/?p=9936

Introduction of Blockchain

 

Blockchain is a technology
that uses cryptography to create a secure linkage between records.

 

Blockchain was first described in 1991 by Stuart Haber and W. Scott Stornetta.

 

Blockchain has nodes, and these nodes are called Blocks. Each block contains the hash, hash of the previous block, timestamp and the data. Tempering with blockchain is not easy. If a block has been corrupted than the chain gets corrupted.

The Concept of Blockchain

A Block is similar to the linked list but with more complexity. A block’s hash is generated by the data from the block. But it is simple to generate the hash from data. To prevent this it also contains the hash of the previous block. so, if any data is touched then block get invalid and the chain as well. If someone wants to hack the blockchain then hacker needs to update all the blocks. It is not that simple and it is time-consuming as well.

 

Block Diagram for BlockChain

What is Salesforce Blockchain

 

Salesforce Blockchain is a new way to create, secure and share data from applications with a network of partners. This is because Salesforce Blockchain provides the infrastructure of a distributed ledger(A distributed ledger is a database that is consensually shared and synchronized across multiple sites) and adds on the power of Salesforce metadata. A partner can securely publish and independently verify records on Salesforce Blockchain from whatever system they use.

Benefits that you can get from aligning Blockchain with Salesforce

A). The Increase of CRM Data Security

That is the point at which your organization can get
demonstrated information that is ensured by blockchain innovation. It is a huge
element while utilizing cloud arrangements.

B). The Ability to Be Closer to Your Customers and Grasp their Demands

Blockchain can give you a top to the bottom outline of the
prospects and clients, break down their requests and choose where to convey the
business assets. That is the reason for applying the blockchain innovation
inside CRM can support consumer loyalty and give you an inventive apparatus for
dealing with the business procedure.

C). The Customer Experience Management Improvement

That is how you will guarantee the customer’s information
security and deal with the customer’s experience in any case of the
business.

Consequently, the blockchain together with CRM can expand the
security, quality, and speed of your client administration higher than ever.

Build Your First Blockchain with Salesforce Apex

1.The first step is to create a class called Block. This class will further be utilized to create new blocks in the chain.

 

public class Block 
{
    public integer index;
    public long timestamp;
    public string data;
    public string prevHash;
    public string hash;
    //The constructor of the class will have three parameters.index,data and prevhash
    public Block( integer index,string data,string prevHash)
    {
        this.index=index;
        this.timestamp=generateTimeStamp();
        this.data=data;
        this.prevHash=prevHash;
        this.hash = this.getHash();
    }
    //This method will generate timestamp for the block.
     private long generateTimeStamp()
    {
        return DateTime.Now().getTime();
    }
    //This method creates hash code from data + prevHash + index + timestamp.
    public string getHash()
    {
        Blob dataToEncrypt = Blob.valueOf( this.data + this.prevHash + this.index + this.timestamp);
        //using the generateMac method from Crypto class,selecting HmacSHA256 in the algorithm,choosing Private key to generate a message authentication code (Mac).
        Blob encrypted = crypto.generateMac('HmacSHA256', dataToEncrypt, Blob.valueOf('key'));
        return EncodingUtil.base64Encode(encrypted);
    }
}

2. Create a Class called Blockchain. This class will be used to create the new blocks in the chain and Validate chain. This class  method will check for the valid block. if the block is not valid then it will return false or it will return true

 

public class BlockChain
 {
    public List<Block> chain;
    public BlockChain()
     {
        chain = new List<Block>();
     }
     public void addBlock(string data)
{
        //Defining Index from chain size
        integer index = chain.size();
    //Checking for previous block's hash, If it is first block then it set previous block as '0'
        string prevHash = chain.isEmpty()==true ? '0' : chain.get(chain.size()-1).hash;
        
        //Creating a block from index, data and previous block's hash
        Block newBlock = new Block(index, data, prevHash);
        
        //Adding the new block in the chain
        chain.add(newBlock);
    }
    
    //This method is checking for the valid chain.
    public boolean isChainValid(){
        
        for(integer i=0; i < chain.size() ; i++ ){ 
            //if the chain is not valid then it will return false or it will return true
            if( !isBlockValid(i) ){
                return false;
            }
        }
        
        return true;
    }
    
    //Checking block's hash with run time calculated a hash from the block
    public boolean isBlockValid(integer index){
        
        
        //If someone has changed the block data then getHash will return a new data and not be same as the block's Hash
        if(chain[index].hash != chain[index].getHash() ){
            return false;
        }
        //If the index is greater than zero then it is also checking the block's prevHash from previous block's hash. 
        if(index > 0 && chain[index].prevHash != chain[index-1].hash ){
            return false;
        }
        return true;
    }
}

 

Test Class

 

@isTest
public class TestBlockchain{
    
    //Testing Blockchain 
    @isTest
    public static void testBlockChain(){
        /**Data Setup**/
        
        //Creating Instance of Blockchain
        BlockChain bChain = new BlockChain();
        
        //addBlock method take data as the string
        //Changing data to the string with the JSON format
        
        //Adding the first block to the chain
        bChain.addBlock( json.serialize( new BCTestDataWrapper('Iron Man', '2334343434') ) );
        
        //Adding the second block to the chain
        bChain.addBlock( json.serialize( new BCTestDataWrapper('Thor', '34343434') ) );
        
        
        /**Positive Testing**/
        
        //isChainValid will return true, as no data has been modified from block
        system.assertEquals(true, bChain.isChainValid() );
        
        //Print Blockchain
        system.debug('-Blockchain Data Before Modifying--'+Json.serialize( bChain.chain));
        system.debug('-Blockchain Data Before Modifying--' +bChain.isChainValid());
        
        
        /**Negative Testing**/
        
        //Now updating the 0 index's block
        BCTestDataWrapper tData = (BCTestDataWrapper)JSON.deserialize(bChain.chain[0].data, BCTestDataWrapper.class);
        tData.name = 'Thanos';
        bChain.chain[0].data = json.serialize(tData);
        
        //isChainValid will return false, as the data has been modified from block
        system.assertEquals(false, bChain.isChainValid() );
        
        //Print Blockchain
        system.debug('-Blockchain Data After Modifying--'+Json.serialize( bChain.chain) );
        system.debug('-Blockchain Data After Modifying--' +bChain.isChainValid());
    }

Test Data Wrapper Class

 

public class BCTestDataWrapper{
    public string name;
    public string accountNumber;
    
    public BCTestDataWrapper(string name, string accountNumber){
        this.name = name;
        this.accountNumber = accountNumber;
    }
}

Output

On the execution of the above code, the obtained output is as follows:

isChainValid will return true, as no data has been modified from block

Blockchain Data Before Modifying–[{“timestamp”:1561687116,”prevHash”:”0″,”index”:0,”hash”:”GCS4SGVQ=”, “data”:”{\”name\”:\”IronMan\”,\”accountNumber\”:\”23343434\”}”},{“timestamp”:1561687118,”prevHash”:”GCS4SGVQ=”,”index”:1,”hash”:”uEFcuKCfhhlIVx

Blockchain Data Before ModifyingTRUE

isChainValid will return false, as data has been modified from block

-Blockchain Data After Modifying–[{“timestamp”:1561687116,”prevHash”:”0″,”index”:0,”hash”:”GCS4SGVQ=”, “data”:”{\”name\”:\”Thanos\”,\”accountNumber\”:\”23343434\”}”},{“timestamp”:1561687118,”prevHash”:”GCS4SGVQ=”,”index”:1,”hash”:”uEFcuKCfhhlIVxFn0

Blockchain Data After ModifyingFALSE

 

]]>
https://absyz.com/blockchain-for-salesforce/feed/ 1
SENDING REPORTS TO EMAIL AS AN ATTACHMENT https://absyz.com/sending-reports-to-email-as-an-attachment/ https://absyz.com/sending-reports-to-email-as-an-attachment/#comments Thu, 27 Sep 2018 06:01:34 +0000 http://blogs.absyz.com/?p=9382

We all know how to create reports and dashboards, but the challenge arises when we need to send reports to email as an excel attachment. Salesforce doesn’t provide us with standard inbuilt functionality to do so. I too faced the same challenge and built a solution for this. We have to follow certain steps to achieve this approach.

  1. Create a report
  2. Create a Visualforce Component
  3. Create a Visualforce Email Template

 

1.Create a report

Creating a report or we can take any existing report which is already present in the Org. And make sure that the report preview format is the tabular format.

2. Create a Visualforce Component

Next, we need to create a visualforce component to get the report data and to display as a report. Here we are getting the report Id from the Email Template.

Visualforce Component: ReportsToEmail

[sourcecode language=”java”]
<apex:component controller=”ReportsToEmailController” access=”global”>
<apex:attribute name=”ReportId” description=”Report ID” type=”Id” assignTo=”{!rptId}”/>
<apex:outputPanel>
<table style=”width: 100%;”>
<thead>
<apex:repeat value=”{!ReportResult.reportMetadata.detailColumns}” var=”colName”>

<!– reportMetadata is a class where it contains metadata of a report.
DetailColumns is a method of ReportMetadata class, it returns the API names (Columns Names)
for the fields that contain detailed data–>

<th><apex:outputText value=”{!ReportResult.reportExtendedMetadata.detailColumnInfo[colName].label}”/></th>

<!– reportExtendedMetadata is class where it contains Report extended metadata and
it provides data type and label information.
detailColumnInfo is a method of reportExtendedMetadata class, it returns map of columns names
and its label to Display as Header –>

</apex:repeat>
</thead>
<tbody>
<apex:repeat value=”{!ReportResult.factMap[‘T!T’].rows}” var=”row” rows=”999″>
<!– Here we will get entire data of each row and T refers to the Row –>
<tr> <apex:repeat value=”{!row.dataCells}” var=”cell”>
<!– Here we will get data of each cell and displayed –>
<td><apex:outputText value=”{!cell.label}”/></td>
</apex:repeat> </tr>
</apex:repeat>
</tbody>
</table>
</apex:outputPanel>
</apex:component>
[/sourcecode]

Apex Controller: ReportsToEmailController

[sourcecode language=”java”]
public class ReportsToEmailController {
public Id rptId { get; set; } // Here we will get the report Id from the VF Component
private transient Reports.ReportResults results; // It will hold the entire data of a report

/*********************
// Method Name : getReportResult
// Description : Here we will get the data of a report and send to the VF Component
/********************/

public Reports.ReportResults getReportResult() {
// Here it will run the report with that report ID and adding the report data into results
results = Reports.ReportManager.runReport(rptId, true);
return results;
}
}
[/sourcecode]

3. Create a Visualforce Email Template

EmailTemplate

After creating that we need to edit the template and add the visualforce component as an attachment.

[sourcecode language=”java”]
<messaging:emailTemplate subject=”Report” recipientType=”User” >
<messaging:plainTextEmailBody >
Hi {!recipient.FirstName}
Please find the below attachments.

</messaging:plainTextEmailBody>
<messaging:attachment filename=”Account Report.xls”>
<!– Here we can add multiple Reports –>
<c:ReportsToEmail ReportId=”xxxxxxxxxxxxxxxxxxxx”/>
<c:ReportsToEmail ReportId=”xxxxxxxxxxxxxxxxxxxx”/>
</messaging:attachment>
</messaging:emailTemplate>
[/sourcecode]

 <c:ReportsToEmail ReportId=”xxxxxxxxxxxxxxxxxx”/> ” Here I have called the VF component and we need to give the Report ID. In filename I am giving the name of the file and the type of the attachment(.xls), it automatically attaches the file to an email.

This Email Template can be used in Email Alerts or in apex class and from there you can send the reports to Email.

Here I am using a checkbox field to send email, using workflow whenever this checkbox field is true I am sending the reports to the email using email alert and then I am unchecking the checkbox using field update.

]]>
https://absyz.com/sending-reports-to-email-as-an-attachment/feed/ 5
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
Highlights of Winter’19 Release Notes: Part II https://absyz.com/highlights-of-winter19-release-notes-part-ii/ https://absyz.com/highlights-of-winter19-release-notes-part-ii/#comments Wed, 05 Sep 2018 09:41:15 +0000 http://blogs.absyz.com/?p=9271

“Aloha Trailblazers Ohana” We bring you back the Part II highlights of Winter’19 Release!! Let’s learn new and blaze our trail!!

Don’t miss out to read the part I highlights to stay updated about the new features!! Part I Highlights

Lightning Communities: Content Management, Flows for Guest Users, and Filtered Search Results

1. Upgrade to Latest Community Theme:

With every release, salesforce adds enhanced and improvised features. Likewise, they have updated the features of lightning communities. With winter’19 release a new layout template is made available for the communities.

Theme Communities

2. Inbuilt Content Management(beta):

A new tile is added in the community workspaces, which allows you to create content within the community and also lets you integrate your Salesforce CRM data, which can be displayed as information. All the data is managed in one place and you can also adjust the layout according to your needs.

ContentManagement Communities

Content Management Communities

3. Export themes from the community builder:

Now, you can export themes which you have created from the developer page on the community builder settings. You can put your theme on APP Exchange or share it with your community via a file. This feature is available to all Communities admins.

export theme

Lightning Components in Community Builder:

1. Help Guest Users with Flows:

Guest users can now access flows through your public community pages. With flows, you can guide your users through the registration process while learning more about them, allowing you to provide the best community experience possible.

2. Block Deletion of Threads in Communities:

With Winter’19 release the orgs created after the release, deletion of feed’s which are nested is blocked.

For e.g: If a question on your community feed has an answer and related replies, that feed cannot be deleted. This is recommended to avoid deletion of the main feed and (solutions) replies to the feed.

3. List view of topics in community content:

You can now view your community’s topics in one place, and sort them by name, description, or type. You can now enable up to 10 topics and filter the list according to your need. You can also modify/delete/edit the list.

Content topics list view

4. Display Related Lists with more precision:

You can use the Related Records List component, which displays all related lists of all kinds, the new components provide a more targeted experience. For instance, you can show just the related open cases for a particular account. In addition, both components have a new layout option for narrower displays, such as sidebars and mobile, for better usability.

5. Show Your Salesforce IoT Data Anywhere in Salesforce with IoT Insights:

Add the Salesforce IoT Insights Community Builder component to show Salesforce IoT data to your Lightning community members.

This makes your Salesforce IoT data available to your users throughout Salesforce, giving them more information to serve customers. The IoT Insights Lightning standard component enhances your CRM data by showing Salesforce IoT information alongside it. You can include the component on Salesforce Lightning record pages, such as cases, work orders, and assets.

rn_iotx_iot_insights

6. Allow Field Service Dispatching from Lightning Communities:

The new FSL Community Dispatcher permission set provides all the permissions a community dispatcher needs to use the dispatcher console, view global actions and their related objects, and schedule, optimize, and dispatch service appointments.

To use the dispatcher console in a community, users need:

  • Customer Community Plus or Partner Community license
  • FSL Dispatcher permission set license

7. New Global Actions for Communities:

Salesforce has added two new case global actions for specific user type.  When you configure your Contact Support Form component, you now see separate case global actions: one for authenticated users and one for guest users.

8. See Field Dependencies While Editing a Record Details Page:

You can now view and update all dependent and controlling fields when editing a picklist or checkbox on a Record Details page.

For that, you should have a dependent picklist field in your object.

Field Dependencies

Community Engagement: Recognition Badges

1. Display Recognition Badges on User Profiles:

These badges are available on the profile component of your community. This displays the last three badges earned by the user and a button to award a new badge.

You can include this badge component in a user’s profile page, to show the badges earned.

2. Award Recognition Badges with the New Give Badge Button:

Giving your fellow users the recognition badges they deserve is easy with the Give Badge action. Add Give Badge as a button, and give any user a badge directly from a user profile.

From a user profile, select Give Badge and that user’s name is automatically included in the To field. You can also give badges with the Give button on the Recognition Badges card. Add the card to your user profiles with the User Profile component or the Recognition Badges component.

rn_networks_givebadgebutton

Give badge

Files in Lightning Communities: Editable File Detail Pages, and Custom Fields on File Uploads

1. Make Changes to Fields whenever necessary:

You can now edit file details in Communities for all fields, including file name, description, and custom fields so you can keep your file information accurate and up to date.

rn_networks_files_edit_details_page

2. Populate Custom Fields When Uploading Files:

Users can populate required custom fields and see validation rule error messages when files are uploaded to the community. This feature is available on files uploaded from Files home, from the Files or Notes and Attachments related lists, and the Lightning file upload component.

When uploading a file, users are alerted to required fields or validation errors that must be fixed before the file can be saved.

rn_files_customfields2

Salesforce Surveys: More Control to Gather the Data You Need

1. Gather Specialized data with new question types:

To gather data in an effective way, with the Winter’19 release three new question types are being introduced in salesforce surveys – CSAT, Sliders, and Picklists.

CSAT lets you collect Customer Satisfaction data from a list of options. Sliders, on the other hand, let’s your participants select a value on a sliding measure scale. Picklists are nothing but a pre-defined list of options for participants.

2. Add Multiple Questions to your surveys:

Users with Survey creator license can now add multiple questions to the surveys, to help the participants navigate and move through survey easily.

View Status and Responses on Survey Invitations:

surveys_related_records

3. No Authentication Required for contacts to take surveys:

In order for a participant to take a survey, they no longer need to log in from their salesforce account, if they are associated with contact records in your Org.

4. Gather financial data from financial services cloud:

With winter’19 release surveys are made available to the Financial Service cloud. A user can create surveys in the financial service cloud, in order to gather insights from banking and financial service customers.

5. Pause and Resume a survey:

Participants can now pause a survey and come back to finish it later without losing their progress. Surveys which require authentication can only be paused. Users are required to log-in with salesforce authentication credentials in order to pause a survey.

APEX: What’s new in Winter’19!!

1. Fire platform events from Batch Apex:

With Winter’19 release Batch classes can fire platform Events. Event records provide more granular tracking of errors than the Apex Jobs UI because they include the record IDs being processed, exception type, exception message, and stack trace. You can also incorporate custom handling and retry logic for failures. Clients listening on an event can tell how often it failed, which records were in scope at the time of failure, and other exception details. Events are also fired for Salesforce Platform internal errors and other “uncatchable” Apex exceptions like LimitExceptions that are caused by reaching governor limits.

To fire a platform event, a batch Apex class declaration must implement the Database.RaisesPlatformEvents interface.

apex

Output:

apexplatform2

2. Use Inherited Sharing keyword to secure your Apex Code:

You can now specify the inherited sharing keyword on an Apex class, which allows the class to run in the sharing mode of the class that called it. Using inherited sharing enables you to pass security review and ensure that your privileged Apex code is not used in unexpected or insecure ways. An Apex class with inherited sharing runs as with sharing when used as a Visualforce page controller, Apex REST service, or an entry point to an Apex transaction.

This example declares an Apex class with inherited sharing and a Visualforce invocation of that Apex code. Because of the inherited sharing declaration, only contacts for which the running user has shared access are displayed. If the declaration is omitted, even contacts that the user has no rights to view are displayed due to the insecure default behavior of omitting the declaration.

Inheritedsharing

vf

Output with Inherited sharing Keyword:

sharing output

Without Inherited sharing keyword this displays the list of all contacts.

3. Streamline API Calls to Your Org:

You can now access API features without configuring remote site settings by using the System.Url.getOrgDomainUrl() method.You can now interact with those objects using Apex code, building endpoints with the System.Url.getOrgDomainUrl()method.

You can also use the updated System.UserInfo.getSessionId() method to retrieve session IDs, even when your code runs asynchronously.

Share Extensible Functionality with the Callable Interface:

Instead of implementing the Process.Plugin interface for use cases it wasn’t designed to support, you can now implement System.Callable. Simply invoke Callable to make a common point of agreement between pieces of code from different parties. This helps developers to build upon one another’s solutions.

To implement the Callable interface, you need to write only one method: call(String action, Map<String, Object> args).

The Callable interface allows integrations in which code from different classes or packages can use common base types.

4. Changed Apex Classes:

With winter’19 release the apex classes have changed and now has new constants.

Schema.DescribeFieldResult Class

New method: isAiPredictionField() 

Returns a Boolean indicating whether the field is enabled to display Einstein prediction data.

Schema.DescribeSObjectResult Class

New Method : getRecordTypeInfosByDeveloperName()

Returns a map that matches developer names to their associated record type.

System.Crypto Class
New Methods:
verify(String algorithmName, Blob data, Blob signature, Blob publicKey)

Returns a Boolean verifying the digital signature for encrypted data, using the specified algorithm and the supplied public key.

verify(String algorithmName, Blob data, Blob signature, String certDevName)

Returns Boolean verifying digital signatures for data, using the specified algorithm and the public key associated with the certDevName.

verifyMac()

Returns a Boolean verifying the HMAC signature for data using the specified algorithm, input data, privateKey, and the mac.

Changed Apex Enum

These enumerations were updated in this release.

Auth.Auth.VerificationMethodEnum Enum

Contains the different ways users can identify themselves when logging in. Can be used to implement mobile-friendly passwordless login pages, and to self-register (and deregister) verification methods.

This enum has a new value, Password. Identity can be verified by password.

Metadata.PlatformActionListContextEnum Enum

Describes the different contexts of action lists.This enum has a new value, ActionDefinition. This value is reserved for future use.

New Apex Interfaces:

Auth.ConfigurableSelfRegHandler Interface

Create a class that implements Auth.ConfigurableSelfRegHandler to register users with their email address or phone number instead of a username and password. When you set up your community’s self-registration with the Configurable Self-Reg Page, Salesforce generates a default AutocreatedConfigSelfReg Apex class. Modify the class to extend the functionality, for example, to change how users are created.

createUser(accountId, profileId, registrationAttributes, password)

Create a community member from the information that the visitor provided on your community’s self-registration page.

Auth.LoginDiscoveryHandler Interface

Create a class that implements Auth.LoginDiscoveryHandler to log in users based on other verification methods than username and password. Users can identify themselves with their email, phone number, or another identifier like a Federation ID or device identifier. When you set up your community’s login page with Login Discovery Page, Salesforce generates a defaultAutocreatedDiscLoginHandler. You can modify the class, for example, to support single sign-on (SSO).

login(identifier, startUrl, requestAttributes)

Log in the external user given the specified identifier, such as email or phone number. If successful, redirect the user to the community page specified by the start URL.

System.Callable Interface

Enables developers to use a common interface to build loosely coupled integrations between Apex classes or triggers, even for code in separate packages. Agreeing upon a common interface enables developers from different companies or different departments to build upon one another’s solutions. Implement this interface to enable the broader community, which might have different solutions than the ones you had in mind, to extend your code’s functionality.

call(action, args)

Provides functionality that other classes or packages can utilize and build upon.

Visualforce: Field Sets in Lighting Experience and New Access Metrics

1. Create and Edit fieldsets(Lightning):

Now you can create and edit fieldsets in lightning experience.

When a fieldset is added to a Visualforce page, developers can loop over its fields and render them. If the page is added to a managed package, administrators can add, remove, or reorder fields in a field set to modify the fields presented on the Visualforce page without modifying any code. The same Visualforce page can present different sets of information.

field sets

2. New Access Metrics Fields:

Use the new ProfileId and LogDate access metrics fields to prioritize which Visualforce pages to migrate to Lightning Experience.

The ProfileId field shows the Salesforce profile ID of the user who viewed the Visualforce page. The LogDate field shows the date that the user accessed the page. This field provides more insight into page usage than the MetricsDate field, which represents the date the metrics are collected.

3. Use Image Proxy URL to display third party images securely:

You can now protect your users from unauthorized requests by using the IMAGEPROXYURL function to securely fetch images outside your org’s server.

To securely retrieve an external image, include the IMAGEPROXYURL function on the src attribute of a tag or the valueattribute of an object.

<img src={!IMAGEPROXYURL(“https://domain”)}/>

<apex:image value=”{!IMAGEPROXYURL(“domain”)}”/>

4. Improve Security with Iframes:

You can now isolate HTML static resources on a separate domain using iframes. Using a separate domain to embed information from untrusted sources protects your Visualforce content.

To reference a static HTML file on a separate domain, use $IFrameResource.<resource_name> as a merge field, where resource_name is the name you specified when you uploaded the static resource.

5. URL parameters are no more case sensitive:

The protected URL parameters used in Visualforce pages—retURL, startURL, cancelURL, and saveURL—are no longer case-sensitive. For e.g: If you change the parameter value from retURL to returl, the system now recognizes it as a protected parameter.

Search: Relevant Results in Real Time and More Ways to Filter Results and Search

1. Get More Relevant Search Results Without the Wait:

Search results now instantly prioritize the objects you interact with. That means new users, or users changing roles, don’t have to build up interaction history to see what’s most important when they search. Previously, it took some time to accrue interactions with objects and prioritize those objects in search results. Now any object your users open, create, or update gets an instant boost when using global search.

 2. Filter Search Results by Number Range:

  1. When the numbers matter, use filters to frame your search results. Zero in on opportunities that fall within a certain amount or probability range.
  2. For example, use number range filters to create a list of hot opportunities to follow up on. On the search results page, click Opportunities in the sidebar to see the available filters. Enter your target range, and click the magnifying glass.

From Setup, in the Object Manager, go to Search Layouts for each object. Add the fields that users want to filter to the Search Results layout. You can’t filter encrypted fields. 

Screenshot (144)

3. Recover Your Unsaved Text After Getting Timed Out:

Sometimes your Lightning Experience session is interrupted, whether you’ve been inactive too long or you lost your connection. You used to see the same timeout message, regardless of how your session ended. Now the message that pops up is specific to your scenario and tells you how to recover the unsaved text.

If your session is interrupted, return to the page to copy unsaved text, like a Chatter post, so you don’t lose it during a new session.

Screenshot (145)

4. Field History Tracking Data Deleted After 18 Months:

  1. Salesforce guarantees to retain your field history data for up to 18 months.
  2. Starting with the Winter ’19 release, we no longer retain field history beyond 18 months. To retain field history longer, you can purchase the Field Audit Trail add-on.
  3. This policy applies to all orgs created after June 2011 who have not purchased the Field Audit Trail add-on.
  4. To guarantee that you have access to your field history data, purchase the Field Audit Trail add-on. Field Audit Trail lets you define a policy to retain archived field history data up to 10 years from the time the data was archived.
  5. Use the queryAll() API to retrieve deleted field history during the grace period and create your own backup. You can’t use the getDelete() API to retrieve data that Salesforce deletes following the 18-month limit.

Productivity Features:

1. Email Experience: Attachments in List Emails and Actions, Bounce Notifications, Email Tracking, and Quick Text.

a. Bounce Back from Email Bounces:
  1. Sales reps need to know when their emails to contacts, leads, and person accounts don’t go through. Without a warning, they’re waiting for a response that’ll never come. Now reps know which lead, contact, or person account has a bad email address, and they know which specific email wasn’t delivered.
  2. Any user can see a bounce warning. If the user has update rights to the record, the user can update the contact’s email address to remove the bounce warning.
  3. A bounce warning appears next to the email address in the lead, contact, and person account record.
  4. To activate Bounce Management, from Setup, click Email, then click Deliverability. Select Activate bounce management. To display bounce information, from Setup, enter Enhanced Email in the Quick Find box, and then select Enhanced Email. Click Enable.

Screenshot (146)

 b. Quickly See Whether Customers Open Email from Your Company:
      1. Now we can glance at the activity timeline to see if and when customers open the email that reps send through Salesforce.
      2. Previously, to see if and when customers opened an email from your company, reps ran the HTML Email Status report. But now, tracking information is visible in the activity timeline.
    1. Screenshot (147)
    2. 3.  If you want, add the First Opened and Last Opened fields to your email page layouts to see the information there, too.

Screenshot (148)

c. Use Attachments After Inserting Salesforce Classic Email Templates:

Your sales reps know that they can insert a Salesforce Classic email template into a Lightning Experience email. Now they can use existing content and add attachments to the email too. For text, custom HTML, and letterhead email templates, reps can add attachments from Files.Screenshot (149)

Screenshot (150)

      1. When a Salesforce Classic Visualforce email template is inserted into a Lightning Experience email, you can’t add an attachment.
      2. To change the attachments that are part of a Salesforce Classic email template, go to Classic Email Templates in Setup.
    1.  Screenshot (151)
  1. 2. Kanban: Recently Viewed Availability, Search Kanban View

Explore the power of the Kanban View from Recently Viewed lists. No need to switch to another view to find records. Search is now available on the Kanban View.

a. Get the Kanban View for Recently Viewed Lists Users can switch to the Kanban view from the Recently Viewed list view of almost any object.
    1. Select the Recently Viewed list view (1), then select Kanban from the Display As menu (2).                Screenshot (152)
b.  Search for Records in the Kanban View
    1. Users can hone in on the records they need faster by searching the selected list view from within the Kanban view.
    2. Enter a search term in the search box to see matching records.Screenshot (153)

Analytics: Reports and Dashboards

Reports: Enhanced Run Page Improvements (Beta), Drill into Your Data, Edit Joined Reports with the Lightning Experience Report Builder (Beta)

The second beta release of the enhanced run page report is available to all users. It brings many powerful features to report readers, such as grouping report data and toggling the visibility of detail rows. Drill into your data to get more information. As part of the Lightning joined reports beta, edit joined reports with the Lightning Experience report builder.

1. Edit Joined Reports with Lightning Report Builder (Beta)

  • Enhance your joined report workflow by editing joined reports with the Lightning report builder and with more run page functionality including filtering and sorting.
  • This release contains a beta version of Lightning joined reports, which means it’s a high-quality feature with known limitations. Lightning joined reports isn’t generally available unless or until Salesforce announces its general availability in documentation or in press releases or public statements
  • To view joined reports in Lightning Experience, you need the Run Reports user permission.
  • To create or edit joined reports, you need one of these permissions: Create and Customize Reports, Report Builder, or Report Builder (Lightning Experience).
  • Work with joined reports in Lightning Experience’s modern interface and take advantage of Lightning Experience’s productivity-improving features like report run page filtering. Edit joined filters, groups (including cross-block groups), and columns with the Lightning report builder.
  • If necessary, turn on the Lightning joined reports beta. From Setup, enter Reports in the Quick Find box, then select Reports and Dashboards Settings. Select Enable Lightning Joined Reports (Beta), and then click Save. To edit a joined report with the Lightning report builder, click Edit (Beta).

Screenshot (155) - Copy

2. Features Not Available

These features aren’t available in the Lightning Experience report builder, but they are available in the embedded Salesforce Classic report builder. To open the Salesforce Classic report builder in Lightning Experience, click either New Report (Salesforce Classic) or Edit (Salesforce Classic).

Editing and building feature gaps and limitations include:

  • Creating joined reports
  • Adding or removing blocks and report types
  • Adding and editing custom summary formulas and cross-block custom summary formulas

Running and reading feature gaps and limitations include:

  • Subscriptions
  • Export
  • Chatter feeds

3. Choose the Currency for a Report

  • If your org has an international clientele, chances are some of your users want the option to review the financial data in other currencies. Lightning report builder lets users set the currency on a report.
  • In an org that has multiple currencies enabled and currencies activated, select the report. Click Edit. In the currency picklist, set the currency. To preserve your choice for this report, click Save.

Screenshot (156)

Dashboards: More Filter Values, Joined Reports as Source Reports, Custom Axis Ranges, and Decimal Precision

1. Add Up to 50 Values to Each Dashboard Filter

Dashboards illuminate your business data, and dashboard filters let you shine a light on specific parts of your business. Previously, you could add up to 10 distinct values (like State equals California) to a dashboard filter. Now you can add up to 50 distinct values to each dashboard filter.

  • To view, refresh, and apply filters to dashboards, you need the Run Reports user permission.
  • To add filters to dashboards, you need one of these permissions: Create and Customize Dashboards, Edit My Dashboards, or Manage Dashboards in Public Folders.
  • To add or edit filters to dynamic dashboards, you need the Manage Dynamic Dashboards user permission.
  • With up to 50 values per filter, you can filter by all 50 states.
  • Add or edit a filter, choose a field, and then click Add Filter Value to add up to 50 filter values.

Screenshot (157)

2. Set Decimal Precision in Dashboard Charts and Tables

  • Choose how many decimal places charts, tables, and metrics show in dashboards, from 0 to 5.
  • To set decimal places for a dashboard component, you need one of these permissions: Create and Customize Dashboards, Edit My Dashboards, or Manage Dashboards in Public Folders
  • To set decimal places for a dashboard component on a dynamic dashboard, you need the Manage Dynamic Dashboards user permission.
  • Because 14.11B is more than 14B and the difference between 90%, 90.1%, and 90.10001% matters.

Edit or add a dashboard component, then specify decimal precision with Decimal Places.

Screenshot (158).png

3. Use Joined Reports as Source Reports for Dashboard Components

With a joined report as its source report, a dashboard component can contain data from multiple standard or custom report types. Or, you can provide multiple views of the same object.

  • To use a joined report as a source report for a dashboard component, you need one of these permissions: Create and Customize Dashboards, Edit My Dashboards, or Manage Dashboards in Public Folders.
  • To use a joined report as a source report for a dashboard component on a dynamic dashboard, you need the Manage Dynamic Dashboards user permission.
  • See accounts with open cases by joining the cases report type to the accounts report type, filtering for open cases, and grouping by account. Or see cases by status by joining the cases report type together on three joined report blocks and filtering each block by status: open, in progress, and closed.
  • To use a joined report as a source report, it must have a chart. To add a chart to your joined report, edit it with the Lightning Experience report builder or edit it in Salesforce Classic. (You can’t add charts to joined reports using the Salesforce Classic report builder embedded in Lightning Experience.) Then, click Add Chart.

Screenshot (159).png

Usability and Performance Improvements

1. Dependent Picklists No Longer Have a Default Value Selected:

Dependent picklists in communities no longer have a default value when loaded, so they now work the same in communities as they do in your internal org. We made this change because picklists did not consistently assign default values in all environments. If your site design or code assumes a default picklist selection, you need to adjust it.

2. Guest Users Are Redirected to a Login Page When Visiting Record Pages

Salesforce has standardized the guest user experience for all Record pages. Now guest users are redirected to a login page when attempting to visit Record Detail, Record List, or Record Related List pages. Previously, guest users were redirected to a login only when trying to access the Record Detail page.

  • This feature is available in Lightning and Salesforce Tabs + Visualforce communities accessed through Lightning Experience and Salesforce Classic. Communities are available in Enterprise, Performance, Unlimited, and Developer editions.
  • For the redirect to work, the guest user must be able to access to the correct object. For the Record List page, the guest user must have access to the appropriate entity. For the Record Related List page, the guest user must have access to the entity of the related list and the parent record to which the related list is attached.

3. Get Faster Page Response with Support for Optional URL Query Parameters

To improve performance and flexibility, we added support for query parameters to navigateToURL. {!EL} expressions are automatically replaced with a dynamic Aura expression. The Aura expression updates at runtime to parameters provided by the current page, such as parameters from the route or URL query parameters. This change improves performance because only components that are necessary during navigation events are loaded rather than reloading the entire page. However, this change can mean that custom components may not work as expected.

  • This change affects Lightning and Salesforce Tabs + Visualforce communities accessed through Lightning Experience and Salesforce Classic. Communities are available in Essentials, Enterprise, Performance, Unlimited, and Developer editions.
  • This change affects Lightning components at runtime that have the following characteristics.
    • The component has a required String attribute, which doesn’t have a default value
    • The component has a corresponding design attribute
    • The value of the design attribute is an “{!EL}” expression. The expression can be set either as a default value on the design attribute or by changing the value in the Community Builder component properties.
    • The component lives on a page that has no parameter from the route or from the URL query strings for the {!EL} value
  • Previously, the component didn’t load if it met all these characteristics, and so users didn’t see it. Starting with Winter ‘19, Aura tries to load the component regardless, which means that some components might now show on a page with errors in them.
  • If you’ve written custom components that meet the above characteristics, check your code to make sure that you’re not performing unsafe operations on component attributes that might now be undefined.

4. Decrease Page Load Times with Community Content Delivery Network (Generally Available)

Introduced as a pilot feature in Winter ‘18, the Community Content Delivery Network (CDN) is now available to everyone for free. Use the CDN to decrease your community’s page load time and improve your member’s experience.

  • Provision and activate the CDN by editing your custom domain. Select Salesforce serves the domain over HTTPS, using a Salesforce content delivery network (CDN) partner and a shared HTTPS certificate and click Save.
  • Provisioning takes 2–6 hours but requires no downtime and you are emailed when it’s finished. When it’s complete, activate your domain. Activation takes 10–15 minutes and does temporarily make your community unavailable, so we recommend doing this step at a time when traffic is light.

Chatter

1. Save Your Chatter Posts as Drafts:

Have you ever lost your work in the middle of writing an important Chatter post? We know how frustrating that is. Introducing Draft Posts, a new option to automatically save all your unpublished feed items.

As you type a new post, Chatter saves your work to the My Drafts tab. Add files, links, images, mentions, hashtags, and any other rich text, because we save it all.

new004

new005

  • You can access your drafts in My Drafts to publish, edit, or delete them.

Screenshot (160)

  • When you save a post with a hashtag, the corresponding topic is not created until the post is published.
  • To turn on Draft Posts in your org, navigate to the Chatter setup menu. Under the Draft Posts section, select Allow draft posts.

2. It’s About Time—Date Format Fixed for Spanish Locales

The date and time information that appears with feed items and comments is fixed. The rule is that the locale setting determines the date-time format, and the language setting determines the language. For Spanish locales, when the language setting was English, a mix of Spanish and English for the date and time was shown. Now it’s all fixed.

API

1. New and Changed API:

There are many new standard objects added. Few changed objects are:

EmailMessage

These fields are new

  • FirstOpenedDate
  • IsBounced
  • IsOpened
  • IsTracked
  • LastOpenedDate

Folder

These values are new to the Type field

  • Quick Text
  • Macro

Note: There are a few other fields which are changed. For the complete reference please visit Salesforce Winter 19 release notes.

2. SOSL: Changed Clauses

ListView=Recent

USING ListView = is an optional returning clause used to search within a single given object’s list view. You can now use USING ListView = Recent to search for the most recently accessed items that were viewed or referenced by the current user.

3. REST API: New and Changed Calls

  • New Calls

/v44.0/consent/action/  – Determine the actions to which your customer has (or hasn’t) consented, regardless of which objects in Salesforce recorded the consent.

  • Changed Calls

/vXX.X/limits/ – For the data storage and file storage reports, /vXX.X/limits/ performs calculations the same way as the Salesforce user interface. The API now uses these definitions:

1 KB = 1,024 bytes

Previously, it used these definitions:

1 KB = 1,000 bytes.

Hope, this helped you learn new and blaze your trail!!

Check out Highlights of Winter’19 Release PartI: Part I Highlights

Source:  Salesforce Winter’19 Release Notes

]]>
https://absyz.com/highlights-of-winter19-release-notes-part-ii/feed/ 1
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
Getting started with Salesforce DX https://absyz.com/getting-started-with-salesforce-dx/ https://absyz.com/getting-started-with-salesforce-dx/#respond Mon, 04 Jun 2018 10:26:19 +0000 https://teamforcesite.wordpress.com/?p=8700

What is Salesforce DX?

The term Salesforce Developer Experience (DX) encompasses both a set of tools and new features that affect the app development lifecycle. Salesforce DX introduces a new development paradigm that shifts the center of your world from monolithic, org-based development to modular, artifact-based development. This model streamlines the entire development life cycle, with benefits like:

  • Improving team development and collaboration.
  • Facilitating automated testing and continuous integration.
  • Making the release cycle more efficient and agile.

Salesforce DX isn’t a magic bullet!

Salesforce DX isn’t a magic bullet that will fix every challenge development team has with organizing change and managing releases. In their current form, the tools related to Salesforce DX will be easier for members of your team that can work with command line interfaces (CLIs) or integrated development environments (IDEs).

  • In a traditional Salesforce development lifecycle, app builders use sandboxes to create and test changes. Often, for teams in the middle of a project, the ‘source of truth’ might really be whichever environment contains the latest, stable build of their project about to be pushed into the next higher environment. For another team of developers, their source of truth may or may not be in the same sandbox(es).
  • Instead of piecing together the state of various environments to get the latest versions of code or metadata, your team can get the latest versions from a centralized source control system, like Git or Subversion. This style of managing development artifacts (i.e. code and other customizations) is called source driven development.
  • Shifting to source driven development won’t eliminate conflicts in code or metadata, or change the need to communicate clearly across teams. But it does put the burden of organizing, managing and resolving changes into source control systems, which are built to do this efficiently. Source driven development can also give you and your team greater visibility (and audit history) into the changes made to your org—whether in code or configuration—and better ways to undo changes that have negative impacts.

A common usecase :

If we want to share a particular application with others, one of the fastest ways to do this was to create an unmanaged package. But this also meant we needed to keep track of the login to that org if we wanted to ever work with that package again, and also remember what package went with that org(because any changes in the package can be done only from the org where it is created).

But Salesforce DX make things easier for us. When we need to create an unmanaged package to share something, we convert that same package into a Salesforce DX project and store it in source control. If we want to make changes, we can quickly spin up a temporary environment (called a scratch org), make our updates, sync our changes back to source control, spin up another scratch org, push our updated source to the new org and test out our changes. If we’ve made an error in my updates, correcting and testing multiple versions of an app takes minutes, not hours or days.

 

Let’s take a closer look at three key pieces of the Salesforce DX toolset: the Salesforce CLI, the Dev Hub, and scratch orgs.

Salesforce CLI

Wouldn’t it be better to have an application with a UI? That would help more people use Salesforce DX. Also, then we wouldn’t have to remember all those different commands and parameters.

Some of the reasons are :

  • Tying Salesforce DX to a specific UI would limit how you can benefit from Salesforce DX. The Salesforce CLI does a ton of heavy lifting for you, like handling the communication to your different Salesforce orgs in an standardized way. By exposing that power in a CLI tool, you can leverage these functions with the different tools you or your team want to use — like a shell script, a continuous integration system, or the IDE of your choice.
  • A UI can increase how efficiently you work with a system—to a point. But with all the different options for how you may want to use Salesforce DX, trying to tie everything back to a single UI could become quite overwhelming. With the complexity of many systems today, CLIs are often one of the few common ways developers work.

People often think that the Salesforce CLI can only be used with Salesforce DX projects – which isn’t true.The Salesforce CLI is, as the name says, a command line interface that enables you to run numerous tasks on your Salesforce environments. A major portion of the current functionality is targeted at elements that were introduced with Salesforce DX.

Dev Hub

If you try to just install the Salesforce CLI and run Salesforce DX commands, you’ll find quite a few commands will first need you to authenticate into a Dev Hub. This functionality is what allows you and your team to create and manage temporary environments called scratch orgs.

You can turn on Dev Hub functionality in your Production org. Under Setup > Dev Hub, you’ll see two toggles. The first one will enable the Dev Hub functionality, and the second is related to enabling developer controlled packaging. Once you enable Dev Hub capabilities, you cannot undo the change— keep this in mind when enabling this functionality in Production.

Scratch Orgs

Scratch orgs are one of the biggest changes (and gifts) Salesforce DX brings to your development team. These temporary Salesforce instances are designed to allow you to easily and quickly build and test changes. They can last anywhere from 1-30 days and the default lifespan is 7 days. Scratch orgs can be created in minutes and they expire without any additional management from a team member.

Scratch orgs, though amazing, will not replace your need for sandboxes.Screenshot (80)

Scratch orgs can be a great alternative or complement to the developer sandboxes, which may get crowded during the initial stages of app development. But scratch orgs won’t perfectly mirror your production environment. They’re also not the place for end-to-end integration testing, testing with large data volumes, user acceptance testing or training. These things can only be done in the sandboxes.

Screenshot (81)

 

Set up our Salesforce DX environment and do some hands on

  • Install Command Line Interface(CLI)
    • after installation, open cmd as Run as administrator
  • Log In to the Dev Hub using the command
    • sfdx force:auth:web:login -d -a DevHub
    • -a is used to create an alias DevHub and -d is used to make this the default org.

Screenshot (82)

  • Take a look at all set of available commands by typing
    • sfdx force –help
  • For doing hands on create a directory and download a project from GitHub
    • mkdir my_sfdx_project – creating a directory
    • cd my_sfdx_project – going into the directory
  • Next, use this command to clone the app repository:
    • git clone https://github.com/forcedotcom/sfdx-dreamhouse.git
  • Next, open the directory:
    • cd sfdx-dreamhouse

Screenshot (83)

  • Cloning the repository pulls all the source code into your local file system. But before you start editing, you first create your own branch. This is a best practice as defined by GitHub Flow, because it helps ensure your Master branch is a clean and production-ready version of your code.
  • Create a branch for your project
    • git checkout -b my_branch
    • Now that you’re working in your own branch, it’s easy to submit updates to your team later on.
  • Use the following command to create the scratch org, set it as your default, and give it an alias:
    • sfdx force:org:create -s -f config/project-scratch-def.json -a “default scratch org”
    • Notice that we didn’t get a password. This is because with Salesforce DX we use cached authentication tokens.
  • Let’s try out this. Enter the following command
    • sfdx force:org:open
  • Push the local source to the scratch org with this command
    • sfdx force:source:push

Screenshot (97)

  • At this point we’re close to being able to run the DreamHouse app. But when you look at the source that was pushed to the org, you see that the app uses a permission set to provide access. Before we can access the app, we need to assign that permset using the CLI.
    • sfdx force:user:permset:assign -n Dreamhouse
  • We don’t have any of the DreamHouse app data in the org. Luckily, we do have sample data in our repository.Let’s use the CLI and the SObject Tree API to import this data into the org.
    • sfdx force:data:tree:import –plan data/sample-data-plan.json

Screenshot (96)

We have fully set up and configured our project, we are ready to begin the development. We will now open the org and check out our Dreamhouse application.

Open the scratch org with sfdx force:org:open command. Notice, that you don’t have to login. Open Dreamhouse app from the app launcher. We can see the sample data that we have input earlier by clicking on different tabs.

Screenshot (95)

 

We have used Salesforce DX to create our development environment and it was much simpler and less time taking than the process which we use now. We can quickly spin up the scratch org and do development and testing of any particular module in our project.

Unlocked Packages

The last part of the process is packaging. All of us are aware about managed and unmanaged packages that we use for packaging of our code. Both methods have some advantages and disadvantages. Unlocked packages have taken best from both the methods.

Unlocked packages allow you to decide what pieces of metadata should be in a package (hence the name). This means you can experiment with how you want to define packages, as well as update and change your packages into the future. The process of adopting unlocked packages will have overlap with the process of adopting source driven development. Identifying potential packages within your production environment is similar to deconstructing your org into modular pieces for source control.

Best practices around developing packages are still evolving. The road to adopting packages, and breaking your org into modular units for source control, will require flexibility and some trial-and-error. You’ll need to be willing to experiment and spend meaningful time analyzing your experiments.

For more detailed information please check SFDX Trailmix

]]>
https://absyz.com/getting-started-with-salesforce-dx/feed/ 0