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

Advertisements

Dynamic Screens using Visualforce and Flows

Standard

 

Oh boy, do I have something real nice for you all today!

Real nice.jpg

Something Real Nice!

Let’s say, you find myself in the world of action adventure blockbuster “Pacific Rim”. You are tracking Kaiju in an object called “Kaiju” and and tracking Jaegers with an object called “Jaeger”. From the detail page of Kaiju, I create a new detail button called “Dispatch Jaeger” that runs a flow by calling a Visualforce page. I know this is not typical, but stick with me! This flow associates the selected Jaeger to the Kaiju so then the whupping can commence!

Kaiju vs Jaeger

That works pretty well, but a user will always have to be on a Kaiju detail page to dispatch a Jaeger, so it might be good to put something on the home page that allows someone to either dispatch a Jaeger on an existing Kaiju OR create a new Kaiju and Dispatch a Jaeger all at once.

The first place I went is the google verse because I thought I would just create a small Visualforce page with an input box on do some sort of URL hack to get it to push a value to the already created Visualforce page that launches my flow. Turns out, there is really no such thing as “small” when it comes to this type of stuff. Most of the articles I read involved some sort of controller, so my overhead went pretty quickly from one Visualforce page to Visualforce page + controller + tester.

Back to the drawing board I went!

2015-12-09 15_45_16-pacific rim whiteboard - Google Search.png

I remembered some early work I did with flows where I used a decision element as my starting point, which would then direct a user to certain pages. I decided to explore the option of using this, and it worked!

Here is what I did! I modified my dispatch Jaeger flow so that the starting element is a decision.

Flow Overview

Starting Decision

This decision checks to see if KaijuId is being passed over from the Visualforce page, which it would be if you were launching it from Kaiju Detail. If this value does not start with the prefix for the Kaiju record (This works WAAAY better than checking for null or not null), it redirects to the newly created “quick dispatch” screen element.

I added my Visualforce page to my home screen and boom, my flow correctly presented me with the quick create screen!Home Page

However, I still needed the ability to create a dispatch from the detail screen, so let’s click the button and see what happens!

Dispatch from Record Yep, the flow determines that I am running a dispatch from a record detail and points me to the right screen!

To sum it up…I was able to with Zero Extra Code, modify my flow so that two different screens are presented to the user based on if they were dispatching a Jaeger from a specific Kaiju, or were having to dispatch a Jaeger from the home page via a quick create function.

Dispatch jaeger VF code
You might also be wondering why I am using a visualforce page? Well, if you want to run flows in a community, you have to wrap that flow in a visualforce page…That being said, you can totally do this same type of thing with a URL launched flow too…the functionality is really the same with the novelty part of this being that it works within Visualforce.

So, that wraps this post up! Thanks for checking it, comments / questions are always appreciated.
Also, quick note, I will be at the Salesforce World Tour in Seattle on the 17th. I would be more than happy to talk about flows or other Salesforce awesomeness, just look for this guy:

Salesforce in Seattle!

I am smiling because I support Salesforce

Attaching a copy of an email alert in Salesforce

Standard

How long has it been? A long freaking time!
Long timeBetween summer vacations, coaching soccer and cub scouts, there has not been much idle time for this boy to blog, which stinks because there has been so much fun stuff figured out!

But, here I am, eating a turkey sammich, listing to some EDM on Slacker Radio and trying to get a blog post cranked out for you all.

What I am going to blog about is an annoyance that has been going on for quite some time… the issue of workflow email alerts. In fact, this idea is over 5 years old!

See, when you build out an email alert and it fires…well…it just fires. You can do a work around that involves carbon copys to an email to salesforce box or creating activities, but those workarounds are either not scaleable or they don’t give you much more information than “this email was sent!”.

But, I did find a work around that is scalable using my favoritest thing ever, flows*. Now, did you see that little thing there? That Asterix? Yep, that is there for a reason. It is there because I wrote this out using flow triggers. I am sure you can do this with process builder, but I am just documenting the flow trigger function here. I like process builder, but in this case, I just need to crank something out quick, so I am using triggers.

The “Too Long; didn’t read” version is this. I created a flow that runs via the workflow (remember, I am using flow triggers!). When that flow trigger runs, it will do two things. It will send off the email alert AND create an emailmessage record. Yeppers, I said create an emailmessage. What I have found is that within salesforce you can create an email record through a flow and it will happily sit there. The trick is that you will need to pass the record ID from where you are starting and use that ID for the “parent ID” field on the emailmessage record.

This is a good jumping off point if you want to venture forth and tinker around yourself. For those of you that want more details, here ya go!

My assumptions at this point are that you are comfortable creating your own method of running this flow. As long as you can pass variables over from the record, you should be good to go. This flow only has two elements. The email alert (which is already built) and the record create for the email message. There are a bunch of things you can build out when you create the email message, but I am just going to cover the basics.

  • Parent ID – this should be the record you want this emailmessage living under. In my case, it was, well, case.
  • Status – Status is a funny one. It is displayed in plain English but the value is actually numeric. In my case, I am recording a copy of a sent email, so I used a status of 3, which is “sent”.
  • EmailMessageBody – An interesting thing about this method is how the text is displayed. You will actually be creating the emailmessage.body by using the field “HTMLbody” and to make it so the text looks nice, you will need to do the following:
  • Create a text template called “LineBreak”. This text template will just have the HTML value for break “<BR>”

Line break

  • Create a text template called “Email body”. Enter your data and insert the text template “linebreak” wherever there should be a line break. If you need to get values from the parent record, insert them here. I choose to pass them all over via the flow trigger, but you could just as easily do it with a requrery.

Linebreak being used

The end result is that the emailmessage you created via the flow will have a similar look / feel to the email that was sent out via the alert. Actually, it will look way more like the Text version, but really the point is to have this copy not so much to look pretty.

As I said before, I will leave the method of running this flow up to you, so let’s talk about the results.

By doing this, I was able to get a copy of the alert email attached to the parent. I was then able to remove the activity creation on the workflow since that was how we were noting that an email was sent out. The email copy is an actual copy, so we know what was sent out, which you couldn’t do through the activity. As an added benefit, running this via the flow allowed me to do some extra shenanigans that you really cannot do through a workflow, like running queries on other objects and adding them to the email.

The last benefit is crazy obvious, this is a LOW maintenance function. If a new value is added to the email alert, I (or another admin) just needs to add it to the record creation function…no dev time needed!

As always, let me know if there are questions / comments

 

andrew

 

 

Cleaner Page Layouts using Flows and Formulas (1 of 3)

Standard

Back in the day, when I was just a transfer student at Everett Community College, “one week” was a hit single and I was a newbie coder taking visual basic.

(Your welcome for this ear worm)

During this class, we had a discussion on page layouts, that went a little something like this:

If you design a layout that has a bad tab order, and it reduces the speed of a transaction by one second, is it a big deal? Well, consider it this way: If your software is bought by a million people, and they can complete 500 transactions a day, your one second reduction of efficiency is costing the consumer 500000000 seconds per day…which is 8,333,333 minutes or 138,888 hours. If the average wage of those users is ten dollars an hour, your one second in efficiency now has cost 1.3million dollars per day.

Not even a Lego Calculator could make that discussion cool

With guilt trip thusly set to “argh”, I focused my efforts on UI design and making things work efficiently. Even now, I can remember the tab order of one of my first CRM’s I worked on…because it was out of order.

The stakes have changed since I was taking Visual Basic. I (we) support sales, and lost productivity is not simply about lost time, but about what your sales teams COULD have been doing. The math is pretty easy…and pretty scary:

Time spent clicking / scrolling / using salesforce in an inefficient manner

X by Number of times

X by Number of Users

X by days in year

= Time wasted = Money Lost = No free coffee

For the sake of this blog post, I am going to clean up the contact layout. I have sat with my users and estimated that they waste about 2 seconds every time they hit the layout  because of a section that Marketing has requested. This section consists of four check boxes, three text boxes and one URL field in a two column layout. This section was created for marketing and was placed near to the top of the layout in return for the data not being required. This section pushed a much more used section down below the scroll line (IE, users would have to scroll to see it). Marketing has given the OK on making this section not visible as long as there is some visual refernce to these fields still on the page layout.

A user will typically hit the contact layout 25 times per day and I have 25 users. If I can compact the layout, I should be able to reduce scroll time by about half, which should save about 45 (sales) hours per year. Notice, I didn’t just say hours, I said sales hours. Sure, saving 45 regular hours might not be much in the whole scheme of things, but sales hours is like a force multiplier. If you enabled your sales teams to have even a few more minutes per week, they can make a few more calls, make a few more emails, make a few more dollars.

Take a minute to enjoy this worn out cat.

Phew

I am beat just writing about this!

I am going to break this whole thing out into three distinct chunks:

1)      Create the Summarizing Formulas (In this blog)

2)      Create the Visual Prompts (Next Blog)

3)      Make Data Entry awesome with Flows (Next Next Blog)

Summarizing Formulas

Personally, I tend to write smaller, nested formulas that analyze bits and pieces of data. This makes it a bit easier (in my opinion) to write that final formula that presents the results to the user. While you could probably write this all in one huge formula, for the sake of troubleshooting and scalability, I am going to create the following fields:

1)      Create a formula to look at the 3 text fields (Return Type is Text)

Text(

if(len(Test_Text_1__c)>0,1,0)+

if(len(Test_Text_2__c)>0,1,0)+

if(len(Test_Text_3__c)>0,1,0))&” out of 3 populated; ”

Text Box Formula

2)      Create a formula to look at the URL field (Return Type is Text)

if(len(Test_URL__c)>0,”URL Present”,”URL Not Present”)

URL Formula

3)      Create a formula to look at the check box fields (Return Type is Text)

Text(

if(Example_Check_Box1__c=TRUE,1,0)+

if(Example_Check_Box_2__c=TRUE,1,0)+

if(Example_Check_Box_3__c=TRUE,1,0)+

if(Example_Check_Box_4__c=TRUE,1,0))&” out of 4 set to True; “Check Box Formula

4)      Create a formula to aggregate the above

Check_Example_CheckBox__c &” “& Check_Test_Text__c &” “& Check_Test_URL__cAggregate Formula

The net result is a field that will present the user with data facts not data entry points. Aside from having a cleaner layout, I a firm believer that if presented with text, most humans brains at least acknowlege that text before moving on. By reducing the clutter, you are making your overall page layout less fatiguing.

End Result

Individual Results

In the next post, I am going to discuss how we are going to visually prompt the user to give us data, but until then consider the other benefits of this type of functionality:

1) You could use these fields in reports to give better summaries

2) You could write validation rules off of these formulas rather than the individual fields

3) You could write workflows off of these formulas

See you all next week, same BatTime, same BatChannel where I will show you all how to kick it up a notch and grab your users attention!

Kick it up a notch

You totally thought I was doing Batman pic, weren’t you?

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