journal
is a program for storing and displaying financial records.
- Import financial records from multiple Norwegian banks:
- Bank Norwegian (XLS)
- Bulder Bank (custom CSV)
- DNB (XLS)
- Eika Group (most local banks), Storebrand and many others (standard CSV)
- Komplett Bank (JSON)
- Identify spending habits using automatic grouping of records.
- Define budgets for record groups.
- Export record groups for further processing in other programs.
- Take ownership of your financial records. All data is stored in a SQLite database.
Building and installing journal
requires the Golang
compiler. With Go installed, journal
can be installed
with:
go install github.com/mpolden/journal/...@latest
This will build and install journal
in $GOPATH/bin/journal
.
For more information on building a Go project, see the official Go documentation.
My bank account exists at Example Bank with the account number 1234.56.78900. The bank supports export of records to CSV.
The first step is to configure our bank accounts and match groups.
journal
uses the TOML configuration
format and expects to find its configuration file in ~/.journalrc
.
Example:
database = "/home/user/journal.db"
comma = "."
defaultGroup = "* ungrouped *"
[[accounts]]
number = "1234.56.78900"
name = "Example Bank"
[[groups]]
name = "Public Transportation"
budgets = [
-5000, # January
-5000, # February
-5000, # March
-5000, # April
-5000, # May
-5000, # June
0, # July
0, # August
-5000, # September
-5000, # October
-5000, # November
-5000, # December
]
patterns = ["(?i)^Atb"]
[[groups]]
name = "Groceries"
budget = -100000
patterns = ["(?i)^Rema"]
[[groups]]
name = "One-off purchases"
ids = [
"deadbeef",
"cafebabe",
]
[[groups]]
name = "Ignored records"
pattern = ["^Spam"]
discard = true
database
specifies where the SQLite database containing our records should be
stored.
comma
is the decimal separator to use when displaying monetary amounts.
Defaults to .
defaultGroup
is the default group name to use for unmatched records. Defaults
to * ungrouped *
.
[[accounts]]
declares known bank accounts. The section can be repeated to
define multiple accounts. Importing records for an unknown account is an error.
[[groups]]
declares how records should be grouped together. name
sets the
group name and patterns
sets the list of regular expressions that match record
texts. The section can be repeated to declare multiple groups.
If any of the patterns in patterns
match, the group is considered a match for
a given record. Matching follows the order declared in the configuration file,
where the first matching group wins.
Records can be pinned to a group using the ids
key. This avoids the need to
create patterns for records that may only occur once. The ids
key must be an
array of IDs to pin. Pinning takes precedence over matching patterns. Record IDs
can be found with journal ls --explain
.
A monthly budget can be set per group by with the budget
key. The budget is
specified as one-hundredth of the currency. budget = -50000
means a budget of
-500,00 NOK .
When listing records for multiple months, the budget will be multiplied by the
number of months in the displayed time range. E.g. with budget = -50000
and $ journal ls --since 2018-05-01 --until 2018-07-01
, the total budget will be 3 * -50000 = -150000
.
It's also possible to set a custom budget for each month using the budgets
key. The value of budgets
has to be an array of 12 numbers, one per month. If
budgets
is unset, the value of budget
will be used for all months.
Unwanted records may pollute the journal (e.g. inter-account transfers), these
records can be ignored entirely by setting discard = true
on the matching
group.
Most Norwegian banks support export to CSV. This can usually be done through your bank's web interface.
CSV export example:
"01.06.2018";"01.06.2018";"Rema 1000";"-1.000,00";"5.000,00";"";""
"05.06.2018";"05.06.2018";"Rema 1000";"-500,00";"4.500,00";"";""
"07.06.2018";"07.06.2018";"Atb";"-35,00";"4.465,00";"";""
"09.06.2018";"09.06.2018";"Rema 1000";"-800,00";"3.665,00";"";""
"15.06.2018";"15.06.2018";"Atb";"-35,00";"3.630,00";"";""
"01.07.2018";"01.07.2018";"Rema 1000";"-250,00";"3.595,00";"";""
"02.07.2018";"02.07.2018";"Atb";"-35,00";"3.560,00";"";""
"05.07.2018";"05.07.2018";"Rema 1000";"-750,00";"2.810,00";"";""
"07.07.2018";"07.07.2018";"Atb";"-35,00";"2.775,00";"";""
"15.07.2018";"15.07.2018";"Atb";"-35,00";"2.740,00";"";""
The command journal import
is used to import records. Given the export file
and configuration above, records can be imported with:
$ journal import 1234.56.78900 example.csv
journal: created 1 new account(s)
journal: imported 10 new record(s) out of 10 total
Records have now been stored in a SQLite database located in
/home/user/journal.db
.
Repeating the import only imports records journal
hasn't seen before, so
running the above command again imports 0 records:
$ journal import 1234.56.78900 example.csv
journal: created 0 new account(s)
journal: imported 0 new record(s) out of 10 total
Some banks have their own export format, in such cases the correct reader must be specified when importing records. Example for Bank Norwegian:
$ journal import -r norwegian 1234.56.78900 norwegian-export.xlsx
See journal import -h
for complete usage.
Now that we have imported records, they can be listed with journal ls
:
$ journal ls
journal: displaying records for all accounts between 2018-07-01 and 2018-07-28
+-----------------------+---------+----------+----------+---------+--------------------------------+
| GROUP | RECORDS | SUM | BUDGET | BALANCE | BALANCE BAR |
+-----------------------+---------+----------+----------+---------+--------------------------------+
| Groceries | 2 | -1000.00 | -1000.00 | 0.00 | |
| Public Transportation | 3 | -105.00 | -50.00 | 55.00 | ++++++++++++++ |
+-----------------------+---------+----------+----------+---------+--------------------------------+
| Total | 5 | -1105.00 | -1050.00 | 55.00 | ++++++++++++++ |
+-----------------------+---------+----------+----------+---------+--------------------------------+
By default, only records within the current month are listed and sorted descending by sum.
Records are grouped together according to configured match groups. If we want to understand a record grouping, we can list individual records and their group:
$ journal ls --since=2018-07-01 --until=2018-07-31 --explain
journal: displaying records for all accounts between 2018-07-01 and 2018-07-31
+---------------+--------------+------------+------------+-----------------------+-----------+----------+
| ACCOUNT | ACCOUNT NAME | ID | DATE | GROUP | TEXT | AMOUNT |
+---------------+--------------+------------+------------+-----------------------+-----------+----------+
| 1234.56.78900 | Example Bank | 77c2a500e1 | 2018-07-05 | Groceries | Rema 1000 | -750.00 |
| 1234.56.78900 | Example Bank | 8f864212ce | 2018-07-01 | Groceries | Rema 1000 | -250.00 |
| 1234.56.78900 | Example Bank | 2e25c40379 | 2018-07-15 | Public Transportation | Atb | -35.00 |
| 1234.56.78900 | Example Bank | 84ca136809 | 2018-07-07 | Public Transportation | Atb | -35.00 |
| 1234.56.78900 | Example Bank | 5833456f0b | 2018-07-02 | Public Transportation | Atb | -35.00 |
+---------------+--------------+------------+------------+-----------------------+-----------+----------+
| TOTAL | -1105.00 |
+---------------+--------------+------------+------------+-----------------------+-----------+----------+
If we want show older records, date ranges can be specified using --since
and
--until
:
$ journal ls --since=2018-06-01 --until=2018-07-31
journal: displaying records for all accounts between 2018-06-01 and 2018-07-31
+-----------------------+---------+----------+----------+---------+--------------------------------+
| GROUP | RECORDS | SUM | BUDGET | BALANCE | BALANCE BAR |
+-----------------------+---------+----------+----------+---------+--------------------------------+
| Groceries | 5 | -3300.00 | -4000.00 | -700.00 | ---------------- |
| Public Transportation | 5 | -175.00 | -100.00 | 75.00 | ++ |
+-----------------------+---------+----------+----------+---------+--------------------------------+
| Total | 10 | -3475.00 | -4100.00 | -625.00 | ---------------- |
+-----------------------+---------+----------+----------+---------+--------------------------------+
Note that the budget has been automatically adjusted to the number of months that contain records.
The option --month
can be used to show records for the most recent month.
journal ls --month=7
is equivalent to journal ls --since=2018-07-01 --until=2018-07-31
where 2018
is substituted for the current calendar year.
If the given month is after the current month, records from the previous year
are displayed instead. E.g. if the current date is in January 2019, journal ls --month=3
is equivalent to journal ls --since=2018-03-01 --until=2018-03-31
.
Options also be combined:
$ journal ls --since=2018-01-01 --explain
journal: displaying records for all accounts between 2018-01-01 and 2018-07-31
+---------------+--------------+------------+------------+-----------------------+-----------+----------+
| ACCOUNT | ACCOUNT NAME | ID | DATE | GROUP | TEXT | AMOUNT |
+---------------+--------------+------------+------------+-----------------------+-----------+----------+
| 1234.56.78900 | Example Bank | e6c18424ba | 2018-06-01 | Groceries | Rema 1000 | -1000.00 |
| 1234.56.78900 | Example Bank | b6b2496771 | 2018-06-09 | Groceries | Rema 1000 | -800.00 |
| 1234.56.78900 | Example Bank | 77c2a500e1 | 2018-07-05 | Groceries | Rema 1000 | -750.00 |
| 1234.56.78900 | Example Bank | 2e1aa3cf1a | 2018-06-05 | Groceries | Rema 1000 | -500.00 |
| 1234.56.78900 | Example Bank | 8f864212ce | 2018-07-01 | Groceries | Rema 1000 | -250.00 |
| 1234.56.78900 | Example Bank | 2e25c40379 | 2018-07-15 | Public Transportation | Atb | -35.00 |
| 1234.56.78900 | Example Bank | 84ca136809 | 2018-07-07 | Public Transportation | Atb | -35.00 |
| 1234.56.78900 | Example Bank | 5833456f0b | 2018-07-02 | Public Transportation | Atb | -35.00 |
| 1234.56.78900 | Example Bank | 2e8e1ac9e1 | 2018-06-15 | Public Transportation | Atb | -35.00 |
| 1234.56.78900 | Example Bank | 84c948c456 | 2018-06-07 | Public Transportation | Atb | -35.00 |
+---------------+--------------+------------+------------+-----------------------+-----------+----------+
| TOTAL | -3475.00 |
+---------------+--------------+------------+------------+-----------------------+-----------+----------+
See journal ls -h
for complete usage.
Record groups can be exported to CSV for further processing in other programs such as a spreadsheet.
$ journal export --since=2018-01-01
2018-07,Groceries,-1000.00
2018-07,Public Transportation,-105.00
2018-06,Groceries,-2300.00
2018-06,Public Transportation,-70.00
See journal export -h
for complete usage.