Plain text is worth it

Posted on January 07, 2018 • 2 min read

hledger is one of my favorite pieces of software. Written in haskell, it allows you to balance your books by recording transactions in a simple plain text format, which looks like this:

2018/01/01 Supermarket
    Expenses:Groceries           $45
    Assets:Cash                 $-45

Expenses go up, assets go down, balance is maintained. My discipline on this front waxes and wanes, but no matter how out of whack my books are at any given time, I always manage to balance them in January so that filing taxes for the previous year is slightly less brutal. Normally this is a bit tedious, as I've only automated the process with enough duct tape and bash to get the job done. Something like this (using reckon to properly categorize new transactions) is typical:

reckon -l 2017.ledger -f some_bank.csv -a "Assets:Some Bank" >> 2017.ledger

Too cheap to pay my banks' extortionate fees for automatically downloading my own data, I typically download either .qfx, .ofx, or .csv from their sites and massage it into the ledger format.

Citi made a bad website for Costco

Costco dumped AmEx a couple of years ago and started offering Visa cards provided by Citi.

The default transaction view is sane; that is, you can see all of the transactions for a given time period via tabular HTML. There is a "Print Screen" button. There is a search form with a dropdown that allows you to view individual statements. However, there is no "Download Transactions" button. I stared at this view for quite a while, assuming I was missing something. Apparently, what I was missing was the "Spend Summary" link, which takes you to a page that looks like:

Spend Summary

Almost unbelievably, it's only possible to download a single category from this view. You cannot download an entire "Year to Date" .csv!

Back to the JSON

Returning to the HTML transaction view, it was a relief to see that the tabular transaction view was populated by a mere XHR call. Firefox's network monitor lets you save a .har file containing a record of the data transferred during the browser session.

Now that I actually had a way to download a complete log of transactions, the only thing left was to write an abomination that combined the power of jq, perl -pie, and reckon to output proper ledger files:

#!/usr/bin/env bash

set -euxo pipefail


function har2csv() {
    jq -r '
      .log.entries[] |
      select(.response.content.mimeType == "application/json") |
      .response.content.text |
      fromjson |
      .accountActivity.postedTransactionJournals[] |
      .columns |
      map(.activityColumn) |
      flatten |
      del(.[] | nulls) |
      map(gsub("[\\n]"; "")) |
      map("\"" + . + "\"") |
      join (",")'

function clean() {
    tr '|' ' ' | perl -p -i -e 's/\$ //'

reckon -f <(cat $HAR | har2csv | clean) \
       --date-format '%B. %e, %Y %T' \
       -u -i "$@"

Thanks Citi!