aboutsummaryrefslogtreecommitdiffstats
path: root/README.md
blob: 06061d1c373790b49f8d99e6f9d160acc56d1a70 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
# journal

![Build Status](https://github.com/mpolden/journal/workflows/ci/badge.svg)

`journal` is a program for storing and displaying financial records.

## Features

* 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.

## Installation

Building and installing `journal` requires the [Golang
compiler](https://golang.org/). 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](https://golang.org/doc/code.html).

## Example

My bank account exists at *Example Bank* with the account number
*1234.56.78900*. The bank supports export of records to CSV.

### Configuration

The first step is to configure our bank accounts and match groups.

`journal` uses the [TOML](https://github.com/toml-lang/toml) configuration
format and expects to find its configuration file in `~/.journalrc`.

Example:

```toml
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.

### Export file

Most Norwegian banks support export to CSV. This can usually be done through
your bank's web interface.

CSV export example:

```csv
"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";"";""

```

### Importing records

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.
 
### Listing records

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.

### Export records

Record groups can be exported to
[CSV](https://en.wikipedia.org/wiki/Comma-separated_values) 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.