hledger-forecast 0.4.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +1 -1
- data/.gitignore +1 -0
- data/.rubocop.yml +3 -0
- data/README.md +111 -41
- data/example.journal +33 -22
- data/example.yml +40 -26
- data/hledger-forecast.gemspec +1 -0
- data/lib/hledger_forecast/calculator.rb +21 -0
- data/lib/hledger_forecast/cli.rb +27 -2
- data/lib/hledger_forecast/formatter.rb +24 -0
- data/lib/hledger_forecast/generator.rb +41 -258
- data/lib/hledger_forecast/settings.rb +41 -0
- data/lib/hledger_forecast/summarizer.rb +106 -0
- data/lib/hledger_forecast/summarizer_formatter.rb +115 -0
- data/lib/hledger_forecast/transactions/default.rb +88 -0
- data/lib/hledger_forecast/transactions/modifiers.rb +90 -0
- data/lib/hledger_forecast/transactions/trackers.rb +87 -0
- data/lib/hledger_forecast/version.rb +1 -1
- data/lib/hledger_forecast.rb +12 -4
- data/spec/custom_spec.rb +31 -4
- data/spec/modifier_spec.rb +21 -6
- data/spec/monthly_end_date_spec.rb +18 -33
- data/spec/monthly_end_date_transaction_spec.rb +44 -7
- data/spec/monthly_spec.rb +7 -7
- data/spec/summarizer_spec.rb +86 -0
- data/spec/track_spec.rb +5 -67
- metadata +15 -7
- data/lib/hledger_forecast/summarize.rb +0 -134
- data/lib/hledger_forecast/tracker.rb +0 -37
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 37dbc9f011b6a43fa1d186e92dfb77c3c184cdb4a7cc5ef690a77d53c57f4722
|
4
|
+
data.tar.gz: e71185f0ad678b45f1ffa155c89c491bd37d36307d845dd023b823db6ced42d4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d25713fb91fde68daaa07f6809a3c567afc18864a759e47fd032c31cd78cbe195eba2919deff4547d2fe6888e032f7394af4012aea839d1fc6b3d4ee7b1e94bf
|
7
|
+
data.tar.gz: 363185c38d788ae91528dc1fde6e21201fc19bec673848202a43589c36c8be3f6fe8e54cb367bfb8652ea286eda6513ab38e86e20aef99f8b7011cb1351fed3b
|
data/.github/workflows/ci.yml
CHANGED
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -1,20 +1,28 @@
|
|
1
|
-
|
1
|
+
<p align="center">
|
2
|
+
<img src="https://github.com/olimorris/hledger-forecast/assets/9512444/5edb77e3-0ec6-4158-9b16-3978c1259879" alt="hledger-forecast" />
|
3
|
+
</p>
|
2
4
|
|
3
|
-
|
5
|
+
<h1 align="center">hledger-forecast</h1>
|
4
6
|
|
5
|
-
|
7
|
+
<p align="center">
|
8
|
+
<a href="https://github.com/olimorris/hledger-forecast/stargazers"><img src="https://img.shields.io/github/stars/olimorris/hledger-forecast?color=c678dd&logoColor=e06c75&style=for-the-badge"></a>
|
9
|
+
<a href="https://github.com/olimorris/hledger-forecast/issues"><img src="https://img.shields.io/github/issues/olimorris/hledger-forecast?color=%23d19a66&style=for-the-badge"></a>
|
10
|
+
<a href="https://github.com/olimorris/hledger-forecast/blob/main/LICENSE"><img src="https://img.shields.io/github/license/olimorris/hledger-forecast?color=%2361afef&style=for-the-badge"></a>
|
11
|
+
<a href="https://github.com/olimorris/hledger-forecast/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/olimorris/hledger-forecast/ci.yml?branch=main&label=tests&style=for-the-badge"></a>
|
12
|
+
</p>
|
6
13
|
|
7
|
-
|
14
|
+
**"Improved", you say?** Using a _yaml_ file, forecasts can be quickly generated into a _journal_ file ready to be fed into [hledger](https://github.com/simonmichael/hledger). Forecasts can be easily constrained between dates, inflated by modifiers, tracked until they appear in your bank statements and summarized into your own daily/weekly/monthly/yearly personal forecast income and expenditure statement.
|
15
|
+
|
16
|
+
I **strongly** recommend you read the [rationale](#paintbrush-rationale) section to see if this app might be useful to you.
|
8
17
|
|
9
18
|
## :sparkles: Features
|
10
19
|
|
11
20
|
- :book: Uses a simple yaml file to generate forecasts which can be used with hledger
|
12
|
-
- :date: Can smartly track
|
21
|
+
- :date: Can smartly track forecasts against your bank statement
|
13
22
|
- :moneybag: Can automatically apply modifiers such as inflation/deflation to forecasts
|
14
|
-
- :abacus:
|
15
|
-
- :
|
23
|
+
- :abacus: Enables the use of maths in your forecasts (for amounts and dates)
|
24
|
+
- :chart_with_upwards_trend: Display your forecasts as income and expenditure reports (e.g. daily, weekly, monthly)
|
16
25
|
- :computer: Simple and easy to use CLI
|
17
|
-
- :chart_with_upwards_trend: Summarize your forecasts by period and category and output to the CLI
|
18
26
|
|
19
27
|
## :package: Installation
|
20
28
|
|
@@ -42,7 +50,7 @@ The available options are:
|
|
42
50
|
|
43
51
|
### Generate command
|
44
52
|
|
45
|
-
The `hledger-forecast generate` command will generate a forecast
|
53
|
+
The `hledger-forecast generate` command will generate a forecast _from_ a `yaml` file _to_ a journal file. You can see the output of this command in the [example.journal](https://github.com/olimorris/hledger-forecast/blob/main/example.journal) file.
|
46
54
|
|
47
55
|
The available options are:
|
48
56
|
|
@@ -59,7 +67,7 @@ The available options are:
|
|
59
67
|
|
60
68
|
Running the command with no options will assume a `forecast.yml` file exists.
|
61
69
|
|
62
|
-
### Using with
|
70
|
+
### Using with hledger
|
63
71
|
|
64
72
|
To work with hledger, include the forecast file and use the `--forecast` flag:
|
65
73
|
|
@@ -67,11 +75,13 @@ To work with hledger, include the forecast file and use the `--forecast` flag:
|
|
67
75
|
|
68
76
|
The command will generate a forecast up to the end of Feb 2024, showing the balance for any asset accounts, overlaying some bank transactions with the forecast journal file. Of course, refer to the [hledger](https://hledger.org/dev/hledger.html) documentation for more information on how to query your finances.
|
69
77
|
|
70
|
-
To apply any modifiers, use the `--auto` flag at the end of your command.
|
78
|
+
> **Note**: To apply any modifiers, use the `--auto` flag at the end of your command.
|
71
79
|
|
72
80
|
### Summarize command
|
73
81
|
|
74
|
-
As your `yaml` configuration file grows, it can be helpful to sum up the total amounts and output them to the CLI.
|
82
|
+
As your `yaml` configuration file grows, it can be helpful to sum up the total amounts and output them to the CLI.
|
83
|
+
Furthermore, being able to see your monthly profit and loss statement _if_ you were to purchase that new item may
|
84
|
+
influence your buying decision. In hledger-forecast, this can be achieved by:
|
75
85
|
|
76
86
|
hledger-forecast summarize -f my_forecast.yml
|
77
87
|
|
@@ -79,14 +89,16 @@ The available options are:
|
|
79
89
|
|
80
90
|
Usage: hledger-forecast summarize [options]
|
81
91
|
|
82
|
-
|
83
|
-
|
92
|
+
-f, --forecast FILE The path to the FORECAST yaml file to summarize
|
93
|
+
-r, --roll-up PERIOD The period to roll-up your forecasts into. One of:
|
94
|
+
[yearly], [half-yearly], [quarterly], [monthly], [weekly], [daily]
|
95
|
+
-h, --help Show this help message
|
84
96
|
|
85
97
|
## :gear: Configuration
|
86
98
|
|
87
|
-
### The
|
99
|
+
### The yaml file
|
88
100
|
|
89
|
-
> **Note**: See the [example.yml](https://github.com/olimorris/hledger-forecast/blob/main/example.yml) file for an example
|
101
|
+
> **Note**: See the [example.yml](https://github.com/olimorris/hledger-forecast/blob/main/example.yml) file for an example config and its corresponding [output](https://github.com/olimorris/hledger-forecast/blob/main/example.journal)
|
90
102
|
|
91
103
|
Firstly, create a `yaml` file which will contain the transactions you'd like to forecast:
|
92
104
|
|
@@ -175,6 +187,17 @@ monthly:
|
|
175
187
|
to: "2025-01-01"
|
176
188
|
```
|
177
189
|
|
190
|
+
It can also be useful to compute a `to` date by adding on a number of months to the `from` date. Extending the example above:
|
191
|
+
|
192
|
+
```yaml
|
193
|
+
- amount: 125
|
194
|
+
category: "Expenses:Holiday"
|
195
|
+
description: Holiday
|
196
|
+
to: "=12"
|
197
|
+
```
|
198
|
+
|
199
|
+
This will take the `to` date to _2024-02-29_. This can be useful if you know a payment is due to end in _n_ months time and don't wish to use one of the many date calculators on the internet.
|
200
|
+
|
178
201
|
### Calculated amounts
|
179
202
|
|
180
203
|
> **Note**: Calculations will be determined up to two decimal places
|
@@ -191,7 +214,7 @@ monthly:
|
|
191
214
|
description: New Kitchen
|
192
215
|
```
|
193
216
|
|
194
|
-
Simply ensure that the amount starts with an `=` sign, is enclosed in quotation marks and uses standard mathematical notations.
|
217
|
+
Simply ensure that the amount starts with an `=` sign, is enclosed in quotation marks and uses standard mathematical notations. Of course, it may make sense to restrict this transaction with a `to` date in months, as per the [transaction level dates](#transaction-level) section.
|
195
218
|
|
196
219
|
### Tracking transactions
|
197
220
|
|
@@ -203,10 +226,10 @@ To mark transactions as available for tracking you may use the `track` option in
|
|
203
226
|
|
204
227
|
```yaml
|
205
228
|
once:
|
206
|
-
|
229
|
+
- account: "Assets:Bank"
|
207
230
|
from: "2023-03-05"
|
208
231
|
transactions:
|
209
|
-
- amount: 3000
|
232
|
+
- amount: -3000
|
210
233
|
category: "Expenses:Shopping"
|
211
234
|
description: Refund for that damn laptop
|
212
235
|
track: true
|
@@ -220,7 +243,7 @@ To use this feature, ensure you pass a filepath to the `-t` flag, such as:
|
|
220
243
|
|
221
244
|
The app will use a hledger query to determine if the combination of category and amount is present in the periods between the `from` key and the current date in the journal file you've specified. If not, then the app will include it as a forecast transaction in the output file.
|
222
245
|
|
223
|
-
###
|
246
|
+
### Modifiers
|
224
247
|
|
225
248
|
> **Note**: For modifiers to be included in your hledger reporting, use the `--auto` flag
|
226
249
|
|
@@ -228,17 +251,17 @@ Within your forecasts, it can be useful to reflect future increases/decreases in
|
|
228
251
|
|
229
252
|
```yaml
|
230
253
|
monthly:
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
254
|
+
account: "Assets:Bank"
|
255
|
+
from: "2023-03-05"
|
256
|
+
transactions:
|
257
|
+
- amount: 450
|
258
|
+
category: "Expenses:Groceries"
|
259
|
+
description: Food shopping
|
260
|
+
modifiers:
|
261
|
+
- amount: 0.02
|
262
|
+
description: "Inflation"
|
263
|
+
from: "2024-01-01"
|
264
|
+
to: "2024-12-31"
|
242
265
|
```
|
243
266
|
|
244
267
|
This will generate an [auto-posting](https://hledger.org/dev/hledger.html#auto-postings) in your forecast which will
|
@@ -259,15 +282,64 @@ modifiers:
|
|
259
282
|
to: "2025-12-31"
|
260
283
|
```
|
261
284
|
|
262
|
-
###
|
285
|
+
### Roll-ups
|
286
|
+
|
287
|
+
As part of the summarize command, it can be useful to sum-up all of the transactions in your `yaml` file and see what your income and expenditure is over a given period (e.g. "how much profit do I _actually_ make every year when all of my costs are taken into account?").
|
288
|
+
|
289
|
+
In order to do this, custom forecasts need to have the `roll-up` key defined. That is, given the custom period you've specified, what number do you need to multiply the amount by in order to "roll it up" into an annualised figure. Let's look at the example below:
|
290
|
+
|
291
|
+
```yaml
|
292
|
+
custom:
|
293
|
+
- frequency: "every 2 weeks"
|
294
|
+
account: "Assets:Bank"
|
295
|
+
from: "2023-03-01"
|
296
|
+
roll-up: 26
|
297
|
+
transactions:
|
298
|
+
- amount: 80
|
299
|
+
category: "Expenses:Personal Care"
|
300
|
+
description: Hair and beauty
|
301
|
+
```
|
302
|
+
|
303
|
+
Every 2 weeks a planned expense of £80 is made. So over the course of a year, we'd need to multiply that amount by 26 to get to an annualised figure. Of course for periods like `monthly` and `quarterly` it's easy for hledger-forecast to annualise those amounts so no `roll-up` is required.
|
304
|
+
|
305
|
+
To see the monthly summary of your `yaml` file, the following command can be used:
|
306
|
+
|
307
|
+
hledger-forecast summarize -f my_forecast.yml -r monthly
|
308
|
+
|
309
|
+
You can also roll-up with the following periods:
|
310
|
+
|
311
|
+
- daily
|
312
|
+
- weekly
|
313
|
+
- monthly
|
314
|
+
- quarterly
|
315
|
+
- half-yearly
|
316
|
+
- yearly
|
317
|
+
|
318
|
+
### Summary exclusions
|
319
|
+
|
320
|
+
It can be useful to exclude certain items from your summary, like one-off items. This can be achieved by specifying `summary_exclude: true` next to a transaction:
|
321
|
+
|
322
|
+
```yaml
|
323
|
+
once:
|
324
|
+
- account: "Assets:Bank"
|
325
|
+
from: "2023-03-05"
|
326
|
+
transactions:
|
327
|
+
- amount: -3000
|
328
|
+
category: "Expenses:Shopping"
|
329
|
+
description: Refund for that damn laptop
|
330
|
+
summary_exclude: true
|
331
|
+
track: true
|
332
|
+
```
|
333
|
+
|
334
|
+
### Additional config settings
|
263
335
|
|
264
336
|
Additional settings in the config file to consider:
|
265
337
|
|
266
338
|
```yaml
|
267
339
|
settings:
|
268
|
-
currency: GBP
|
269
|
-
show_symbol: true
|
270
|
-
thousands_separator: true
|
340
|
+
currency: GBP # Specify the currency to use
|
341
|
+
show_symbol: true # Show the currency symbol?
|
342
|
+
thousands_separator: true # Separate thousands with a comma?
|
271
343
|
```
|
272
344
|
|
273
345
|
## :camera_flash: Screenshots
|
@@ -282,12 +354,10 @@ settings:
|
|
282
354
|
|
283
355
|
## :paintbrush: Rationale
|
284
356
|
|
285
|
-
|
286
|
-
|
287
|
-
Regarding the latter; I may be expecting a material amount of money to leave my account in May (perhaps for a holiday booking). But maybe, that booking ends up leaving in July instead. Whilst I would have accounted for that expense in my forecast, it will be tied to some date in May. So if that transaction doesn't appear in the "actuals" of my May bank statement (which I import into hledger), it won't be included in my forecast at all (as the latest transaction period will be greater than the forecast period). The impact is that my forecasted balance in any future month could be $X better off than reality. Being able to automatically look out for these transactions, and include them if they're not present, is a nice time saver.
|
357
|
+
I moved to hledger from my trusty Excel macro workbook. This thing had been with me for 5+ years. I used it to workout whether I could afford that new gadget and when I'd be in a position to buy a house. I used it to see if I was on track to have £X in my savings accounts by a given date as well as see how much money I could save on a monthly basis. That time I accidentally double counted my bonus or thought I'd accounted for my credit card bill? Painful! Set me back a few months in terms of my savings plans. In summary, I relied _heavily_ on having a detailed and accurate forecast.
|
288
358
|
|
289
|
-
|
359
|
+
I love hledger. Switching from Excel has been a breath of fresh air. There's only so many bank transactions a workbook can take before it starts groaning (yes, even on an M1 Mac). However there were a few forecasting features that I missed. The sort of features that in Excel terms mean I'd just copy a bunch of cells and paste them into columns which represented future dates or apply a neat little formula to divide a big number by 12 to get to a monthly repayment. Because I like to plan 3-5 years out at a time, I wanted to crudely account for future price and salary increases. Sure, I can add some auto-postings to the end of my journal file but I bet a lot of users didn't know about this or even know how to constrain them between two dates.
|
290
360
|
|
291
|
-
|
361
|
+
I also made an assumption that a lot of users probably think of their finances in terms of their monthly costs (e.g. car payments, mortgage, food), half-yearly costs (e.g. service charge if you have an apartment in the UK) and yearly costs (e.g. holidays, gifts) etc. But likely never do the math to add them all together and workout how much money they have left over by the end of it all. Well I built that into this app and my daily profit figure hit me hard :rofl:. Give it a try!
|
292
362
|
|
293
|
-
|
363
|
+
So I thought I'd share this little Ruby gem in the hope that people find it useful. Perhaps for those who are moving from an Excel based approach to [plain text accounting](https://plaintextaccounting.org), or for those who want a little bit of improvement to the existing capabilities within hledger.
|
data/example.journal
CHANGED
@@ -1,40 +1,51 @@
|
|
1
|
-
~ monthly from 2023-03-01 *
|
2
|
-
Income:
|
3
|
-
|
4
|
-
Expenses:Food
|
5
|
-
Expenses:
|
6
|
-
Expenses:Holiday £208.33 ; Holiday savings
|
1
|
+
~ monthly from 2023-03-01 * Salary, Bills, Food, New Kitchen
|
2
|
+
Income:Salary $-3,500.00; Salary
|
3
|
+
Expenses:Bills $175.00 ; Bills
|
4
|
+
Expenses:Food $500.00 ; Food
|
5
|
+
Expenses:House $208.33 ; New Kitchen
|
7
6
|
Assets:Bank
|
8
7
|
|
9
|
-
~ monthly from 2023-03-01 to
|
10
|
-
Expenses:Mortgage
|
8
|
+
~ monthly from 2023-03-01 to 2025-01-01 * Mortgage
|
9
|
+
Expenses:Mortgage $2,000.00 ; Mortgage
|
11
10
|
Assets:Bank
|
12
11
|
|
13
|
-
~ monthly from 2023-03-01 *
|
14
|
-
|
15
|
-
Assets:
|
12
|
+
~ monthly from 2023-03-01 to 2024-02-29 * Holiday
|
13
|
+
Expenses:Holiday $125.00 ; Holiday
|
14
|
+
Assets:Bank
|
16
15
|
|
17
|
-
~
|
18
|
-
|
16
|
+
~ monthly from 2023-03-01 to 2025-01-01 * Rainy day fund
|
17
|
+
Assets:Savings $300.00 ; Rainy day fund
|
19
18
|
Assets:Bank
|
20
19
|
|
21
|
-
~
|
22
|
-
|
20
|
+
~ monthly from 2024-01-01 * Pension draw down
|
21
|
+
Income:Pension $-500.00 ; Pension draw down
|
22
|
+
Assets:Pension
|
23
|
+
|
24
|
+
~ every 3 months from 2023-04-01 * Quarterly bonus
|
25
|
+
Income:Bonus $-1,000.00; Quarterly bonus
|
26
|
+
Assets:Bank
|
27
|
+
|
28
|
+
~ every 6 months from 2023-04-01 * Top up holiday funds
|
29
|
+
Expenses:Holiday $500.00 ; Top up holiday funds
|
23
30
|
Assets:Bank
|
24
31
|
|
25
32
|
~ yearly from 2023-04-01 * Annual Bonus
|
26
|
-
Income:Bonus
|
33
|
+
Income:Bonus $-2,000.00; Annual Bonus
|
27
34
|
Assets:Bank
|
28
35
|
|
29
|
-
~ every
|
30
|
-
Expenses:
|
36
|
+
~ every 2 weeks from 2023-03-01 * Hair and beauty
|
37
|
+
Expenses:Personal Care $80.00 ; Hair and beauty
|
31
38
|
Assets:Bank
|
32
39
|
|
33
|
-
~ 2023-06-01 * [TRACKED]
|
34
|
-
Expenses:
|
40
|
+
~ 2023-06-01 * [TRACKED] Refund for that damn laptop
|
41
|
+
Expenses:Shopping $-3,000.00; Refund for that damn laptop
|
35
42
|
Assets:Bank
|
36
43
|
|
37
44
|
= Expenses:Food date:2024-01-01..2024-12-31
|
38
|
-
Expenses:Food
|
39
|
-
Assets:Bank
|
45
|
+
Expenses:Food *0.02 ; Food - Inflation
|
46
|
+
Assets:Bank *-0.02
|
47
|
+
|
48
|
+
= Expenses:Food date:2025-01-01..2025-12-31
|
49
|
+
Expenses:Food *0.05 ; Food - Inflation
|
50
|
+
Assets:Bank *-0.05
|
40
51
|
|
data/example.yml
CHANGED
@@ -2,32 +2,44 @@ monthly:
|
|
2
2
|
- account: "Assets:Bank"
|
3
3
|
from: "2023-03-01"
|
4
4
|
transactions:
|
5
|
-
- amount: -
|
6
|
-
category: "Income:Bonus"
|
7
|
-
description: Bonus
|
8
|
-
- amount: -2000
|
5
|
+
- amount: -3500
|
9
6
|
category: "Income:Salary"
|
10
7
|
description: Salary
|
8
|
+
- amount: 2000
|
9
|
+
category: "Expenses:Mortgage"
|
10
|
+
description: Mortgage
|
11
|
+
to: "2025-01-01"
|
12
|
+
- amount: 175
|
13
|
+
category: "Expenses:Bills"
|
14
|
+
description: Bills
|
11
15
|
- amount: 500
|
12
16
|
category: "Expenses:Food"
|
13
17
|
description: Food
|
14
18
|
modifiers:
|
15
|
-
- amount: 0.
|
19
|
+
- amount: 0.02
|
16
20
|
description: "Inflation"
|
17
21
|
from: "2024-01-01"
|
18
22
|
to: "2024-12-31"
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
+
- amount: 0.05
|
24
|
+
description: "Inflation"
|
25
|
+
from: "2025-01-01"
|
26
|
+
to: "2025-12-31"
|
27
|
+
- amount: "=5000/24"
|
28
|
+
category: "Expenses:House"
|
29
|
+
description: New Kitchen
|
30
|
+
- amount: 125
|
23
31
|
category: "Expenses:Holiday"
|
24
|
-
description: Holiday
|
25
|
-
|
26
|
-
|
27
|
-
description: Mortgage
|
28
|
-
to: "2024-01-01"
|
29
|
-
- account: "Assets:Savings"
|
32
|
+
description: Holiday
|
33
|
+
to: "=12"
|
34
|
+
- account: "Assets:Bank"
|
30
35
|
from: "2023-03-01"
|
36
|
+
to: "2025-01-01"
|
37
|
+
transactions:
|
38
|
+
- amount: 300
|
39
|
+
category: "Assets:Savings"
|
40
|
+
description: "Rainy day fund"
|
41
|
+
- account: "Assets:Pension"
|
42
|
+
from: "2024-01-01"
|
31
43
|
transactions:
|
32
44
|
- amount: -500
|
33
45
|
category: "Income:Pension"
|
@@ -39,7 +51,7 @@ quarterly:
|
|
39
51
|
transactions:
|
40
52
|
- amount: -1000.00
|
41
53
|
category: "Income:Bonus"
|
42
|
-
description:
|
54
|
+
description: Quarterly bonus
|
43
55
|
|
44
56
|
half-yearly:
|
45
57
|
- account: "Assets:Bank"
|
@@ -47,7 +59,7 @@ half-yearly:
|
|
47
59
|
transactions:
|
48
60
|
- amount: 500
|
49
61
|
category: "Expenses:Holiday"
|
50
|
-
description:
|
62
|
+
description: Top up holiday funds
|
51
63
|
|
52
64
|
yearly:
|
53
65
|
- account: "Assets:Bank"
|
@@ -59,21 +71,23 @@ yearly:
|
|
59
71
|
|
60
72
|
once:
|
61
73
|
- account: "Assets:Bank"
|
62
|
-
from: "2023-03-
|
74
|
+
from: "2023-03-05"
|
63
75
|
transactions:
|
64
|
-
- amount:
|
65
|
-
category: "Expenses:
|
66
|
-
description:
|
76
|
+
- amount: -3000
|
77
|
+
category: "Expenses:Shopping"
|
78
|
+
description: Refund for that damn laptop
|
79
|
+
summary_exclude: true
|
67
80
|
track: true
|
68
81
|
|
69
82
|
custom:
|
70
|
-
- frequency: "every
|
83
|
+
- frequency: "every 2 weeks"
|
71
84
|
account: "Assets:Bank"
|
72
85
|
from: "2023-03-01"
|
86
|
+
roll-up: 26
|
73
87
|
transactions:
|
74
|
-
- amount:
|
75
|
-
category: "Expenses:
|
76
|
-
description:
|
88
|
+
- amount: 80
|
89
|
+
category: "Expenses:Personal Care"
|
90
|
+
description: Hair and beauty
|
77
91
|
|
78
92
|
settings:
|
79
|
-
currency:
|
93
|
+
currency: USD
|
data/hledger-forecast.gemspec
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
module HledgerForecast
|
2
|
+
# Calculate various
|
3
|
+
class Calculator
|
4
|
+
def initialize
|
5
|
+
@calculator = Dentaku::Calculator.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def evaluate(amount)
|
9
|
+
return amount unless amount.is_a?(String)
|
10
|
+
|
11
|
+
@calculator.evaluate(amount.slice(1..-1))
|
12
|
+
end
|
13
|
+
|
14
|
+
def evaluate_date(from, to)
|
15
|
+
return to unless to[0] == "="
|
16
|
+
|
17
|
+
# Subtract a day from the final date
|
18
|
+
(from >> @calculator.evaluate(to.slice(1..-1))) - 1
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/hledger_forecast/cli.rb
CHANGED
@@ -118,6 +118,29 @@ module HledgerForecast
|
|
118
118
|
options[:forecast_file] = file
|
119
119
|
end
|
120
120
|
|
121
|
+
opts.on("-r", "--roll-up PERIOD",
|
122
|
+
"The period to roll-up your forecasts into. One of:",
|
123
|
+
"[yearly], [half-yearly], [quarterly], [monthly], [weekly], [daily]") do |rollup|
|
124
|
+
options[:roll_up] = rollup
|
125
|
+
end
|
126
|
+
|
127
|
+
opts.on("--from DATE",
|
128
|
+
"Include transactions that start FROM a given DATE [yyyy-mm-dd]") do |from|
|
129
|
+
options[:from] = from
|
130
|
+
end
|
131
|
+
|
132
|
+
opts.on("--to DATE",
|
133
|
+
"Include transactions that run TO a given DATE [yyyy-mm-dd]") do |to|
|
134
|
+
options[:to] = to
|
135
|
+
end
|
136
|
+
|
137
|
+
opts.on("-s", "--scenario \"NAMES\"",
|
138
|
+
"Include transactions from given scenarios, e.g.:",
|
139
|
+
"\"base, rennovation, car purchase\"") do |_scenario|
|
140
|
+
# Loop through scenarios, seperated by a comma
|
141
|
+
options[:scenario] = {}
|
142
|
+
end
|
143
|
+
|
121
144
|
opts.on_tail("-h", "--help", "Show this help message") do
|
122
145
|
puts opts
|
123
146
|
exit
|
@@ -155,8 +178,10 @@ module HledgerForecast
|
|
155
178
|
end
|
156
179
|
|
157
180
|
def self.summarize(options)
|
158
|
-
|
159
|
-
|
181
|
+
config = File.read(options[:forecast_file])
|
182
|
+
summarizer = Summarizer.summarize(config, options)
|
183
|
+
|
184
|
+
puts SummarizerFormatter.format(summarizer[:output], summarizer[:settings])
|
160
185
|
end
|
161
186
|
end
|
162
187
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module HledgerForecast
|
2
|
+
# Formats various items used throughout the application
|
3
|
+
class Formatter
|
4
|
+
def self.format_money(amount, settings)
|
5
|
+
Money.from_cents(amount.to_f * 100, (settings[:currency]) || 'USD').format(
|
6
|
+
symbol: settings[:show_symbol] || true,
|
7
|
+
sign_before_symbol: settings[:sign_before_symbol] || false,
|
8
|
+
thousands_separator: settings[:thousands_separator] ? ',' : nil
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.output_to_ledger(*compiled_data)
|
13
|
+
output = compiled_data.compact.map do |data|
|
14
|
+
data.map do |item|
|
15
|
+
next unless item[:transactions].any?
|
16
|
+
|
17
|
+
item[:header] + item[:transactions].join + item[:footer]
|
18
|
+
end.join
|
19
|
+
end.join("\n")
|
20
|
+
|
21
|
+
output.gsub(/\n{2,}/, "\n\n")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|