Admin Tools vs Coding: So you Think you can Autonumber? Part Two

04/16/2019 by Mario Di Genio
In the second post of this two-part series, we’ll dive into how an admin could resolve the conditional autonumber problem.

The Autonumber Options

In the first part of this series, we explored how to add autonumber functionality the coding way. Now let’s explore the admin tools way. As a quick refresher, the three things we need to remember for our autonumber implementation are:

  • Autonumber only for certain Record Types
  • Start numbering with 1690
  • Follow a 6 digit format
The Admin Tools Way

We’re gonna give it a try and see how we can accomplish the same thing we did with coding but using the out-of-the-box tools of Salesforce. What can be executed immediately after an operation on a record? A workflow rule.

The problem: Since we need to take into account past records (to detect the last number generated), workflow rules are not an option, as they just allow you to work with the current record only.

So what’s next in line in the order of execution of Salesforce that we could use:

    1. Executes all before triggers.
    2. Runs most system validation steps again, such as verifying that all required fields have a non-null value, and runs any user-defined validation rules.
    3. Executes duplicate rules.
    4. Saves the record to the database, but doesn't commit yet.
    5. Executes all after triggers.
    6. Executes assignment rules.
    7. Executes auto-response rules.
    8. Executes workflow rules.
    9. If there are workflow field updates, updates the record again.
    10. If the record was updated with workflow field updates, fires before update triggers and after update triggers one more time (and only one more time), in addition to standard validations. Custom validation rules, duplicate rules, and escalation rules are not run again.
    11. Executes processes and flows launched via processes and flow trigger workflow actions. 
      1. When a process or flow executes a DML operation, the affected record goes through the save procedure. Executes escalation rules.
    12. Executes entitlement rules.
    13. If the record contains a roll-up summary field or is part of a cross-object workflow, performs calculations and updates the roll-up summary field in the parent record. Parent record goes through save procedure.
    14. If the parent record is updated, and a grandparent record contains a roll-up summary field or is part of a cross-object workflow, performs calculations and updates the roll-up summary field in the grandparent record.
    15. Grandparent record goes through save procedure.
    16. Executes Criteria Based Sharing evaluation.
    17. Commits all DML operations to the database.
    18. Executes post-commit logic, such as sending email.

With Process Builder, we could include the same type of actions that a workflow rule would, but we can also add a Flow, which would allow us to go through other records to get the last autonumber value generated, increment it and assign it to the new record. This seems like a viable path, so let’s give it a go.

First, I create the flow. I want to have that step of querying the last record created asap to make sure that it’s possible. I add the “Get Records” step:

  1. Enter the label
  2. Select Opportunity in the “Get Records of This Object”
  3. Filter Opportunity Records
  4. And... I cannot filter by Record Type name, it only accepts the Id.

MG-Code-2-1.png

So I close the screen, go back to the setup (since you don’t have the setup menu on the left in the flow feature), try to go to the Record Type (which in lightning takes a bit more clicks since standard objects are no longer directly in the setup menu and you need to go to object manager first), go to the object, go to the Record Type, get the ID, and make it all the way back to the flow.

Back in the flow, I add the “Get Records” step (yet again):

  1. Enter the label
  2. Select Opportunity in the “Get Records of This Object”
  3. Filter Opportunity Records
  4. Filter by Record Type Id.
  5. Select the “Sort Opportunity Records”
  6. Go to “Select Variable to Store Opportunity”
  7. Create the Record Variable to store it (this allows you to store the entire record and all the fields you may need to process)
  8. Select Opportunity Fields to Store in Variable
  9. Save

MG-Code-2-2.png

Now I can debug and see if the step works and gets the last Opportunity created, and it looks like it does.

Then I create the process builder to call when an Opportunity is created. Since the flow is already created, this is something I could just go in, create the process builder, add the flow, and that’s it.

MG-Code-2-3.png

Then I go back to the Flow and start thinking about how to retrieve the Opportunity record that the execution comes from. Now, when you have practice with process builder, you’d have probably figured this one out first, but in the world of triggers the list of records that started the execution is already provided with Trigger.old and Trigger.new, so no need to do anything else. I create a variable to store the current Opportunity in the flow, save as a new version, activate, go back to the process builder, deactivate, add the variable to pass the Opportunity ID to the flow, save as a new version and activate. Also note, I could have done this as well with the Record Type ID, so that it’s not hardcoded in the flow, as when I set up the Get Records step.

MG-Code-2-4.png

This is what I see as a downside to using these tools. The fact that you have to go back and forth, that you can’t just save or deactivate and save, but you have to save as another version. This adds a lot of back and forth, clicks and screens that need to be displayed that consume some valuable time. In coding, you would have it all in the same screen; you just scroll up a bit and change the variable, and that would be it.

Back again in the flow, I add the decision step depending on whether there’s already an Opportunity created or not:

MG-Code-2-5.png

Add the steps for assigning in the case there’s no previous Opportunity:

MG-Code-2-6.png

And then try to add the step to increment in 1 in the case there’s a previous Opportunity. Now the problem is: how do we increment the number we have from the previous Opportunity by 1? Well, this is a tricky one. Here’s the thing: in coding, I can easily transform a string that represents a number into a number. But in flow, we need to have the field already as a number to be able to increment it (flow does not have functions to transform a text into its numeric value). So I need to make some adjustments to my model before I’m able to continue. And it’s time to navigate back to the Opportunity object (since I thought I was done with that and have already closed the tab :( ).

Go back to setup, go to object manager, go to the object, go to the fields, create a number field to store the name’s number as a number and make it all the way back to the flow.

I have to make sure that the “Get Records” step brings the new field I created, the decision step applies on that field, and it’s able to go to the assignment in both cases and take that field as the one to be assigned.

Which leads us to the next problem: I need to assign to the current Opportunity field the value of the previous Opportunity incremented by 1. And flow only allows you to either assign a field the value of a variable or increment the value of that same field, but not both at a time.

Now the assignment turns into 2 assignments:

  1. Assign the number value of the previous record to the new record:

MG-Code-2-7.png

  1. Increment the value in the new record by 1:

MG-Code-2-13.png

And last but not least, we need to make sure the record is updated, so we add the “Update Records” step for the current Opportunity. Now we seem to have it all, ready to test it out.

MG-Code-2-16.pngMG-Code-2-8.png

The problem is (yet again): we had to create a new field of type number to be able to do the increment, and we’re storing the autonumber value there instead of the name, as we needed in the first place. So we would have to create a third assignment of the number field to the name.

And there’s also the issue with the formatting; we want the autonumber to be displayed with zeros to the left to complete a 6-digit sequence. So we move on to the next trick; instead of doing the increment in the flow, we can do it in a formula, the formula can turn the autonumber field from a text to a number, increment it in 1 and format it back as text, with the zeros to the left.

MG-Code-2-10.png

Each record would have the autonumber field for their name and then the formula field to produce the next autonumber field to assign. This requires me once again to modify all the steps of the process builder to retrieve and assign correctly. And this would require only one assignment, since all the heavy logic is actually done by the formula. This is how our flow looks at the end:

MG-Code-2-14.png

We test it out, and a regular autonumber field would continue to count, but our Autonumber Name field counts only the ones of the indicated Record Type, and the formula Autonumber Next Name generates the name already formatted for the next record.

MG-Code-2-15.png

So as you can see it was quite a journey to get here, and it did take a village, and 16 versions of the flow, and a couple of tricks to make it work. Depending on your skills, maybe you already knew how to solve this from the start, or you would have gone through the same back-and-forth as I did.

There is the formula resource in flow, which works just as well for the increment and formatting, but the issue I found with it is that the editor does not have the syntax helper that the formula field has. So you need to know exactly the formula you need, in order to be able to use it in a resource, and then put it as the value to assign.

Conclusion

Process Builder and particularly Flow are very powerful tools; they give administrators the power to perform a wide variety of operations they could not do otherwise without coding. But when you are implementing a solution, back and forth is inevitable; you think of things that come up at every minute. When every line of code turns into several screens in flow or any other admin tool, it starts to consume more time than coding. Saving every time as a new version is good on one hand, as you have all the different changes saved in case you need to go back to a previous version, but it’s yet another screen to open and go through. If you need to know what value was assigned to a variable, you have to open every assignment step in your flow to find out which one contains your variable and the value assigned.

There’s also the tricks that you have to be inspired to come up with, to sort through the minutiae of the solutions with admin tools - things that in code can be resolved in one line, directly in the same screen where you have the rest of your solution, yet with flow you have to find a workaround, as we did with the formula to resolve the increment and the formatting of our autonumber.

So coding may still hold a one up here. Even when you have to create unit testing for it, when it’s a simple case like this, it does not take as long as navigating through several screens to find a workaround for something that is not even the solution to the problem itself, but for limitations of the platform. This factors in heavily when delivery time is tight.

Of course, this entire discussion could have been spared, if conditional Autonumber was possible from the start, at least with Record Type-based conditions. Yet I hope this shed some light as to why sometimes one solution is more preferable than others, even when the tools are provided to solve it either way.

The Takeaway

If you need to perform transformations of data, leverage your flow or process builder with auto-calculating fields, such as formulas and roll-up summaries. Also if a value you need to put in your current record depends on the immediate previous record, consider calculating the value in the latter with a formula, so you just have to retrieve it and assign it.

Make it Happen

If this post got your autonumber gears turning, here are some interesting ideas you can vote for:

Resources

How would you resolve this request: coding or admin tools? Tell me all about it in the comments below, in the Salesforce Trailblazer Community, or tweet directly at me @mdigenioarkus.