Like I said in 2016, accounting is still a manual and tedious process.
However, since then I’ve made quite some headway, especially with regard to automatically fetching and storing incoming invoices. By now, all of those thankfully arrive via email, which allows me to have Zapier automatically fetch them and store attached invoice PDFs in the appropriate folders in Google Drive.
One particular, lasting pet peeve of mine in that respect, however, so far has been German railway company Deutsche Bahn AG and the fairly limited and inaccessible (by automated means, that is) way by which they’re giving you access to your invoices. For some convoluted, bureaucratic reason I didn’t fully comprehend they can’t – or won’t – automatically send you invoices for regional train tickets bought online or via their mobile app. All you get is a purchase confirmation email, which doesn’t include the actual invoice. You have to sign in to their online ticket store instead and manually go through a 3-step process for each ticket in order to have an email with the invoice sent to you.
So, there I was. Regularly logging in to the Deutsche Bahn ticket store at the end of each month in order to manually trigger invoice delivery for up to 30 tickets during a busy month with plenty of client meetings and on-site consulting. Triggering the download for each of my public transport invoices for keeping track of my travel expenses so far has been a tedious, recurring monthly task.
Since last week however, I’m using Puppeteer, a popular Node.js library that allows you to programmatically control a Chromium browser in order to access websites in an automated fashion with a bespoke robotic process automation workflow for fetching these invoices.
To that effect, I’ve created and published a small Node.js command line tool called InvoiceFetcher that allows me (and you if you’re having the same or a similar problem) to finally automate this process.
Together with 1Password‘s command-line tool (for not having to store my Deutsche Bahn credentials in plain text somewhere, or alternatively having to remember them) and the tiny Bash script below all I have to do now by the end of each month is to execute a single command, which then automatically takes care of logging into the online store and triggering an invoice email for each ticket.
If you’re wondering where those text files in
~/Google\ Drive/Accounting/db_invoice_numbers come from that get concatenated to
db_invoice_numbers.txt: This is where the purchase confirmation email mentioned above comes in handy. Again, I’m using Zapier to have a text file containing the invoice number created for each such confirmation email.
In order to install and use InvoiceFetcher all you have to do is clone the repository and then run
npm link in the project’s root folder. This will create a symlink to the main
index.js script under the name
invoice-fetcher in your global
node_modules folder, which in turn will allow you to run the
invoice-fetcher command from anywhere on your machine.
Afterwards, you can simply run
invoice-fetcher $DB_USERNAME $DB_PASSWORD $DB_INVOICE_NUMBERS
in order for InvoiceFetcher to retrieve the Deutsche Bahn invoices specified by whitespace-delimited invoice numbers under
The reason why I didn’t publish InvoiceFetcher as a fully-fledged NPM package that can be installed via
npm install yet is that – while enormously useful to me – InvoiceFetcher so far is more of a one-off script that I didn’t want to pollute the official NPM repository with.
If you have any questions about the particulars of these Zapier processes (or “Zaps” as they like to call them) or any of the components and scripts involved in this process automation please get in touch.
eval $(op signin)
cd ~/Google\ Drive/Accounting/db_invoice_numbers
cat *.txt > ../db_invoice_numbers.txt
while read db_invoice_number; do
done < ~/Google\ Drive/Accounting/db_invoice_numbers.txt
invoice-fetcher $(op get item ITEM_KEY --fields username) $(op get item ITEM_KEY --fields password) $db_invoice_numbers
Update 23/10/2020: The project has been renamed to InvoiceRobot.