adept / full-fledged-hledger

Tutorial on Hledger setup with multi-year files, multi-source imports and a range of auto-generated reports
https://github.com/adept/full-fledged-hledger/wiki
BSD 3-Clause "New" or "Revised" License
399 stars 32 forks source link

Statements that span year boundaries #27

Open jtdoepke opened 1 year ago

jtdoepke commented 1 year ago

Hello, thank you making this repository; having an accounting system that you can rebuild and version control has been really great!

I was wondering if you have any advice for handling account statements that don't align to month boundaries?

I'd like to keep my transactions in CSV files that match the PDF statements I receive so that I can quickly error-check the journal files against the beginning and ending balance on the statement.

However, at least some of my accounts issue statements that don't align to the beginning and end of months. For example, I have a credit card whose January statement spans from Dec. 13 to Jan. 12.

This isn't a problem for most of the year, but around Dec-Jan it messes with the autogenerated opening and closing balances, and the yearly reports all include multiple years. The best idea I have so far is to split up the transactions like this:

csv/
├── 2022-12.csv        # Transactions from the Dec. 2022 statement.
├── 2022-to-2023.csv   # Dec. transactions from the Jan. 2023 statement. 
└── 2023-01.csv        # The rest of the transactions from the Jan. 2023 statement.

And then create separate .journal files that are only used for error-checking:

2022-12-13 beginning balance
    liabilities:credit cards:card name      $-1234.00 = $-1234.00
    equity:opening/closing balances

include journal/2022-to-2023.journal
include journal/2023-01.journal

2023-01-12 ending balance
    liabilities:credit cards:card name      = $-5678.00

Is there a better way to do this? Am I missing something obvious?

adept commented 1 year ago

I have a similar problem with one of my providers, and what I resorted to do is to handle this in the in2csv script.

Incoming statements go into import/provider/in/Provider-YYYY-MM.csv. For Dec statement, a statement for Jan next year is added to the list of inputs for in2csv via:

extraInputs file
  | Just [year] <- filePattern "Provider-*-Dec.csv" file =
      let next = (read year + 1)::Int in [printf "Provider-%d-Jan.csv" next]
  | otherwise = []

And then in2csv is written to assume either 1 or 2 input files. It extracts the year from the filename of the first file, processes them both, and then filters the output to that year - by piping the output through grep.

This way, processing Dec statement would always effectively "append" Jan statement to it, but then filter out transactions that belong to the next year, leaving you with a cleaned-up csv that is split on the year boundary.