hledger-forecast 0.3.0 → 0.4.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: cb90937d10de71d495146036711f7028d12de7f5b7c814ccf0fb62dc7ffc5e7f
4
- data.tar.gz: 05143fad945647f27f30e49626974ec62b66074863a5f11e86898a824b182c85
3
+ metadata.gz: 85bd96722d50a8d5b2c8e8cbb9f973d88832827f74226d3b78d5f511b96265bf
4
+ data.tar.gz: b69f6698e5c7294cd2b62c8672887044a416d0ed6624803293acd9246a84fa14
5
5
  SHA512:
6
- metadata.gz: 00e039f29f6f50237d4bca32d8f5e2f27173ac880661bb1445558a98380816de0718e3e748b639e7018d79b49ce019f6dac7b145b98104a687d04bbf36c8db57
7
- data.tar.gz: 233262e4e1a0612c821334f97599a0d2b00962968a18f591eb5cd96f4efdd5116c037e5b5570f2b6c3e74b1955dec140ffd774a7c04feacdb6d628303d71cb87
6
+ metadata.gz: 2e3c4e2a1ef57546778525c37fa4b53854a10244f3e509c3bd48d8c3fcb49c2edc892c84f221f7980c56687ec4766f5379939ea82a06a06b238a8aa3f1a1ed8b
7
+ data.tar.gz: 4fd49fc32b5fd5aa17e24ac166f384352a5cb85a72f57cb3aa774b8837c62c94439412252ba7164641b59c4cec7fc60a218eab1419dad913ea008c30058722d5
data/README.md CHANGED
@@ -2,15 +2,16 @@
2
2
 
3
3
  [![Tests](https://github.com/olimorris/hledger-forecast/actions/workflows/ci.yml/badge.svg)](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 `YAML` config file to generate forecasts whilst adding functionality for future cost rises (e.g. inflation) and the automatic tracking of planned transactions.
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 YAML files to generate forecasts which can be used with hledger
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 begin the generation of your forecast _from_ a `yaml` file _to_ a journal file.
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 likely be for the period of 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 is a nice time saver.
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
@@ -19,6 +19,9 @@ monthly:
19
19
  - amount: 75
20
20
  category: "Expenses:Phone"
21
21
  description: New cell phone
22
+ - amount: "=2500/12"
23
+ category: "Expenses:Holiday"
24
+ description: Holiday savings
22
25
  - amount: 1000
23
26
  category: "Expenses:Mortgage"
24
27
  description: Mortgage
@@ -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],
@@ -1,3 +1,3 @@
1
1
  module HledgerForecast
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'colorize'
4
4
  require 'date'
5
+ require 'dentaku'
5
6
  require 'highline'
6
7
  require 'money'
7
8
  require 'optparse'
@@ -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.3.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-08 00:00:00.000000000 Z
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