- Python 99%
- Nix <1%
Hefter #
Hefter imports bank statements into ledger-cli plain text account format.
hleder already has built-in support for csv import, but I want more features:
- Interaction: I want to review and change a transaction before commiting it to the journal.
- Learn from data: I don't want to write rules to rewrite subject and account.
- Import from PDF: Some unnamed credit card providers still cannot export CSV files.
- I want to type this and be done:
hefter <file.csv> <file-2.csv> <file.pdf>
How it works #
It reads your $LEDGER_JOURNAL; it follow include statements.
A rules file ($HEFTER_RULES) defines what file patterns should be
processed by what source (CSV, PDF) and what account is linked to these statements:
rule "my-bank" {
pattern "export_DE23*_*.*.*.csv" // use globs
account "Assets:My Bank"
source type="csv" {
skip 1 // skip the header row
columns date=4 aux_date=5 subject=6 note=10 amount=11 // map transaction fields to columns
currency "EUR" // default currency for amounts
// check that the header row contains the expected column names
assertions {
date row=0 value="Buchungstag"
aux_date row=0 value="Valutadatum"
subject row=0 value="Name Zahlungsbeteiligter"
note row=0 value="Verwendungszweck"
amount row=0 value="Betrag"
// you can check any row in any named column
}
// deal with locales
date_format "%d.%m.%Y" // strptime() format codes, see here: https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior
delimiter ";"
decimal_separator ","
}
}
rule "my-credit-card" {
pattern "report-202*-*-*.pdf"
account "Liabilities:My Credit Card"
source type="pdf" {
// finds the largest table on each page, expects a header row
columns date=1 aux_date=0 note=2 amount=4 // subject and note are optional, but at least one must be set
currency "EUR"
// assertions always refer to the header row
assertions {
date value="Transaktions-datum"
aux_date value="Buchungsdatum"
}
date_format "%d.%m.%Y"
decimal_separator ","
// strip newlines from columns, e.g., `Transaktions-\ndatum` becomes `Transaktions-datum`
strip_newlines
// remove duplicate whitespace from subject and note
strip_duplicate_whitespace
// replace / delete with regular expressions
replace "Kartenumsatz" with="" in="note"
// also works as block
replace {
"Verwendungszweck: (.+)" with="\\1" in="note"
"Bäcker (.+)$" with="Bäcker" in="subject"
}
// ... or ignore whole rows based on content
ignore "^Gutschrift" in="note"
// (also works as block)
}
}
Sources yield bank statements (date, auxiliary date, subject, note and amount).
Bank statements that have a matching transaction in the ledger are ignored.
The rest are shown to the user to change subject, target account, and dates.
Users can accept or discard an item.
Accepetd bank statements are turned into proper transactions with postings and all that and then saved to $LEDGER_FILE.