I saw a post today that talked about a business need to give Sub-Opportunities (some related record that sits under the Opportunity object) an Excel-esque naming schema. If the Parent Opportunity was named 2401-0005 and there were 5 child records, their names should be:

  1. 2401-0005A
  2. 2401-0005B
  3. 2401-0005C
  4. 2401-0005D
  5. 2401-0005E

Our 25th through 30th records should be:

  1. 2401-0005Y
  2. 2401-0005Z
  3. 2401-0005AA
  4. 2401-0005AB
  5. 2401-0005AC

Immediately, we run into a few challenges to make this happen in Flow exclusively, such as creating a map of trailing digits to match letter designations. If the business suddenly experiences growth or the format is to be changed, this solution can be a bit "brute force" and challenging to maintain moving forward. This would be quite a bit easier if we could use something like Apex's charAt() method, which would allow us to dynamically retrieve letters from an alphabet string, but Flow as of today offers no such functionality. Even if Flow did offer that functionality, how would we write our 27th sub-record (2401-0005AA) with Flow-based tools?

As such, an Apex Invokable might be a smart choice here until Salesforce provides a better way to search and retrieve characters by index. We can use some repurposed Java code (retrofitted to Apex) to do this for us. We will:

  1. Use a Record-Triggered Flow to kick off the automation we need to run (on the creation of the Sub-Account record, but realistically this can be used on anything to return this naming convention)
  2. Using the Opportunity lookup in $Record, I want to go out and check how many Sub-records there are
    1. To do this, we will use a Get Records element to get all the Sub-Opportunities with the same $Record.Opportunity__c lookup
    2. Using an assignment block, we will then use the 'Equals Count' operator to see how many records we have returned
  3. We will then feed this returned count integer into our Apex Invokable

Here is the Flow so far:

Our Flow used to give Excel-style naming to these Sub-object records
the getSubOpportunities element
the getCountOfSubOpportunities element

Now, here is the Apex Invokable logic that makes it all work:

public with sharing class columnNameGenerator {
    @InvocableMethod(label='Give Name with Column-naming-convention' description='A-ZZ' category='Account')
    public static List<List<String>> columnNameGenerator(List<Integer> whichNumberSubOppIsThis) {
        List<List<String>> returnList = new List<List<String>>();
        for(Integer s : whichNumberSubOppIsThis){
            Integer n = s; 
            List<String> sb = new List<String>();
            List<String> result = new List<String>();
            List<String> alphabets = new List<String>{'A','B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
            for(Integer j = 0; j < n; j++){
                Integer index = j/26;   
                String item = '';
                if(index > 0) {
                    item += alphabets[index-1];
                }
                item += alphabets[math.mod(j,26)];
                result.add(item);
            }
        sb.add(result.get(result.size()-1));
        returnList.add(sb);
        }
    return returnList;
    }
}

columnNameGenerator.cls

This class:

  1. Accepts a list of Integers (containing your sub-record count)
  2. Declares a list containing letters of the alphabet
  3. Iterates as many times as your provided count
  4. Divides your count by the number of letters in the alphabet
    1. If the integer result is greater than 1 (e.g. 27/26), it will add the letter from the index (-1) that represents that value (e.g. 1=A)
  5. Appends the second letter, which for counts 1-26 will be the only letter
  6. Adds the final element of the list to a list of lists to get sent back to Flow
🩹
This code is configured only to work up to Sub-record #702, which is name 'ZZ'

We then use the output of that Invokable Apex and append that to the default prefix we are using. This can be done in a formula field:

{!$Record.Opportunity__r.Name}+ '-'+{!getcolumnstylename}

And that's it! We can also spot-check input-value pairs by overwriting the entrance parameter with our own:

15 records => O
29 records => AC
217 records => HI

Giving records Lettered Excel-column-style naming conventions in Salesforce using Flow & Apex