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

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

03/19/2019 by Mario Di Genio
In the first of this two-part series, we’ll take a look at how a developer might configure autonumber functionality with code.

As a developer, there’s a number of requests that I frequently receive. Though not all have the same level of complexity, the one thing they all have in common is the fact that the request cannot be accomplished (or at least not exactly the way the customer wants it to work) with the admin tools Salesforce has to offer.

Among these are the requests that are short-time development features, that can be easily completed within a day or two. The ones I like to call “one trigger to go, please”: get the request, do the coding, add unit testing, test it out, put together the change set, and off it goes.

For these “to-go” features sometimes there’s an alternative that can be done with Salesforce admin tools. So why still go with development in those cases? Let’s follow a case study to figure out our options and the pros and cons of each. In this first post we’ll see how a developer provides a solution.

The Request

Our customer wants to use autonumber for naming only one particular type of Opportunities (let’s call it “AutoNumber RT”). They do not want to use autonumber on any other Opportunity Record Types. It must start numbering with: 1690. The desired behavior is when an Opportunity of that type is entered into Salesforce, it gets autonumbered beginning at #001690 and so on.

The Analysis

The 3 things we need to remember for our implementation are:

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

It’s important to keep a concise list of the requirements, so that while you are implementing the solution you don’t forget any of the items. The formatting is something that especially tends to be overlooked when you get excited about the main logic finally working.

The Research

What is an Autonumber Field?

The first step is to research how autonumber works. This type of field, as described by Salesforce, is “a system-generated sequence number that uses a display format you define. The number is automatically incremented for each new record.” The options offered to configure it mostly cover formatting and start number. The only option that would make this field configurable for more complex purposes would be to make it an external ID (which means that it would be turned into an indexed field and therefore used in queries for filtering a large number of records). But that’s not applicable to cover our request.

Autonumber does not offer options to only count records that meet certain conditions, such as for certain Record Types or records that contain specific values in certain fields. It will keep counting no matter the type of record that is created as well; because it’s an autonumber on the same object, no matter which Record Type, it will keep increasing. For our request, we don’t want to count all records but only the ones of a certain type, so we cannot use this type of field.

Also, an autonumber field keeps counting forward even if the last record is deleted. If you create Opportunity 002222, then delete it, the next new Opportunity would be numbered 002223. It will not detect that the last number was deleted and can be reused. This also creates gaps in the sequence that cannot be bypassed if you want to keep the numbering consistent.

Why is Conditional Autonumbering not Implemented Already?

In Salesforce’s defense, the way autonumber fields work is the same as in any database; it’s not something particular to the platform, but a basic element of the database structure. I cannot speak on Salesforce’s behalf as to why it is not implemented, but I can make some assumptions about the difficulty to do this if I were to implement it.

Autonumber is an automatic field that works like a formula; it’s produced by the system, and it is never editable in the layout for the user (or even a System Administrator) to be able to enter it in certain cases and let it automatically calculate in others. For this reason, if Salesforce wanted to allow conditional autonumbering, it would also require changes on the way the layout behaves.

This sounds fairly easy if the conditions are only based on Record Type, because when you create a record you always have to select the Record Type first. After the Record Type is selected, the layout can display the field as editable if it does not meet the Record Type conditions. If the Record Type does meet the conditions, then don’t display the autonumber field during editing and show it after saving with the number generated as non-editable.

To me, adding a slightly different behavior based on Record Type is reasonable and frequently  requested by customers, as this related idea states as well: Different Field Names, Based on Record Type.

But if the conditions for autonumbering were set on values that the user enters in any other field, Salesforce would have to show the layout in editing mode with the field editable at first (since it does not have any values entered in any field), and then based on the values entered by the user continuously re-render the layout making the autonumber editable or not as it meets or not the conditions with every input. This type of re-rendering as the user inputs data is very commonly resolved with coding and takes some time to implement correctly. It can also be very disruptive for the user to be entering information and having sections of the page appear and disappear, so it’s just not a usability good practice.

Still, regardless of our opinions, our customer is waiting and we need to provide a solution with the tools we have available today. So let’s get to it.

The Options

Back to our original request; if an autonumber field is not an option for this case, then what can we do? Here’s where your own abilities come into play whether you are an administrator or developer. We’re going to explore both options, coding and admin tools, and the different challenges that come up with each.

The Coding Way

The request is very direct as to what it needs to do; it needs to happen upon record creation, based on past records created to continue the numbering. What can be executed immediately before or after an operation on a record and retrieve additional records to make a decision? A trigger.

For the Record Type:

  • AutoNumber RT: autonumber the Name field of the Opportunity as one increment from the last record created of the same Record Type.
  • Non-AutoNumber RT:  do not autonumber the Name field of the Opportunity and take the name entered by the user.

The Name field needs to be editable by the user in one of the cases, and the customer does not want us to develop a special page or component for the input of the Opportunity to control this based on the Record Type selected, so we’re going to leave the Name field as a text field editable at all times. The name is required; no matter the Record Type the user will have to enter a value, and if it’s the Autonumber RT, then we overwrite it with the autonumber value. Otherwise we leave the value entered by the user.

In the trigger we need to:

  1. Retrieve the ID of the Record Type we need to autonumber (Line 3).
  2. Retrieve the last Opportunity of that Record Type and the autonumber value it was assigned (Line 5).
  3. Set the number by default as the start number, which we store in a label for easy configuration in case it changes after deployment (Line 7).
  4. If there’s a previous record created of this type, then transform it into a number (Line 10). If there’s no previous record created of this type before, or for any reason the record has a value that is not numeric, then assign the first value of the sequence (1690 as requested).
  5. For every Opportunity that was created (Line 14), assign an increment of 1 (Line 16) as the autonumbered name (Line 18).
    1. If the number is less than 6 digits, then add the zeros to the left to complete the length.
    2. This is the line that would probably require a couple of tries to get it right.

This is the label to store the first value to start the counting:

Since all type of code in Salesforce needs unit testing in order to be deployed to a production environment, we create a test class for our trigger. Test classes can be configured to take into account the data currently in the system or to ignore it and assume there are no records created at all. Since our request is very simple and we know exactly the number that the sequence must start with, we create an Opportunity and validate that our trigger created it with the first number of the sequence (1690).

In the test class we need to:

  1. Retrieve the ID of the Record Type we need to autonumber (Line 6).
  2. Create an Opportunity of the Record Type Autonumber RT (Line 8 and 11).
  3. Retrieve the information of the Opportunity we just created with the data that our trigger should have auto-populated (Line 14).
  4. Validate that the autonumber name field has the number 001690 assigned (Line 15).


This class executes all lines of the trigger giving it 100% coverage, allowing us to deploy it to a production environment (any coding must be covered for at least 75% of its lines).

We test it out, and it works correctly; only the Record Types we want have the field autonumbered (Autonumber Name field):

We put together the change set, and we’re ready to deploy.

This is something that as a developer with some experience you can do well in an hour or so and have it ready for deployment. Since everything is very direct, and we have all the information of what we do in the same screen (the trigger code), complete view of the variables, additional information retrieved, and what’s going to be executed all in one place.

One possible issue to consider is if you already have triggers created on the object; these may be your own development or packages you have installed. In this case, you may have to either merge your code so that you have only one trigger per object as this is a good practice, because there’s no way to know or determine which trigger executes first for the same object and same event. Of course you should test as thoroughly as possible to make sure that what was working before is still working now in addition to your functionality.

The only little trick here is to transform the name field of the previous record into a number to be able to increment it in one, and then transform it again into a string and add the left padding with zeros to comply with the formatting.

In the second post of this series we’ll dive into how you can use admin tools to create a solution to the same problem. Stay tuned...


In the meantime, here are some resources to get started with triggers:

How do you feel about triggers now? Too complex or easy to handle? Tell me all about it in the comments below, in the Salesforce Trailblazer Community, or tweet directly at me @mdigenioarkus.