Lightning Flow and Test Coverage

If you read on the same sentence Flow and Test, what do you think is the article about? My first thought was “how to test a flow in order to avoid issues.” Something like this one.

However, my entry would like to focus on Test Coverage as it is a key point that could be a pain if you need to deploy Flows in active mode. The reason, they also require to have a 75% of coverage at least, in order to get a success deploy.

Flow Test Coverage? I thought this is a #clicksnotcode tool …

Yes and it may not make sense if you are working with Screen Flow. In fact, we do not need to worry about test coverage on these kind of flows. However, you need to keep in mind those that work without screens such as autolaunched flows. You can have more information here.

And how can we do it? Like the documentation says, via a Trigger.

Let’s try to explain it with an example.

If you have read some others entries, you will already know my Flow examples are based on a Hotel Reservation App. So below example is related to Reservations. The scope of the autolaunched flow is to send an email to the guest once he pays the reservation.

And in order to make it work, I need to call it from my Trigger.

trigger ReservationTest on Reservation__c (before insert, before update)
{
    for(Reservation__c r : Trigger.new)
    {
        if(r.isPaid__c)
        {
            System.debug('Run the email flow');
            
            Map<String, Object> params = new Map<String, Object>();
            params.put('guestEmail', r.guestEmail__c);
                
            Flow.Interview.EmailFlow flowToSendEmail = new Flow.Interview.EmailFlow(params);
            flowToSendEmail.start();
        }
    }
}

Now, that we have the new flow, we need to check Flow Coverage status. But the first execution is to identify all Active elements we have in the org in order to be able to calculate the coverage.

Running this query:

Select MasterLabel,
	Definition.DeveloperName,
	VersionNumber,
	Processtype
 FROM Flow 
 WHERE Status = 'Active' 
    AND (ProcessType = 'AutolaunchedFlow' 
       OR ProcessType = 'Workflow' 
       OR ProcessType = 'CustomEvent' 
       OR ProcessType = 'InvocableProcess')

We get below result, and we can identify 2 Autolaunched flow. One of them is the EmailFlow, the one we are using on this example.

Run on Developer Console with Use Tooling API checked

On the other side, Salesforce provides an object in order to check coverage, FlowTestCoverage and we will use it in order to check EmailFlow one. However it only returns a record if there is already some coverage of the elements, so the easiest way to start checking it is modify previous query adding as a filter where the Id not in on the new FlowTestCoverage object.

Select MasterLabel,
		Definition.DeveloperName,
		VersionNumber,
		Processtype
 FROM Flow 
 WHERE Status = 'Active' 
    AND (ProcessType = 'AutolaunchedFlow' 
       OR ProcessType = 'Workflow' 
       OR ProcessType = 'CustomEvent' 
       OR ProcessType = 'InvocableProcess')
    AND Id NOT IN (SELECT FlowVersionId FROM FlowTestCoverage)

The query result is the same as before so we can start writing our first test in order to cover EmailFlow one.

@isTest
public class EmailFlowApexTest
{
	static testMethod void validateEmailFlow()
    {
        Reservation__c r = new Reservation__c();
        r.isPaid__c = true;
        r.guestEmail__c = 'a@ff.com';
        insert r;
        
	    List<Reservation__c> rList = [Select Id, isPaid__c, guestEmail__c from Reservation__c where Id = :r.Id];
        System.assert(true, rList.get(0).isPaid__c);
    }
}

Now, this test covers the trigger that starts EmailFlow, so if we run previous query again, now, EmailFlow will not appear as part of the result, and running a query against FlowTestCoverage, we can start getting some information about our job.

SELECT Id, 
 	ApexTestClassId, 
 	TestMethodName, 
 	FlowVersionId, 
 	NumElementsCovered, 
 	NumElementsNotCovered 
 FROM FlowTestCoverage

Where we can see how match the FlowVersionId with ours, and also the TestMethodName we defined above, validateEmailFlow.

Now I wonder: What about if our test has more than one step? What does happen with above result? So let’s go for it. After the email is sent, we will have a decision element that will check the total amount of the reservation. After that, do an assignment to a certain object. We could continue adding more complex to the flow but let’s keep it simple so far.

The first step is to modify the test in order to have an amount higher or less than the decision filter.

@isTest
public class EmailFlowApexTest
{
    static testMethod void validateEmailFlow()
    {
        Reservation__c r = new Reservation__c ();
        r.isPaid__c = true;
        r.guestEmail__c = 'agarcia@financialforce.com';
        r.TotalAmount__c = 100;
        insert r;
        
	    List<Reservation__c> rList = [Select Id, isPaid__c, guestEmail__c from Reservation__c where Id = :r.Id];
        System.assert(true, rList.get(0).isPaid__c);
    }
}

With this, if we run below query,

SELECT Id, 
     ApexTestClassId, 
     TestMethodName, 
     FlowVersionId, 
     NumElementsCovered, 
     NumElementsNotCovered 
 FROM FlowTestCoverage

We get a similar result as the previous one. The only difference is that NumElementsCovered is 3 while NumElementsNotCovered is 1 . The reason is because now, our flow has 4 elements, the core one that sends the email, the decision and the 2 assignments. But our test only covers one of the assignments.

So next step is to add a second method that covers the second decision path.

@isTest
public class EmailFlowApexTest
{
    static testMethod void validateEmailFlow()
    {
        Reservation__c r = new Reservation__c ();
        r.isPaid__c = true;
        r.guestEmail__c = 'agarcia@financialforce.com';
        r.TotalAmount__c = 100;
        insert r;
        
	List<Reservation__c> rList = [Select Id, isPaid__c, guestEmail__c from Reservation__c where Id = :r.Id];
        System.assert(true, rList.get(0).isPaid__c);
    }
    
    static testMethod void validateEmailFlowWithAmountLessThan50()
    {
        Reservation__c r = new Reservation__c();
        r.isPaid__c = true;
        r.guestEmail__c = 'agarcia@financialforce.com';
        r.TotalAmount__c = 25;
        insert r;
        
	List<Reservation__c> rList = [Select Id, isPaid__c, guestEmail__c from Reservation__c where Id = :r.Id];
        System.assert(true, rList.get(0).isPaid__c);
    }
}

And this time, the query execution returns below result where we can see the second testMethod.

Also we can check both have same values on NumElementsCovered and NumElementsNotCovered because each one cover a single path.

Note: Whenever I made a modification on my trigger, the query took a while (even a day) to get the results. It’s like Salesforce needed some time to process new test coverages.

Finally I would like to talk about how we know we achieve the 75% required in order to be able to deploy my flow. Unfortunately Salesforce does not provide the information yet but explain a way to calculate it manually.

For example, if you have 10 active autolaunched flows and processes, and 8 of them have test coverage, your org’s flow test coverage is 80%.

Salesforce help: https://sforce.co/2PqALZw

 

Having that, if I only have a single flow in my org with some test coverage, per above info, my flow coverage is 100%. However I would not be surprised if they look into the test flow and check the number of elements. So if I have 4 elements and 2 are covered, my coverage is 50% and if I cover 3, I achieve the 75% required. Keep this in mind just in case.

Update 20190726

While I was writing this post, I found out some weird behaviours with tests. If I removed a test method that covered a flow and run the query again, results were same as if I had the test in place. Because of that, I decided to raise a case with Salesforce in order to know more, and I would really like to share the final answer with you.

When we first run a test class it will add a record for each method to the FlowTestCoverage object. If we modify the class to add a new method and run it again, then, it will add a new record for the new method. But if we remove a method it will not delete the record. The record will only be removed if a change is made to the associated flow version.

If we delete the test class completely it will remove all FlowTestCoverage records for the related class since it no longer exists.

If you would like the FlowTestCoverage object to reflect changes made to test classes then, the best way to do this would be to create a new version of the flow and run the test classes against the new version.

Hope it helps others.

Visual Flow & Lightning Components (I)

Visual Flow & Lightning Components (I)

It’s a fact that Visual Flow needed something that could make it more attractive to developers, and Salesforce did it.

Now we are able to integrate a Lightning Component as part of the Flow with just drag and drop and this blog will explain how easy it is.

Please, take into account that if your org is on Spring ’19, the look and feel of the Cloud Flow designer would be different because Salesforce is going to deliver Flow Builder

Using Standard Lightning Component

When we add a new screen to the flow, the first action is to add some new fields to show them. If we click on “Add a Field” tab, we  can scroll down and under Extensions section, we can find Lightning Components label.

Captura de pantalla 2018-11-30 a las 20.30.40

After adding it to the screen, you need to highlight it, so that you would be able to see all Standard Lightning Components that Salesforce already provides and we can use.

My example already have 2 radio buttons in order to decide if I would like to go ahead with the booking process or I prefer to stop it.

Captura de pantalla 2018-11-30 a las 20.34.09.png

And I would like to show something nicer like a toggle, the one that I already selected.

Winter ’19 provides new Lightning Components we can add to flows. Toggle is one of them.

So the result would be like below image.

Using Custom Lightning Component

But what about if you don’t find the Lightning Component you really need on Flow? That is not a problem, because you can also create your custom Lightning Component and add it to the Flow.

Let’s talk about another example. We will create a simple Flow with 2 DatePickers. The first one is provided by Flow, however the second is a custom Lighting Component. How does it look like?

Captura de pantalla 2018-12-20 a las 9.46.35.png

Their look and feel are similar and both work like tweens. The only difference with the Lightning component is that we can customize it. For instance, you can see that the size is larger than the flow one. Or you can change background color for instance.

How can we visualize in the Flow? First of all, remember that the DatePicker is a custom Lighting Component, so yes, you need to be sure that you implement a new interface in order to make it visible: lightning:availableForFlowScreens

Captura de pantalla 2018-12-20 a las 13.07.27

So doing that, it will appear on flow with all standard lightning components that Salesforce already provide, so it is just a matter of drag and drop.

Captura de pantalla 2018-12-20 a las 13.17.47

And that’s all, you have integrate your custom Lightning Component into your Flow.

Now Flow is beautiful as well as useful

From Attachment to File via Flow?

Some days ago I got a message asking me if it was possible to move from Attachments to Files in Salesforce using the #clicksnotcode tool VisualFlow and after some researches I would say no, this is not possible without code. But if you find the way, please, please, please, leave me a message so that I can update this post.

So, what is this post about? My researches and how I got that the answer is no.

First of all, the use case. As you know we cannot create Attachments in Lightning Experience, only Files are available in LEX, so anything that we want to keep should be also migrated.

But how?

  • Manually? That could be a really expensive option, and tired, to be honest.
  • Via code? Yes!! I like this option. At the end, a File is a Salesforce Object, ContentVersion , and as you can find on this blog, with a really simple piece of code you can create a new File record. Below piece adds the query to an attachment. After that, find the image with the new file and also the result of a query done in  Workbench.
List<Attachment> attList = [SELECT 
                               Body,BodyLength,Name,ParentId 
                            FROM Attachment limit 1];
Attachment att = attList.get(0);

String fileContent = att.body.toString();
ContentVersion conVer = new ContentVersion();
conVer.PathOnClient = 'MigratedFile.txt';
conVer.Title = 'MigratedFile.txt';
conVer.Description = att.Name + ' migrated';
conVer.VersionData = EncodingUtil.base64Decode(fileContent);
conVer.FirstPublishLocationId = '001B000000hYespIAC'; 
insert conVer;

Captura de pantalla 2018-06-28 a las 17.15.33

Captura de pantalla 2018-06-28 a las 17.20.22

And what about VisualFlow?

I created something really simple, 4 steps flow. But it has a welcome and a thanks screen, so actually the job is done in 2 steps.

Captura de pantalla 2018-06-28 a las 17.30.46

First one is Record Lookup where I retrieve the single attachment that I have in my organization. Please, keep in mind that if you have a list of Attachments, and use a Record Lookup, it will return a single record, but if your idea is to retrieve all attachments, you need to use a Fast Record Lookup step.

Captura de pantalla 2018-06-28 a las 17.31.10

This step is going to store data into the variable that I created, and all of them are similar, Text variables.

Captura de pantalla 2018-06-28 a las 17.31.48

The second step is to create the ContentVersion record, assigning the variable data that I got on the previous step.

Captura de pantalla 2018-06-28 a las 17.32.00

And that is all. Yes, so simple.

However, when I run it I got an error and this email where I can see that there is an issue on VersionData field.

Captura de pantalla 2018-06-28 a las 17.42.18

The reason is simple. Attachment Body returns a Blob that I need to convert into String in order to be able to encode and pass to the Content file.

....
String fileContent = att.body.toString();
....
conVer.VersionData = EncodingUtil.base64Decode(fileContent);
....

Is there a way to fix it? No as far as I could find. My first idea was to check what the variable was returning, adding a middle step to show the body value

Captura de pantalla 2018-06-28 a las 17.55.06

And as I expected that is not my body text

Captura de pantalla 2018-06-28 a las 17.54.46

So the next thought was to try to create a formula in flow or make any transform, something that could help me, but I couldn’t find any.

Captura de pantalla 2018-06-28 a las 17.51.16

So I think that the only way to do it is via some Apex code. We can create a class that has InvocableMethod annotation and do the transform there and call the class as it was an step, but, to be honest, why do I want to do it when I can run the whole transform from an apex class as I explained before?

At the end, I would advice to create your own ApexClass that execute the process to do the migration if you do not want to use the tool that Salesforce provides.

Good luck!!

Salesforce BigObjects

What is a BigObject?

Two years ago I started working with Big Objects, a Salesforce pilot that looked very interesting for me. And now that it seems that General Available time is closer, I would like to write about them.

Please, take into account that a Salesforce pilot could be discarded like Data Pipeline that it would not be GA at the end.

Big Objects is a new type of objects that Salesforce provides. Maybe the most important thing I can tell is that they do not count against the storage limit. Well, you could say that External Objects already do.

You can learn more about External Objects here.

Yes, you are right. But this time, data lives in your organisation instead of in an external storage and this means that you can work with them like with Custom / Standard objects, but if you go to Salesforce Storage screen, you would not find them.

Big Objects let you store and manage large amounts of data.

Use Case

But before starting with the explanation, let’s talk about the Use Case.

As a company that creates software, we have stories in order to develop new functionality. Before delivering them, we need to pass a code review, so that, we ensure the best to our end users.

Captura de pantalla 2017-07-07 a las 12.21.47

But how much storage should I use to keep code review records in our Production org? Should I remove them? If so, what about auditing?

BigObjects is your solution, so that, you can move old records to a new Code Review History BigObject record. Let’s focus for now on this new History object.

How to Create a BigObject?

Unfortunately you cannot do it in a declarative way. You need to define them via Metadata API and then do a deployment via cmd or workbench.

Before doing it, take into account:

  1. Indexes are required and in order to include them, you need to be on API 39.0 onwards.
  2. Once you deploy one, you cannot make any modification like amend a field type, change label, etc. However in a declarative way you can do small changes like the label and API name.
<?xml version="1.0" encoding="UTF-8"?>
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
  <deploymentStatus>Deployed</deploymentStatus>
  <fields>
    <fullName>CanBeMerged__c</fullName>
      <label>Can Be Merged</label>
      <length>80</length>
      <type>Text</type>
    </fields> 
  <fields>
  <fullName>CodeReviewDate__c</fullName>
    <label>Code Review Date</label>
    <type>DateTime</type>
    <required>true</required>
  </fields>
  <fields>
    <fullName>Comments__c</fullName>
    <label>Comments</label>
    <length>255</length>
    <type>Text</type>
  </fields>
  <fields>
    <fullName>Employee__c</fullName>
    <label>Employee</label>
    <referenceTo>Employee__c</referenceTo>
    <relationshipName>Employees</relationshipName>
    <required>true</required>
    <type>Lookup</type>
  </fields>
  <fields>
    <fullName>Score__c</fullName>
    <label>Score</label>
    <precision>1</precision>
    <scale>0</scale>
    <type>Number</type>
  </fields>
  <fields>
    <fullName>Story__c</fullName>
    <label>Story__c</label>
    <referenceTo>Story__c</referenceTo>
    <relationshipName>Stories</relationshipName>
    <required>true</required>
    <type>Lookup</type>
  </fields>
  <indexes>
    <type>PRIMARY</type> 
    <fullName>Test1CodeReviewPK</fullName>
    <fields>
      <name>Story__c</name>
      <sortDirection>DESC</sortDirection> 
    </fields>
    <fields>
      <name>Employee__c</name>
      <sortDirection>DESC</sortDirection>
    </fields>
    <fields>
      <name>CodeReviewDate__c</name>
      <sortDirection>DESC</sortDirection>
    </fields>
  </indexes>
  <label>Test1 Code Review History</label>
  <pluralLabel>Test1 Code Reviews History</pluralLabel>
</CustomObject>

Once you deploy it into your organization, you would find something like this under BigObject entry:

I decided to name is as Test1 Code Review History because once it is created I cannot modify it, and I didn’t want to use Code Review History label for now.

Captura de pantalla 2017-07-14 a las 13.03.54.png

What can we highlight?

  1. The API name ends with __b instead of __c or __x like custom and external objects.
  2. We will not find Standard fields.
  3. We can create as many custom fields as we want but right now it only supports these field types: DateTime, Lookup, Number, Text and Long TextArea. What about the rest? Try to be creative. For instance a Checkbox can be converted into number or text.
  4. You will not find any other section like PageLayout or Buttons for now.
  5. You will not find Triggers section. It is not allowed for now.
  6. You will not be allowed to create a custom tab related to this object. That is related to previous point and the PageLayout. To visualise Big Object records, you need to create a visualforce page or a lightning component.
  7. You can determine its CRUD and FLS via Profile or Permission Sets during the deploy process or in a declarative way. However for now BigObjects can be only created and read.

Captura de pantalla 2017-07-14 a las 13.44.36

How Can I Create Records?

There are different ways to create BigObject record, like using a csv file, use APIs like Bulk API or even Async SOQL, another Pilot I will talk about in a future entry.

In any case, here, I will focus on Apex.

As I mentioned above, you can only Read or Create records, and nowadays, you cannot use simple DML operations, there is a new one: database.insertImmediate(record)

Test1CodeReview__b cr = new Test1CodeReview__b();
cr.CanBeMerged__c = 'False';
cr.CodeReviewDate__c = System.today();
cr.Comments__c = 'I found a SOQL inside of a loop.';
cr.Employee__c = 'a6j24000000fxSL';
cr.Score__c = 0; 
cr.Story__c = 'a6k24000000k9bN';
database.insertImmediate(cr);

But something pretty cool that it was not available at the beginning, it is the fact we can use this method, to also update records. Actually it works like upsert. If I make a call where the record has a primary key that doesn’t exist, it would create a new record as we can see in the below image.

Captura de pantalla 2017-07-14 a las 14.28.04

However if the value already is in the platform, it will make a modification.

Test1CodeReview__b cr = new Test1CodeReview__b();
cr.CanBeMerged__c = 'False';
cr.CodeReviewDate__c = System.today();
cr.Comments__c = 'I found a SOQL inside of a loop.';
cr.Employee__c = 'a6j24000000fxSL';
cr.Score__c = 1; //Change to 1
cr.Story__c = 'a6k24000000k9bN';
database.insertImmediate(cr);

Captura de pantalla 2017-07-14 a las 14.35.49

If I come back to the original use case, I would like to move CodeReview__c records to Test1CodeReviewHistory__b records. In order to do that I only need to retrieve the record I need and create a new BigObject entry.

CodeReview__c cr = [Select Id, CanBeMerged__c, 
                           CodeReviewDate__c, Comments__c, 
                           Employee__c, Score__c, Story__c 
                    From CodeReview__c 
                    Limit 1];

String canBeMerged = cr.CanBeMerged__c == true ? 'True' : 'False';

Test1CodeReview__b crh = new Test1CodeReview__b();
crh.CanBeMerged__c = canBeMerged;
crh.CodeReviewDate__c = cr.CodeReviewDate__c;
crh.Comments__c = cr.Comments__c;
crh.Employee__c = cr.Employee__c;
crh.Score__c = cr.Score__c; 
crh.Story__c = cr.Story__c;
database.insertImmediate(crh);

How Can I Visualise Records?

As we have already mentioned, we cannot create a custom tab related to a BigObject and show all records. However we can query BigObjects, so what about if we create a custom page for that?

First of all we would need a controller. Really simple one. We have a method to retrieve all records and a get and set to show in a list what we retrieve.

public with sharing class CodeReviewController
{
   private static List<Test1CodeReview__b> codeReviewHistoryList; 
   
   public CodeReviewController()
   {
      setCodeReviewHistoryList(calculateCodeReviewHistoryList());
   } 

   public List<Test1CodeReview__b> calculateCodeReviewHistoryList()
   {
      return [SELECT Id, CanBeMerged__c, CodeReviewDate__c, 
                     Comments__c, Employee__c, Score__c, 
                     Story__c                
               FROM Test1CodeReview__b];
   }

   public static List<Test1CodeReview__b> getCodeReviewHistoryList()
   {
      return codeReviewHistoryList;
   }

   public static void setCodeReviewHistoryList(List<Test1CodeReview__b> value)
   {
      codeReviewHistoryList = value;
   }
}

Secondly, we have the visualforce page. Something to highlight is that right now, the standardController attribute doesn’t work, so we can only create a page with a customController. 

<apex:page showHeader="true" sidebar="true" controller="CodeReviewController">
   <apex:form>
      <apex:pageBlock title="Code Review History Records">
         <apex:pageBlockSection title="Code Review History" columns="1" collapsible="false">
	    <apex:pageBlockTable value="{!codeReviewHistoryList}" var="crHistory">
               <apex:column headerValue="Ready To Merge?">
	          <apex:outputField value="{!crHistory.CanBeMerged__c}"/>
               </apex:column>
	       <apex:column headerValue="Score">
	          <apex:outputField value="{!crHistory.Score__c}"/>
	       </apex:column>
               <apex:column headerValue="Comments">
	          <apex:outputField value="{!crHistory.Comments__c}"/>
               </apex:column>
               <apex:column headerValue="Story">
	          <apex:outputField value="{!crHistory.Story__c}"/>
               </apex:column>
               <apex:column headerValue="Reviewer">
                  <apex:outputField value="{!crHistory.Employee__c}"/>
               </apex:column>
               <apex:column headerValue="Code Review Date">
                  <apex:outputField value="{!crHistory.CodeReviewDate__c}"/>
               </apex:column>
            </apex:pageBlockTable>
         </apex:pageBlockSection>
      </apex:pageBlock>
   </apex:form>
</apex:page>

And the result is this one that includes the record created from scratch and the one that is retrieved from CodeReview__c object.

Captura de pantalla 2017-07-17 a las 9.14.52

Summary

I would like to share this table that summarise BigObjects and compare with Custom Objects. But before, I would like to also highlight that this new object type can be included in a package. You would find under CustomObject section:

Captura de pantalla 2017-07-17 a las 9.16.06

Summary Table:

Feature Custom Object Big Object
Creation Manual
Metadata
Metadata
API name myObject__c myObject__b
Track Activities
Track Field History, etc.
Options Available Options No Available
Field Types All Text ; Date/Time ; Lookup
Number ; Long Text Area
Able to edit fields Yes Yes (with restrictions)
Able to delete fields Yes No
Triggers; Field Sets; etc Options Available Options No Available
Reports Yes No
How to Populate records All CSV file
API (Bulk, SOAP)
Apex
Async SOQL
Can I amend a record? Yes Yes (with restrictions)
Can I see data creating a Tab Yes No
For free? Yes No — Talk with Salesforce
Storage It count against storage It doesn’t count against storage

London’s Calling ’17 and Visual Flow

Last 10th of February, I attended London’s Calling ’17 and I can say it was a great and funny day.

Captura de pantalla 2017-03-12 a las 19.22.17

And obviously, we had lot of opportunities to learn more about Salesforce. Actually I had the chance to run a session about Visual Flow where I got nice questions that I promised to review and answer, and here is the time for it:

1. Did you find any issue related to Communities?

When I created a new Community in my org and tried to add elements, I was not able to find the Flow Lightning Component that allows me to include visualflows in Lightning Experience. However, I can add visualforce pages, so if you have your flow embebed in a visualforce page and you set this page up to be used in Communities, then, it seems you can see your flow in the Community.

2. Did you find any issue during deployment?

Although my daily job tasks do not include deploying flows, I could say that those times that I tried I did not get any special issue to highlight. We just need to keep in mind few things, like also include those objects that flow references but this is like some other components. In addition, although in your org you have several versions, in change set you can only include the latest active one. And as I said in the session, in order to include a flow in package, it should be active, otherwise, it will not appear as an element to be included. You can find more information here.

3. What is coming in Spring ’17 release?

I talked about some Spring’17 features, but I also promised to review, the new FLS feature. But let start checking the behaviour if I do not have access to the object itself.

So having a user which profile only allows to Read and View All reservations:

Captura de pantalla 2017-03-12 a las 11.11.03.png

if I try to run the BookingSystem application, by the time I try to save the Reservation, I get an unhandled error (that’s why Salesforce encourage to cover these in the same way we do in apex) And the administrator receives an email with the log and the error:

Captura de pantalla 2017-03-12 a las 11.14.24Captura de pantalla 2017-03-12 a las 11.15.04

Let’s double check new FLS for Flow in Spring’17

Captura de pantalla 2017-03-12 a las 12.06.57

In this scenario, I have Filter Inaccessible Fields from Flow Request enabled in Process Automation Settings, and also, I have defined a Field Level Security of No Visible for Facility Price in my custom profile

Captura de pantalla 2017-03-12 a las 11.28.42.png

So, having this configuration, I have created also this flow in order to insert a new Facility via a Fast Create screen

Captura de pantalla 2017-03-12 a las 19.01.51.png

So in order to do that, I create a SObject and I use the input fields from the first screen in order to make an assignment to the SObject fields and finally pass the SObject to the Fast Create

Now, if I run the flow with the profile that doesn’t have price visibility, I can create a new record, but having an empty price.

Captura de pantalla 2017-03-12 a las 19.11.19.png

However, if I disable Filter Inaccessible Fields from Flow Request enabled in Process Automation Settings, and run the flow again, the result is different. The record is not half created and the administrator receives and email with the error.

So now, what should I do? Up to you really. You can handle the exception and provide a nice error message and don’t allow the end user to create a Facility record without the prices. However, if the field is not required for the business, you can leave this half creation.

Any other question about Visual Flow? Leave it as a comment and I will try to check it and reply you.

 

 

Lightning Experience and Visual Flow

Today I’m going to do some researches with one of these #clicksnotcode features that Salesforce provides in the Platform, Visual Flow. Ok, this is not a hot topic now, but if we want to check how it works in Lightning Experience (LEX from now onwards) then, this post could be a bit more interesting for you.

Take into account that Visual Flow in LEX is in beta

The use case it’s simple. I have a Hotel, and I would like to get some feedback from my guests, so I will send them a survey.

The Flow would be very simple, and as the creation is not the main goal here, I will not show it step by step. But if you are new, double check Visual Flow documentation and also TrailHead.

First of all we need to open Flow Designer, so, can I do it in LEX? Yes. Go to Setup and just write “flow” in order to find it and be able to open this platform feature.

captura-de-pantalla-2016-12-02-a-las-10-35-11

As you can see on below image, the Flow Designer looks like the Classic UI one, so you would not need to learn how to work with it if you already used it.

captura-de-pantalla-2016-12-02-a-las-12-08-29

Once I have created my Flow, we can add it to our Home page, but remember to Activate it, otherwise it would not be available in Lightning App Builder.

So, go to Home, Edit this page, and Lightning App Builder will help you to add it there.

How? Really simple, if you go to Standard Apps, one of them is Flow (beta) so you only need to click on it, and your flow will appear in the home page.

captura-de-pantalla-2016-12-02-a-las-10-57-11

But actually I have 2 active flows, so what can I do? When you highlight your custom Flow, on the right side you have the option to select the one you need to show, so just pick one.

captura-de-pantalla-2016-12-02-a-las-11-12-38

I can also say that I had to try a couple of times till I got this behavior. First time, Book Room flow did not appear on the drop down list, so there were not way to add it to my Home page. But remember, this feature is on beta, so be patience and try till you get it.

Last thing to mention is the fact that you can chose between 1 or 2 columns. My first thought was that this attribute would help me to determine if I wanted 2 flows on the same row on the page layout, but it is not related to that. It just help you to set all your flow fields in 2 columns instead of one. For instance, these 2 screens show same fields but they are sorted in a different way.

captura-de-pantalla-2016-12-02-a-las-12-11-41captura-de-pantalla-2016-12-02-a-las-12-11-08

And how it works? In Spanish we say better a image rather than thousand words but in this case, better a video rather than thousand images.

 

Maybe your last question is if we can add it to any other place? Yes, for instance, I can include it in my Guest record layout

captura-de-pantalla-2016-12-02-a-las-13-06-23

But let’s make up a little bit and define something for every guest:

captura-de-pantalla-2016-12-04-a-las-20-20-05

In order to do that, I had to add a Lookup step in the Flow and use the variable {!recordId} as a filter. So that, I can retrieve Guest object record and use it in my Flow.

captura-de-pantalla-2016-12-04-a-las-20-26-44

It was not easy to find the way to retrieve the recordId but this post helped me a lot.

I hope you liked this short entry about Flow. You can find more information on Salesforce release notes entry.