A Shortcut for Reminders

I’ve written several times about how I keep track of and follow up on unpaid invoices, most recently here. It’s a system that’s evolved over time to become both more automated and less reliant on me being in my office in front of my Mac. This past weekend, I wrote a Shortcut that allows me to quickly calculate the total of my outstanding invoices from an iOS device., something I’ve been able to do on my Mac for quite a while.

To recap, every time I generate and send out an invoice at work, an item is added to my Invoices list in Reminders. The Reminder is set to follow up with the client 45 days1 after the invoice is issued (assuming it hasn’t been paid) and includes the project name, project number, invoice number, and invoiced amount.

Invoice list in Reminders

What I wanted was a quick way to get the total of all those dollar amounts in parentheses. The solution was a Shortcut, named Unpaid, that was saved to my home screen and then stored in a folder with other work-related items.

Unpaid shortcut saved to home screen

Tapping the Unpaid icon runs the shortcut, which finishes by displaying a dialog box with the number of unpaid invoices and their total.

Results of Unpaid shortcut

It’s obviously not good when this number gets too high, but it’s also bad when it gets too low. That usually means I’ve been delinquent in sending out invoices.

The Unpaid shortcut, which is on all my iDevices, looks like this:

Unpaid shortcut source code

The first two steps initialize the variable total to zero. This is where we’ll accumulate the sum of all the invoiced amounts.

The next step gets all the items in the Invoices list that are unchecked. I should mention that all these reminders are set to repeat. Checking an item on the list doesn’t mean the bill has been paid, it means that I’ve sent a followup email on the bill, and it creates an new item to follow up again two weeks later. When an invoice is paid, I delete its reminder from the list.

We then get a count of the reminders, which we’ll use later.

The bulk of the work is done by a loop that goes through each item in the list, pulling out the title (Get Details of Reminders), extracting the parenthetical with a regular expression (Match Text), deleting the extraneous characters—parentheses, dollar sign, comma—from that string (Replace Text and Get Item from List), and adding that amount to the running total (Calculate and Set Variable).

Finally, total is formatted with commas (Replace Text) and included with the item count in message to the user (Show Result).

Overall, it’s a pretty simple shortcut. The trickiest parts are the regular expressions. If you don’t care about regexes, you can consider the post finished right here. The rest is a discussion of how each of them work.


The first regex, in Match Text, is this:

\(\$[^)]+\)

It’s messy because it has to escape the dollar sign and the parentheses at the beginning and end. But the idea is simple: find any string that starts with an opening parenthesis and a dollar sign and collect every character through the first closing parenthesis.

The second regular expression, in the first Replace Text step, is this:

[()$,]

It defines a character class consisting of opening and closing parentheses, dollar signs, and commas. Any instance of this class is replaced by an empty string, i.e, deleted. I do this because the amount of the invoice has to be parsed as a number, and these extraneous characters prevent that.2

An unstated feature of Shortcuts’s Replace Text step is that it performs a global replace. All instances of the find string are replaced, not just the first one. In Perl terms, this is like using the g flag.

Finally, we have the hardest regex, the one in the final Replace Text:

(\d)(?=(\d{3})+\.)

I adapted this from a Stack Overflow answer that handled integers. It starts with a digit and then the (?=… ) construct, which is called a positive lookahead. The lookahead finds groups of three digits (one or more of such groups) followed by a period. The key is that the regex engine considers the lookahead to have zero width, which has two effects:

  1. It allows us to use the simple replace string,

    $1,
    

    which puts a comma after the digit captured in the first set of parentheses. We don’t have to worry about the part of the string matched in the lookahead because the engine considers the match to have ended just after the captured digit.3

  2. It means that after the first replacement, the regex continues its search after the comma. This allows it to put commas between all the groupings of three digits. The pattern will not only convert 51600.61 to 51,600.61, it will also convert 51600600.61 to 51,600,600.61, and so on, into the billions, trillions, etc. If the search pattern had been

    (\d)((\d{3})+\.)
    

    and the replacement pattern

    $1,$2
    

    we’d turn 51600.61 into 51,600.61 as before, but 51600600.61 would be turned into 51,600600.61 because the search would pick up after the period and skip the second comma. The zero-width makes all the difference.

You could, of course, argue that this application has no need to format numbers in the millions or higher. I’ve never even had as much as a six-figure accumulation of unpaid invoices, let alone a seven-figure one. So a simpler pattern, one that anticipates no more than one comma separator, would work. But it’s more fun to explore the dark corners and learn new things.


  1. Strictly speaking, it’s the first Tuesday that comes after 45 days, but that detail isn’t important here. 

  2. Actually, Shortcuts seems to be able to parse commas in numeric strings, but I deleted them anyway to be on the safe side. 

  3. Oddly, you can capture things by using parentheses inside the lookahead construct, but the regex engine still considers the match to have ended just before the lookahead.