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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 85bd96722d50a8d5b2c8e8cbb9f973d88832827f74226d3b78d5f511b96265bf
4
- data.tar.gz: b69f6698e5c7294cd2b62c8672887044a416d0ed6624803293acd9246a84fa14
3
+ metadata.gz: 37dbc9f011b6a43fa1d186e92dfb77c3c184cdb4a7cc5ef690a77d53c57f4722
4
+ data.tar.gz: e71185f0ad678b45f1ffa155c89c491bd37d36307d845dd023b823db6ced42d4
5
5
  SHA512:
6
- metadata.gz: 2e3c4e2a1ef57546778525c37fa4b53854a10244f3e509c3bd48d8c3fcb49c2edc892c84f221f7980c56687ec4766f5379939ea82a06a06b238a8aa3f1a1ed8b
7
- data.tar.gz: 4fd49fc32b5fd5aa17e24ac166f384352a5cb85a72f57cb3aa774b8837c62c94439412252ba7164641b59c4cec7fc60a218eab1419dad913ea008c30058722d5
6
+ metadata.gz: d25713fb91fde68daaa07f6809a3c567afc18864a759e47fd032c31cd78cbe195eba2919deff4547d2fe6888e032f7394af4012aea839d1fc6b3d4ee7b1e94bf
7
+ data.tar.gz: 363185c38d788ae91528dc1fde6e21201fc19bec673848202a43589c36c8be3f6fe8e54cb367bfb8652ea286eda6513ab38e86e20aef99f8b7011cb1351fed3b
@@ -12,7 +12,7 @@ jobs:
12
12
  runs-on: ubuntu-latest
13
13
  strategy:
14
14
  matrix:
15
- ruby-version: ['2.6', '2.7', '3.0', '3.1', '3.2']
15
+ ruby-version: ['3.0', '3.1', '3.2']
16
16
 
17
17
  steps:
18
18
  - uses: actions/checkout@v3
data/.gitignore CHANGED
@@ -10,6 +10,7 @@ pkg/*
10
10
  .rvmrc
11
11
  .ruby-version
12
12
  .ruby-gemset
13
+ .tool-versions
13
14
 
14
15
  # Spec artifacts
15
16
  /coverage
data/.rubocop.yml CHANGED
@@ -1,3 +1,6 @@
1
+ AllCops:
2
+ TargetRubyVersion: 3.0
3
+
1
4
  Layout/LineLength:
2
5
  Max: 120
3
6
 
data/README.md CHANGED
@@ -1,20 +1,28 @@
1
- # Hledger-Forecast
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
- [![Tests](https://github.com/olimorris/hledger-forecast/actions/workflows/ci.yml/badge.svg)](https://github.com/olimorris/hledger-forecast/actions/workflows/ci.yml)
5
+ <h1 align="center">hledger-forecast</h1>
4
6
 
5
- A wrapper which builds on [hledger's](https://github.com/simonmichael/hledger) [forecasting](https://hledger.org/dev/hledger.html#forecasting) capability. Uses a `yaml` config file to generate forecasts whilst adding functionality for future cost rises (e.g. inflation) and the automatic tracking of planned transactions.
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
- See the [rationale](#brain-rationale) section for why this gem may be useful to you.
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 forecasted transactions against actuals
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: Supports calculated amounts in forecasts (uses the [Dentaku](https://github.com/rubysolo/dentaku) gem)
15
- - :heavy_dollar_sign: Full currency support (uses the [RubyMoney](https://github.com/RubyMoney/money) gem)
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 _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.
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 Hledger
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. This can be achieved by:
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
- -f, --forecast FILE The path to the FORECAST yaml file to summarize
83
- -h, --help Show this help message
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 YAML file
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 of a complex config file and its [output](https://github.com/olimorris/hledger-forecast/blob/main/example.journal)
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
- account: "Assets:Bank"
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
- ### Applying modifiers
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
- account: "Assets:Bank"
232
- from: "2023-03-05"
233
- transactions:
234
- - amount: 450
235
- category: "Expenses:Groceries"
236
- description: Food shopping
237
- modifiers:
238
- - amount: 0.02
239
- description: "Inflation"
240
- from: "2024-01-01"
241
- to: "2024-12-31"
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
- ### Additional settings
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 # Specify the currency to use
269
- show_symbol: true # Show the currency symbol?
270
- thousands_separator: true # Separate thousands with a comma?
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
- Firstly, I've come to realise from reading countless blog and Reddit posts on [plain text accounting](https://plaintextaccounting.org), that everyone does it __completely__ differently! There is _great_ support in hledger for [forecasting](https://hledger.org/1.29/hledger.html#forecasting) using periodic transactions. Infact, it's nearly perfect for my needs. My only wishes were to be able to sum up monthly transactions much faster (so I can see my forecasted monthly I&E), apply future cost pressures more easily (such as inflation) and to be able to track and monitor specific transactions.
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
- Also, I like to look ahead up to 3 years at a time and understand what my bank balances might look like. For this to be really accurate, factors such as inflation and salary expectations should be included. This is where the idea for modifiers came in. Being able to apply a percentage to a given category between two dates and automatically have the impact included any extended forecasts.
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
- Now I'll freely admit these are two minor issues. So minor infact that they can probably be addressed by a dedicated 5 minutes every month as part of your hledger workflow. However I liked the idea of automating as much of my month end process as possible and saw this as an interesting challenge to try and solve.
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
- Whilst I tried to work within the constraints of a `journal` file, moving to a `yaml` format made the implementation of these features much easier and allowed me to stay true to how you'd accomplish forecasting in hledger, manually. Whilst the config file can end up being many lines long, the output journal should be relatively streamlined and easy to follow.
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 * Bonus, Salary, Food, New cell phone, Holiday savings
2
- Income:Bonus £-100.00 ; Bonus
3
- Income:Salary £-2,000.00; Salary
4
- Expenses:Food £500.00 ; Food
5
- Expenses:Phone £75.00 ; New cell phone
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 2024-01-01 * Mortgage
10
- Expenses:Mortgage £1,000.00 ; 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 * Pension draw down
14
- Income:Pension £-500.00 ; Pension draw down
15
- Assets:Savings
12
+ ~ monthly from 2023-03-01 to 2024-02-29 * Holiday
13
+ Expenses:Holiday $125.00 ; Holiday
14
+ Assets:Bank
16
15
 
17
- ~ every 3 months from 2023-04-01 * Bonus
18
- Income:Bonus £-1,000.00; Bonus
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
- ~ every 6 months from 2023-04-01 * Holiday
22
- Expenses:Holiday £500.00 ; Holiday
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 £-2,000.00; Annual Bonus
33
+ Income:Bonus $-2,000.00; Annual Bonus
27
34
  Assets:Bank
28
35
 
29
- ~ every 5 days from 2023-03-01 * Car fuel
30
- Expenses:Car:Fuel £150.00 ; Car fuel
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] Forecast new car cost
34
- Expenses:Car £5,000.00 ; Forecast new car cost
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 *0.1 ; Food - Inflation
39
- Assets:Bank *-0.1
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: -100
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.1
19
+ - amount: 0.02
16
20
  description: "Inflation"
17
21
  from: "2024-01-01"
18
22
  to: "2024-12-31"
19
- - amount: 75
20
- category: "Expenses:Phone"
21
- description: New cell phone
22
- - amount: "=2500/12"
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 savings
25
- - amount: 1000
26
- category: "Expenses:Mortgage"
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: Bonus
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: Holiday
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-01"
74
+ from: "2023-03-05"
63
75
  transactions:
64
- - amount: 5000.00
65
- category: "Expenses:Car"
66
- description: Forecast new car cost
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 5 days"
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: 150
75
- category: "Expenses:Car:Fuel"
76
- description: Car fuel
88
+ - amount: 80
89
+ category: "Expenses:Personal Care"
90
+ description: Hair and beauty
77
91
 
78
92
  settings:
79
- currency: GBP
93
+ currency: USD
@@ -4,6 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'hledger_forecast/version'
5
5
 
6
6
  Gem::Specification.new do |s|
7
+ s.required_ruby_version = '~> 3.0'
7
8
  s.name = 'hledger-forecast'
8
9
  s.version = HledgerForecast::VERSION
9
10
  s.authors = ['Oli Morris']
@@ -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
@@ -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
- forecast = File.read(options[:forecast_file])
159
- puts Summarize.generate(forecast)
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