Welcome to the Lazy Bookkeeper

2019-04-04 4-minute read

Welcome to the first (and given my laziness, possibly last) installment of the lazy bookkeeper. I’m actually not really a bookkeeper at all, so if you are looking for a legal and sound way to keep your books, don’t read this post.

I am lazy though.

I’m tasked with keeping the books on a US organization with a budget of about $150,000. I hate doing bookkeeping so I’ve naturally tried to automate everything I possibly can. I’ll explain how I do it in this blog.

The first two (and most important) steps are to use GnuCash and the GnuCash Python bindings. Last I checked about a year ago, the Python bindings were not working with the Python3 version of GnuCash so you may need to hold back on that version.


Income is easier then expenses, perhaps because we have so little of it :).

The only source of income for the organization are:

  • Membership dues (accounting for almost everything)
  • Donations
  • Program related income (e.g. contracts)
  • Interest (like $10 every year)

We get income via credit card payments (both Stripe and Paypal) and checks.

We have two external systems that handle Membership dues (our custom control panel software) and Donations (CiviCRM).

The custom control panel software automatically generates new membership invoices and sends reminders to people to pay them.

When I get checks, I:

  • Take a picture of the check with my phone
  • Copy it to a Nextcloud account in a folder called: Checks to be processed
  • Enter the checks manually in either our control panel or CiviCRM databases so the sender can be properly credited (these are our single sources of truth for such things)
  • Deposit the checks and take a picture of the receipt (and share it with the same next Nextcloud folder as the checks)

At this point in the process, I had to struggle against my lazy instincts to take an additional step to solve two problems:

  1. The checks are named based on date/time I took them picture. Not that helpful if I’m looking at a list of them
  2. Entering the checks manually is a source of typos and mistakes - which is a substantial cause of misery when bookkeeping.

So, I’ve written a simple script that reads all the pictures of all the checks and then displays them one by one.

For each check that is displayed, I am prompted to enter the check number. The script then queries the control panel for that check number and displays the member it was coded against and the amount. I check these details with the check itself and confirm it.

Then, the script moves the check from the “checks to be processed” folder to a new folder (in a YYYY/MM format) and renames it to include the check number, short version of the organization it is applied against and the amount in the name itself.

The last step is that every few weeks I run a script to import data from both the control panel and the CiviCRM database.

The script finds control panel invoices and payments and donations in CiviCRM and automatically creates the records in GnuCash.


Expenses have been a much harder nut to crack. For many years I simply put all receipts in a giant folder and then, after waiting until the last possible moment, I would go through them all an enter them. I made a Python script to facilitate it - it asks how much the expense is for, what category it should be coded to, etc. However, this task was particularly tedious because I usually couldn’t remember what any expense was for.

So, this year I’ve instituted a new system. I have a set of folders named after each expense account. Now, when I get a receipt, I name it in the format: invoice-number_brief-description_YYYY-MM-DD_00.00_bank.pdf and I save it in the folder matching the expense account.

In short, I am doing the sorting every time a receipt comes in rather than waiting until the end of the year.

Then, I have a script that validates all of my names (in case I made any typos) and automatically imports everything in to GnuCash.

The only other expense to deal with is payroll, so I’ve naturally scripted that as well. I do have to run it for every payroll and enter the variations in random state taxes and such, but by using a terminal script I don’t have to click around the GnuCash interface.


The only part I can’t automate is the reconciliation. However, by minimizing typos it is much easier. Basically consisting of:

  1. Entering interest and bank fees
  2. Tracking down expenses I didn’t get receipts for

The scripts

These scripts can’t be directly used by anyone else and will be useless if you think of them as general purpose scripts. However, if you want to do something similar for your own purposes, you may find them helpful as a way to see how certain items can be imported into GnuCash.