Fuzzy Searching in Salesforce Flows

Standard

Salesforce flows are a magical thing, like good coffee at work and unicorns.

coffee unicorn.jpg

This is how I want my coffee delivered.

 

I have come to realize that there are limits to even the most magical things (BOOO!).

The limitation I have found in flows is around how you search for records…but, let me be clear, it really isn’t a big deal. For most people, finding records using the typical “equals”, “contains”, “starts with” and “ends with” functions will work just fine. I however, found myself going down a path where that wasn’t going to quite cut it. The challenge is how to search on a text input in a manner that is more google like. I don’t know what the kids now a days call it, but back in my day, we might call if “Fuzzy Matching”.

Fozzie_bear.png

Fuzzy, Not Fozzie!

For example, let’s revisit my Jaeger Dispatching System (Special Note, Pacific Rim 2 is scheduled). This system uses dynamic drop downs for the Jaegers, but, what happens when you have a bunch of Jaegers’?  You can build out a record search based on a text box, but, as mentioned before, you are limited to “equals”, “contains”, “starts with” and “ends with” functions. At this point, you might be saying, fine, just use a “contains” operator…and that would work, except what happens when the user spells something wrong? Contains is just two wild cards, so if you entered in “Dangur” instead of “Danger” you would not get a hit.

 

What happened next is pretty funny. I started thinking about how there are patterns in words…and then started thinking about how the pairs of letters could work. Spoiler alert, it totally worked. I proved it in Excel by just using a vlookup and some formulas, so I got pretty excited. It was then that I googled this matching pairs thing and found out that yep, some one wrote about all the fancy math behind it.

http://www.catalysoft.com/articles/StrikeAMatch.html

So, after building out the proof in Excel that this would work, I set about trying to get this to work in Salesforce…specifically a flow. I want to be able to enter in some characters into a text box and see returned results based on how well they matched my search term.

The first thing I did is create a field that removes the spaces from the Jaegers’ names and made them lower case. I don’t want it being “Cherno Alpha”, I wanted “chernoalpha”. This is done via formula field. If doing this in real life, I would build out my formula to also remove punctuation, but this is just for my Jaeger dispatch and my blog, so I am just removing spaces.

Thus, concludes the non flow part of this blog…what follows next is like 100% awesome, you have been warned.

TAKETHISCAT.jpg

Woot! FINALLY got to use this meme!

The first couple things are pretty basic, I have a start screen that has a text box. Next, I have a fast lookup on my Jaeger object. This gets all the Jaegers and puts them all in a collection. Next up is my loop, where I go through each Jaeger record. The only “gotcha” is that when you do the fastlookup, you need to bring over your formatted text from the record. Screen shots of this would be pretty boring, so here is a picture of all the giant robot toys.Jaeger Toys.jpg

Within the loop, I start with two assignments that copy the formatted Jaeger Name (no spaces) and the search string to variables.
I am going to use these variables for the rest of the functions, including the formulas. I take the search string that was entered and format it up.  I remove the spaces, count how many pairs I have and if the value has a remainder, I also remove the last character. I do this because otherwise the matched pair logic would be searching on a single digit, which would skew the results. The formula also checks if the search string is just 3 char, and if it is, it will treat these three char as one “pair”. Pictures and Text!

Formatted Search String

if(len(substitute({!Search_String},” “,””))<>3,
if(
mod(len(substitute({!Search_String},” “,””)),2)<>0,
left(substitute({!Search_String},” “,””),len(substitute({!Search_String},” “,””))-1),
substitute({!Search_String},” “,””)),substitute({!Search_String},” “,””))

Now I have to compare my first matched pair to the formatted name. of the search string that was formatted. I use a formula to get my matched pair:assignment - formatted search string.png

if(len(substitute({!Search_String},” “,””))<>3,
lower(left({!varSearchStringUseCopy},2)),lower(left({!varSearchStringUseCopy},3)))

 

The flow will next do a name check via the decision function. If the Formatted Jaeger Name contains the current matched pair, the flow adds a value of 1 to the counter variable and adds the current pair to a variable that will show the matches and the ID of the current record to another variable. Ugh, that was hard to read, here is a picture:assignment - match found

If the pair is NOT a match, well, I don’t really do anything with it but you might want to shove it to a debug variable. In fact, if you are starting this from scratch, I would HIGHLY suggest you do this!

Next up is yet another assignment, this time though, we are removing the pair was just searched on. This is done with, you guessed it, a formula:

if(len(substitute({!Search_String},” “,””))<>3,
substitute({!varSearchStringUseCopy},left({!varSearchStringUseCopy},2),””),substitute({!varSearchStringUseCopy},left({!varSearchStringUseCopy},3),””))

remove search string

Once that is completed, we check to see if there are more pairs to check. This is done by looking at the number of pairs left after the current pair is removed. This is in a formula I like to call “DisappearingSearchString”:

len({!varSearchStringUseCopy})

The whole process looks like this:

match process

If all the pairs have been used, the flow then checks to see if there were any matches with a decision point on the counter variable. If yes, then we add the matching data into a variable and then start the loop all over again. Because we will want to display some results in a table like format, be sure to append a text template that has a line break at the end of the string. To do this, create a text template with <br> in it.

build out result line.png

One of the things I really wanted was a way to see how many of the pairs were found in a given record. I do this with this formula:

({!varTripCount}/{!frmSearchStringPairs})*100

 

Before the loop starts all over again, any used variables are reset:

clear counters.png

So, enough talk! Let’s see how this works! For comparison purposes, I put in an alternate lookup that will use the “Contains” search function of what was entered in the input.

I also added more Jaegers, 8 in total!

Jaeger List.png

boom

 

First search string is going to be “Eureka”:

Eureka.png

and here are the results:Search Results - Eureka.png

The “Contains” function did what I expected and returned two records, “Striker Eureka” and “Eureka Smack”. However, it did not find “Striker Eurek”, but the matched pairs function did!

Let’s try this on another scenario. Suppose there is someone new in the Jaeger Dispatching Center and they forgot that it is “Cherno Alpha” and they enter in “Alpha Cherno”.

Search String.png

The “contains” search function would literally return ZERO results, whereas the matched pairs function would show an 80% match with Cherno Alpha.Results - Cherno Alpha.png

So, there you have it. With a bit of work, you can do fozzie…err…fuzzy search results with in a flow with Zero coding!

As always, if you have any questions, comments, or suggestions, please let me know!

Andrew

The hot fudge for your visual flow sundae

Standard

Flows really are a ground breaking piece of technology.

were not worthy

It was evident last year at DF14 by how often there were talked about. More stuff is being added every release and there is a great big community of users!

UI based flows are awesome for internal user, just pop the URL into a button and instant awesome! A question that is constantly being asked is, how do I get the pop up window to go away”

See, when you launch the UI version of the flow, it does it’s merry little thing and then takes you back to the start, which is not always ideal! Being that we are all really clever folks in this community, there are a bunch of ways around this, but a lot of them require visualforce / apex or a URL hack…but not many of them actually address the needs I had:

  • I need this to run with in a community
  • I would like the window to close once the flow is completed

First things first, we need the flow to run in a community. According to page 115 of the Visual Workflow Guide:

“Enable external users to run your flow by adding the flow to a Visualforce page and distributing that page through a Force.com site, Customer Portal, or Partner Portal.”

OK, no big deal there. This topic has been covered extensively on this blog and others! As a side note, this is how you get flows playing nicely with Salesforce1, so head over here to learn more…I will wait!

Ah, you are back! Now that we have a flow that will run on communities or internally. How the heck do we get the flow to close out the window? Well, after googling various iterations of “closing visualforce window” I finally just decided to google something like “close browser window javascript” (This was after googling “Moscow Mule Recipes”).

I wish this just came from one source, but I was really using the google hive mind that day! What I ended up doing is using some javascript in a visualforce page called “ForceClose”:

<apex:page showChat=”false” showHeader=”false” sidebar=”false” applyBodyTag=”false” applyHtmlTag=”false”>
<html>
<head>
<title>ESCAPE</title>
<script>
function closeWindow() {
window.open(”,’_parent’,”);
window.close();
}
</script>
</head>
<body onload=”closeWindow()”>

</body>
</html>
</apex:page>

NOTE! If this code looks familiar to someone, please let me know so I can give you a hat tip from little corner of the web!
NOTE + 1! I still have my #ClicksNotCode card, so I would imagine this is not near good code!

Now I have a flow that runs in a Visualforce page AND a Visualforce page that should (in theory) close itself. It is time to…wait, I wish this step could be more dramatic…maybe you could read this in a monster truck voice? Just in your head so you are not disturbing your neighbor! OK, carry on…join the two pages together! Just set your finish location on your flow visualforce page to be the forceclose page!Add Finish Location

And, that is that! So, how does it work? Well, pretty darn good! The super sweet thing though is that this is reusable! I now used the “ForceClose” page 5 or 6 times in various flows, and that is really nice!

As always, thanks for reading the SFDCinSEA blog! If you have any questions or comments, let me know!

Automagically create tasks from templates in Salesforce!

Standard

If you are like me, everyday upon waking up, you are craving coffee. This craving requires action and also requires a set number of steps that will repeated as long as this craving is happening (Hopefully, forever and ever). If I were to map this out, it might look like this:Tasks to Coffee

The act of me waking up will prompt a series of tasks, and this is something that is repeatable EVERY TIME.

Now, apply this to your users. How often will the user be DOING something that requires them to CREATE a task or series of tasks? Here are a few examples I could think of:

  • After closing a deal, follow up tasks are scheduled for 30 / 60 / 90 days out
  • After contacting a lead, follow up tasks are scheduled
  • After losing a deal, create a set up follow up tasks

The key to this exercise is identifying ACTIONS that will require a set of tasks to be created. This is the challenge that I decided to take on with my Salesforce BFF visual flow and my Salesforce Frenemy Process Builder. The idea was that when a case meets a certain criteria, a series of tasks will be created…and is this wasn’t challenging enough, I decided to kick it up a notch and design the functionality in such a way that the tasks are not hard coded but actually templatized.

Here are the ingredients to this functionality:

  • “templitized” tasks
  • A flow
  • A process (though, you could use a flow trigger as well)

At a high level, what will happen is that the flow is kicked off via the process (or trigger). The flow does a query of all tasks and ONLY pulls those that meet our templatized criteria. These are then used as templates for the creation of new tasks. The example below is how I built this out so that a series of tasks are created when I mark a case as “Ready for Coffee”.

Enough talking! Release the Screen Shots!

Release the Screen Shots

Step 1 – Create a “templatized” task

In this case, I note that the task is a template by placing a flag on the subject and setting the task status to completed. By setting the status to completed, you can keep the task from staying open and visible on the users home page. In the example I am building out, I am looking for a subject that ends with “!MakeMeCoffee”.

Task Template XLS

I am using the connector for this because…well…it works and I didn’t want to do it by hand!

Step 2 – Create your flow

The basics of the flow is that there is a fast look up to find your templatized tasks and put them into a Sobject Collection. This collection is then looped through with your regular loop de loop, which builds out the set of tasks that will be created. Be sure to build out a formula for the subject field that strips away the template flags,

Build Task Subject

else, well, you might end up with a lot of stuff!

Flow Magic

As usual, when I built out my flow, I built out one version that is driven off of the UI (pictured below). This way, I can do rapid testing without activating anything. After things are 90% happy, I will remove UI elements and save it as a new flow.

Step 3 – Create your process

Process builder is my frenemy…I see the potential, but am still really sore over loosing flow triggers. But, the cool thing is that we have folks out there in the Upper Echelons of Salesforce looking at our comments and reading our blogs and they are making changes and I am excited for where process builder is going! Soapbox aside, I created a process for case and set the criteria.

Criteria Logic - Process Builder

The ONLY thing this process is doing is calling the flow and passing over just enough information to run. In the past when I have used flow triggers, I tended to push over more information, but since process builder requires activate / clone / activate cycle if something goes ker-plewy (for the record, I did this cycle 7(!) times for this demo!), I have switched over to just pushing over the minimum as a variable.

OK, so the work is done, you are all set…Let’s see how this works!

Now, for the proof.

I have my case created, and I am going to check the box that signals that I would like some coffee.Ready...

As you can see, tasks are now created associated with the case.Go!

To emphasize again, the power of the template is that if I (as a user, not a system admin) wanted to change something about the tasks are created, I can do so on my own and not have to wait for a system admin. Another great benefit for the admin / developer is that nothing is hard coded except for template criteria…and even that could be made more dynamic to handle further scenarios.

Further mind blowing awesomeness is that this is NOT just for tasks on cases…it could be anywhere…or even applied to other objects!

Questions / Comments / Buy me a coffee?

Andrew

Add followers with Flows

Standard

Chatter (in my opinion) is one of the really neat features of salesforce, allowing users to follow records that might be important to them is just one of the “Killer Apps” of this functionality. Ironically enough, being that this is a social network, is the request for that one can just add followers automagically if  “X” condition is met. There are even a couple apps on the appexchange for that.

Automated Networking, Jumbo Shrimp, Stop / Keep Moving, OxyMoron

Automated Networking, Jumbo Shrimp, Stop / Keep Moving, OxyMoron

To me, this takes a bit of the social out of “social networking”, so I am going to sketch out a solution that is a bit more personable but still makes it easy to add a follower

In a nutshell, it goes a little something like this:

1)      Within a record, the current user feels that another user (or themselves) should be on the follow list

2)      The current user clicks a button. In this case, I have called it “Pied Piper”

3)      A flow is launched that does the following:

1. Looks up a user based information given

2.Attaches that user to the current record as a follower

As usual, I am just sketching going to provide the foundation for this functionality. The magic here is that you can flows to do some neat stuff like attaching multiple users, adding comments, tags, etc. You don’t have to add this stuff in, but I would encourage playing around with it to see what you can / can’t do. Also, a quick Caveat. I found that a user will have to have “Modify All” permissions on the object you are pushing this out to. 

That aside, now we get to the Nuts & Bolts of the matter. I have got a couple of components that I am going to be using:

  1. A visual flow
  2. A custom button driven by a URL
  3. A nice cup of Coffee (Optional, or not)

This flow function sounds exciting and awesome (Follower Updates, Magic!), but is really basic. There are four components to this flow, Entry screen, Record lookup, Record Create and the confirmation screen (optional). There is however a critical variable, varAccountID. This is the variable that houses the ID that is passed over via URL. Just be aware when you are building this out!

The Components

Salesforce Flows, How awesome

On the entry screen, there is a text box for entry of a person’s name. The text box value is passed to the Record Lookup. One of the easiest improvements would be making this multi search (name, ID, email), just something to keep in mind.

Search Box

The flow does a look up on name, and returns the userID.

2014-05-13 13_15_27-Flow Designer_ public_FlowFromFlow

 

 

Next up is the Record Create on the object Entity Subscription. In this case, the parentID is the accountID, but it can be anything. SubscriberID is just the UserId pulled above.

2014-05-13 12_49_55-Flow Designer_ public_FlowFromFlow

Once the record is created, there is a confirmation screen. This is an optional step, but something I like to do.

Confirmation

Now that I have a flow in place, I create a button (Pied Piper) on the account layout.

Pied Piper Button

1 story point was spent on the clever name

This button is nothing fancy, just running a hyperlink that will open up the flow AND push over the accountID of the record the user is currently in. I did add the retURL on the end so that instead of a loop, the user is returned to the accounts page.

Behind the Curtain

Just to reiterate, this is the foundational work. You could implement this into production and have something that works but it isn’t going to be awesome. Here are the required proof shots!

 

As always, questions or comments, hit me up!

 

andrew

Making a Dynamic Choice That Much Better

Standard

Let’s say that you are writing a flow and at one point you are going to prompt your user for some data that will then be used to populate a dynamic choice field.

Tell me hot shot, how do you handle just one single record?Do you make your user select one and then click through, or is there a better way?

Image “Can I choose not to do Matrix 2 and 3?”

Well, the good news is, you can make a smarter dynamic choice flow. By using some logic and a couple queries, you can choose to display the dynamic choice or bypass it. The reason we can do this is because instead of checking to see how many records are returned, we are just going to check to see if there is more than one. 

The example I am going to use takes a user input of “Last Name” and will check to see if there is ONE or ONE+ records and then determines if the user should see the dynamic choice page or a generic page displayed to the user.

Image

 

1)      Query1 is based on the user input. ID of the first record is passed to a variable (VarID1)

Image

2)      Query2 is based on the user input AND the ID cannot equal VARID1
Image

3)      The results of Query2 is passed to a variable (VarID2). This variable has a default value of zero

4)      Decision point evaluates VarID2 and if the variable DOES NOT equal zero, the dynamic choice screen is presented. Default outcome (in this case) is just a display screen.

Image

5)      Take the rest of the day off (just kidding)

I wish there was more to this, but it really is just a nice piece of logic and the fact that your user doesn’t have a click gate if there is just one record returned will probably go unnoticed, but you will know the truth!

 

EDIT! This blog post really covered this on a high level. If you want a blow by blow account, head over to my buddy Rakesh’s blog…