hledger-forecast 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +23 -4
- data/example.journal +6 -1
- data/example.yml +3 -0
- data/hledger-forecast.gemspec +1 -0
- data/lib/hledger_forecast/generator.rb +14 -5
- data/lib/hledger_forecast/version.rb +1 -1
- data/lib/hledger_forecast.rb +1 -0
- data/spec/computed_amounts_spec.rb +35 -0
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 85bd96722d50a8d5b2c8e8cbb9f973d88832827f74226d3b78d5f511b96265bf
|
4
|
+
data.tar.gz: b69f6698e5c7294cd2b62c8672887044a416d0ed6624803293acd9246a84fa14
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2e3c4e2a1ef57546778525c37fa4b53854a10244f3e509c3bd48d8c3fcb49c2edc892c84f221f7980c56687ec4766f5379939ea82a06a06b238a8aa3f1a1ed8b
|
7
|
+
data.tar.gz: 4fd49fc32b5fd5aa17e24ac166f384352a5cb85a72f57cb3aa774b8837c62c94439412252ba7164641b59c4cec7fc60a218eab1419dad913ea008c30058722d5
|
data/README.md
CHANGED
@@ -2,15 +2,16 @@
|
|
2
2
|
|
3
3
|
[](https://github.com/olimorris/hledger-forecast/actions/workflows/ci.yml)
|
4
4
|
|
5
|
-
A wrapper which builds on [hledger's](https://github.com/simonmichael/hledger) [forecasting](https://hledger.org/dev/hledger.html#forecasting) capability. Uses a `
|
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.
|
6
6
|
|
7
7
|
See the [rationale](#brain-rationale) section for why this gem may be useful to you.
|
8
8
|
|
9
9
|
## :sparkles: Features
|
10
10
|
|
11
|
-
- :book: Uses simple
|
11
|
+
- :book: Uses a simple yaml file to generate forecasts which can be used with hledger
|
12
12
|
- :date: Can smartly track forecasted transactions against actuals
|
13
13
|
- :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)
|
14
15
|
- :heavy_dollar_sign: Full currency support (uses the [RubyMoney](https://github.com/RubyMoney/money) gem)
|
15
16
|
- :computer: Simple and easy to use CLI
|
16
17
|
- :chart_with_upwards_trend: Summarize your forecasts by period and category and output to the CLI
|
@@ -41,7 +42,7 @@ The available options are:
|
|
41
42
|
|
42
43
|
### Generate command
|
43
44
|
|
44
|
-
The `hledger-forecast generate` command will
|
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.
|
45
46
|
|
46
47
|
The available options are:
|
47
48
|
|
@@ -174,6 +175,24 @@ monthly:
|
|
174
175
|
to: "2025-01-01"
|
175
176
|
```
|
176
177
|
|
178
|
+
### Calculated amounts
|
179
|
+
|
180
|
+
> **Note**: Calculations will be determined up to two decimal places
|
181
|
+
|
182
|
+
It may be helpful to let the app calculate the forecasted amount in your transactions on your behalf. This can be especially useful if you're spreading a payment out over a number of months:
|
183
|
+
|
184
|
+
```yaml
|
185
|
+
monthly:
|
186
|
+
- account: "Liabilities:Amex"
|
187
|
+
from: "2023-05-01"
|
188
|
+
transactions:
|
189
|
+
- amount: "=5000/24"
|
190
|
+
category: "Expenses:House"
|
191
|
+
description: New Kitchen
|
192
|
+
```
|
193
|
+
|
194
|
+
Simply ensure that the amount starts with an `=` sign, is enclosed in quotation marks and uses standard mathematical notations.
|
195
|
+
|
177
196
|
### Tracking transactions
|
178
197
|
|
179
198
|
> **Note**: Marking a transaction for tracking will ensure that it is only written into the forecast if it isn't found within a specified transaction file
|
@@ -265,7 +284,7 @@ settings:
|
|
265
284
|
|
266
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.
|
267
286
|
|
268
|
-
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
|
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.
|
269
288
|
|
270
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.
|
271
290
|
|
data/example.journal
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
-
~ monthly from 2023-03-01 * Bonus, Salary, Food, New cell phone
|
1
|
+
~ monthly from 2023-03-01 * Bonus, Salary, Food, New cell phone, Holiday savings
|
2
2
|
Income:Bonus £-100.00 ; Bonus
|
3
3
|
Income:Salary £-2,000.00; Salary
|
4
4
|
Expenses:Food £500.00 ; Food
|
5
5
|
Expenses:Phone £75.00 ; New cell phone
|
6
|
+
Expenses:Holiday £208.33 ; Holiday savings
|
6
7
|
Assets:Bank
|
7
8
|
|
8
9
|
~ monthly from 2023-03-01 to 2024-01-01 * Mortgage
|
@@ -29,6 +30,10 @@
|
|
29
30
|
Expenses:Car:Fuel £150.00 ; Car fuel
|
30
31
|
Assets:Bank
|
31
32
|
|
33
|
+
~ 2023-06-01 * [TRACKED] Forecast new car cost
|
34
|
+
Expenses:Car £5,000.00 ; Forecast new car cost
|
35
|
+
Assets:Bank
|
36
|
+
|
32
37
|
= Expenses:Food date:2024-01-01..2024-12-31
|
33
38
|
Expenses:Food *0.1 ; Food - Inflation
|
34
39
|
Assets:Bank *-0.1
|
data/example.yml
CHANGED
data/hledger-forecast.gemspec
CHANGED
@@ -14,6 +14,7 @@ Gem::Specification.new do |s|
|
|
14
14
|
s.license = 'MIT'
|
15
15
|
|
16
16
|
s.add_dependency "colorize", "~> 0.8.1"
|
17
|
+
s.add_dependency "dentaku", "~> 3.5.1"
|
17
18
|
s.add_dependency "highline", "~> 2.1.0"
|
18
19
|
s.add_dependency "money", "~> 6.16.0"
|
19
20
|
s.add_dependency "terminal-table", "~> 3.0.2"
|
@@ -2,9 +2,10 @@ module HledgerForecast
|
|
2
2
|
# Generates periodic transactions from a YAML file
|
3
3
|
class Generator
|
4
4
|
class << self
|
5
|
-
attr_accessor :options, :modified, :tracked
|
5
|
+
attr_accessor :calculator, :options, :modified, :tracked
|
6
6
|
end
|
7
7
|
|
8
|
+
self.calculator = {}
|
8
9
|
self.options = {}
|
9
10
|
self.modified = {}
|
10
11
|
self.tracked = {}
|
@@ -24,6 +25,8 @@ module HledgerForecast
|
|
24
25
|
|
25
26
|
set_options(forecast_data)
|
26
27
|
|
28
|
+
@calculator = Dentaku::Calculator.new
|
29
|
+
|
27
30
|
output = ""
|
28
31
|
|
29
32
|
# Generate regular transactions
|
@@ -75,7 +78,7 @@ module HledgerForecast
|
|
75
78
|
|
76
79
|
modified_transaction(from, to, account, transaction)
|
77
80
|
|
78
|
-
output += output_transaction(transaction['category'], format_amount(transaction['amount']),
|
81
|
+
output += output_transaction(transaction['category'], format_amount(calculate_amount(transaction['amount'])),
|
79
82
|
transaction['description'])
|
80
83
|
end
|
81
84
|
|
@@ -107,7 +110,7 @@ module HledgerForecast
|
|
107
110
|
modified_transaction(from, to, account, transaction)
|
108
111
|
|
109
112
|
output += "#{frequency} #{from} to #{to} * #{transaction['description']}\n"
|
110
|
-
output += output_transaction(transaction['category'], format_amount(transaction['amount']),
|
113
|
+
output += output_transaction(transaction['category'], format_amount(calculate_amount(transaction['amount'])),
|
111
114
|
transaction['description'])
|
112
115
|
output += " #{account}\n\n"
|
113
116
|
end
|
@@ -137,7 +140,7 @@ module HledgerForecast
|
|
137
140
|
|
138
141
|
modified_transaction(from, to, account, transaction)
|
139
142
|
|
140
|
-
output += output_transaction(transaction['category'], format_amount(transaction['amount']),
|
143
|
+
output += output_transaction(transaction['category'], format_amount(calculate_amount(transaction['amount'])),
|
141
144
|
transaction['description'])
|
142
145
|
end
|
143
146
|
|
@@ -216,7 +219,7 @@ module HledgerForecast
|
|
216
219
|
end
|
217
220
|
|
218
221
|
def self.track_transaction(from, to, account, transaction)
|
219
|
-
amount = transaction['amount']
|
222
|
+
amount = calculate_amount(transaction['amount'])
|
220
223
|
transaction['amount'] = format_amount(amount)
|
221
224
|
transaction['inverse_amount'] = format_amount(amount * -1)
|
222
225
|
|
@@ -240,6 +243,12 @@ module HledgerForecast
|
|
240
243
|
map[period]
|
241
244
|
end
|
242
245
|
|
246
|
+
def self.calculate_amount(amount)
|
247
|
+
return amount unless amount.is_a?(String)
|
248
|
+
|
249
|
+
@calculator.evaluate(amount.slice(1..-1))
|
250
|
+
end
|
251
|
+
|
243
252
|
def self.format_amount(amount)
|
244
253
|
Money.from_cents(amount.to_f * 100, @options[:currency]).format(
|
245
254
|
symbol: @options[:show_symbol],
|
data/lib/hledger_forecast.rb
CHANGED
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative '../lib/hledger_forecast'
|
2
|
+
|
3
|
+
config = <<~YAML
|
4
|
+
settings:
|
5
|
+
currency: GBP
|
6
|
+
|
7
|
+
monthly:
|
8
|
+
- account: "Liabilities:Amex"
|
9
|
+
from: "2023-05-01"
|
10
|
+
transactions:
|
11
|
+
- amount: "=5000/24"
|
12
|
+
category: "Expenses:House"
|
13
|
+
description: New Kitchen
|
14
|
+
- amount: "=25*4.3"
|
15
|
+
category: "Expenses:Food"
|
16
|
+
description: Monthly food shop
|
17
|
+
- amount: "=(102.50+3.25)/2"
|
18
|
+
category: "Expenses:Food"
|
19
|
+
description: Random food
|
20
|
+
YAML
|
21
|
+
|
22
|
+
output = <<~JOURNAL
|
23
|
+
~ monthly from 2023-05-01 * New Kitchen, Monthly food shop, Random food
|
24
|
+
Expenses:House £208.33 ; New Kitchen
|
25
|
+
Expenses:Food £107.50 ; Monthly food shop
|
26
|
+
Expenses:Food £52.88 ; Random food
|
27
|
+
Liabilities:Amex
|
28
|
+
|
29
|
+
JOURNAL
|
30
|
+
|
31
|
+
RSpec.describe 'generate' do
|
32
|
+
it 'generates a forecast with correct CALCULATED transactions' do
|
33
|
+
expect(HledgerForecast::Generator.generate(config)).to eq(output)
|
34
|
+
end
|
35
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hledger-forecast
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Oli Morris
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-05-
|
11
|
+
date: 2023-05-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.8.1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: dentaku
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.5.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 3.5.1
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: highline
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -105,6 +119,7 @@ files:
|
|
105
119
|
- lib/hledger_forecast/tracker.rb
|
106
120
|
- lib/hledger_forecast/version.rb
|
107
121
|
- spec/command_spec.rb
|
122
|
+
- spec/computed_amounts_spec.rb
|
108
123
|
- spec/custom_spec.rb
|
109
124
|
- spec/half-yearly_spec.rb
|
110
125
|
- spec/modifier_spec.rb
|
@@ -144,6 +159,7 @@ specification_version: 4
|
|
144
159
|
summary: An extended wrapper around hledger's forecasting functionality
|
145
160
|
test_files:
|
146
161
|
- spec/command_spec.rb
|
162
|
+
- spec/computed_amounts_spec.rb
|
147
163
|
- spec/custom_spec.rb
|
148
164
|
- spec/half-yearly_spec.rb
|
149
165
|
- spec/modifier_spec.rb
|