hledger-forecast 1.5.2 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +17 -17
- data/README.md +7 -171
- data/example.journal +14 -14
- data/hledger-forecast.gemspec +1 -1
- data/lib/hledger_forecast/calculator.rb +5 -1
- data/lib/hledger_forecast/cli.rb +5 -18
- data/lib/hledger_forecast/generator.rb +52 -35
- data/lib/hledger_forecast/settings.rb +42 -27
- data/lib/hledger_forecast/summarizer.rb +28 -62
- data/lib/hledger_forecast/summarizer_formatter.rb +4 -4
- data/lib/hledger_forecast/transactions/default.rb +28 -57
- data/lib/hledger_forecast/transactions/trackers.rb +34 -40
- data/lib/hledger_forecast/utilities.rb +14 -0
- data/lib/hledger_forecast/version.rb +1 -1
- data/lib/hledger_forecast.rb +1 -2
- data/spec/cli_spec.rb +3 -12
- data/spec/computed_amounts_spec.rb +11 -22
- data/spec/custom_spec.rb +15 -35
- data/spec/half-yearly_spec.rb +6 -13
- data/spec/monthly_end_date_spec.rb +8 -18
- data/spec/monthly_end_date_transaction_spec.rb +20 -45
- data/spec/monthly_spec.rb +11 -28
- data/spec/once_spec.rb +6 -13
- data/spec/quarterly_spec.rb +5 -12
- data/spec/summarizer_spec.rb +11 -42
- data/spec/track_spec.rb +19 -49
- data/spec/verbose_output_spec.rb +3 -3
- data/spec/yearly_spec.rb +5 -12
- metadata +4 -13
- data/example.yml +0 -98
- data/lib/hledger_forecast/csv_parser.rb +0 -106
- data/spec/csv_and_yml_comparison_spec.rb +0 -32
- data/spec/csv_parser_spec.rb +0 -110
- data/spec/modifier_spec.rb +0 -102
- data/spec/stubs/forecast.yml +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6e94131797e8e2c866fa33adc9862c8b5d87dbbc2fa42609c0ea6fc5368a1675
|
4
|
+
data.tar.gz: dc2c4850cff76e74607481997975055e67973b6ea0058ee0193cfabaf888fd1a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9911b761e32f9b4e744fc8fd735d2d889dcde25933a7c514438cfcd79ccc2cff6269624aef20ba00c83a96e62c04c1d7c6179b685a738d3eb0df05d41b0bef59
|
7
|
+
data.tar.gz: 2a9fb8fc081ffe7b470ef23a649e3f1155c14556a452ef8adbf62efe4d23fd4df7ea6c06eec02fa069554db3e9bf1e2d368daa460db511423c5c9c990a39d92b
|
data/.rubocop.yml
CHANGED
@@ -4,20 +4,20 @@ AllCops:
|
|
4
4
|
Layout/LineLength:
|
5
5
|
Max: 120
|
6
6
|
|
7
|
-
Style/StringLiterals:
|
8
|
-
|
9
|
-
|
10
|
-
Style/RedundantReturn:
|
11
|
-
|
12
|
-
|
13
|
-
Metrics/ClassLength:
|
14
|
-
|
15
|
-
|
16
|
-
Metrics/MethodLength:
|
17
|
-
|
18
|
-
|
19
|
-
Metrics/AbcSize:
|
20
|
-
|
21
|
-
|
22
|
-
Style/NumericPredicate:
|
23
|
-
|
7
|
+
# Style/StringLiterals:
|
8
|
+
# Enabled: false
|
9
|
+
#
|
10
|
+
# Style/RedundantReturn:
|
11
|
+
# Enabled: false
|
12
|
+
#
|
13
|
+
# Metrics/ClassLength:
|
14
|
+
# Enabled: False
|
15
|
+
#
|
16
|
+
# Metrics/MethodLength:
|
17
|
+
# Enabled: False
|
18
|
+
#
|
19
|
+
# Metrics/AbcSize:
|
20
|
+
# Enabled: False
|
21
|
+
#
|
22
|
+
# Style/NumericPredicate:
|
23
|
+
# Enabled: False
|
data/README.md
CHANGED
@@ -11,13 +11,13 @@
|
|
11
11
|
<a href="https://github.com/olimorris/hledger-forecast/actions/workflows/test.yml"><img src="https://img.shields.io/github/actions/workflow/status/olimorris/hledger-forecast/test.yml?branch=main&label=tests&style=for-the-badge"></a>
|
12
12
|
</p>
|
13
13
|
|
14
|
-
**"Improved", you say?** Using a _CSV_
|
14
|
+
**"Improved", you say?** Using a _CSV_ file, forecasts can be quickly generated into a _journal_ file ready to be fed into [hledger](https://github.com/simonmichael/hledger). **A 16 line [CSV file](https://github.com/olimorris/hledger-forecast/blob/main/example.csv) can generate a 46 line hledger [forecast file](https://github.com/olimorris/hledger-forecast/blob/main/example.journal)!**
|
15
15
|
|
16
16
|
Forecasts can also be 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.
|
17
17
|
|
18
18
|
## :sparkles: Features
|
19
19
|
|
20
|
-
- :rocket: Uses a simple CSV
|
20
|
+
- :rocket: Uses a simple CSV file to generate forecasts which can be used with hledger
|
21
21
|
- :calendar: Can smartly track forecasts against your bank statement
|
22
22
|
- :dollar: Can automatically apply modifiers such as inflation/deflation to forecasts
|
23
23
|
- :mag: Enables the use of maths in your forecasts (for amounts and dates)
|
@@ -62,13 +62,13 @@ The available options are:
|
|
62
62
|
|
63
63
|
### Generate command
|
64
64
|
|
65
|
-
The `hledger-forecast generate` command will generate a forecast _from_ a `CSV`
|
65
|
+
The `hledger-forecast generate` command will generate a forecast _from_ a `CSV` 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.
|
66
66
|
|
67
67
|
The available options are:
|
68
68
|
|
69
69
|
Usage: hledger-forecast generate [options]
|
70
70
|
|
71
|
-
-f, --forecast FILE The path to the FORECAST CSV
|
71
|
+
-f, --forecast FILE The path to the FORECAST CSV file to generate from
|
72
72
|
-o, --output-file FILE The path to the OUTPUT file to create
|
73
73
|
-t, --transaction FILE The path to the TRANSACTION journal file
|
74
74
|
-v, --verbose Don't group transactions by type in the output file
|
@@ -78,7 +78,7 @@ The available options are:
|
|
78
78
|
|
79
79
|
> **Note**: For the tracking of transactions you need to include the `-t` flag
|
80
80
|
|
81
|
-
Running the command with no options will assume a `forecast.
|
81
|
+
Running the command with no options will assume a `forecast.csv` file exists.
|
82
82
|
|
83
83
|
### Using with hledger
|
84
84
|
|
@@ -100,7 +100,7 @@ The available options are:
|
|
100
100
|
|
101
101
|
Usage: hledger-forecast summarize [options]
|
102
102
|
|
103
|
-
-f, --forecast FILE The path to the FORECAST CSV
|
103
|
+
-f, --forecast FILE The path to the FORECAST CSV file to summarize
|
104
104
|
-r, --roll-up PERIOD The period to roll-up your forecasts into. One of:
|
105
105
|
[yearly], [half-yearly], [quarterly], [monthly], [weekly], [daily]
|
106
106
|
-v, --verbose Show additional information in the summary
|
@@ -138,7 +138,7 @@ The _CSV_ file _should_ contain a header row with the following columns:
|
|
138
138
|
- `summary_exclude` - (boolean) _(optional)_ - Exclude the transaction from the summarizer?
|
139
139
|
- `track` - (boolean) _(optional)_ - Track the transaction against your confirmed transactions?
|
140
140
|
|
141
|
-
###
|
141
|
+
### Example forecast
|
142
142
|
|
143
143
|
Putting it together, we end up with a CSV file like:
|
144
144
|
|
@@ -198,157 +198,6 @@ settings,show_symbol,true,,,,,,,,
|
|
198
198
|
settings,thousands_separator,true,,,,,,,,
|
199
199
|
```
|
200
200
|
|
201
|
-
### An example YML forecast
|
202
|
-
|
203
|
-
> **Note**: The app uses `yml` in place of `yaml` by default
|
204
|
-
|
205
|
-
Taking the _CSV_ example above and applying it to a _YML_ file:
|
206
|
-
|
207
|
-
```yml
|
208
|
-
monthly:
|
209
|
-
- account: "Assets:Bank"
|
210
|
-
from: "2023-03-01"
|
211
|
-
transactions:
|
212
|
-
- amount: -3500
|
213
|
-
category: "Income:Salary"
|
214
|
-
description: Salary
|
215
|
-
- amount: 2000
|
216
|
-
category: "Expenses:Mortgage"
|
217
|
-
description: Mortgage
|
218
|
-
to: "2025-01-01"
|
219
|
-
- amount: 175
|
220
|
-
category: "Expenses:Bills"
|
221
|
-
description: Bills
|
222
|
-
- amount: 500
|
223
|
-
category: "Expenses:Food"
|
224
|
-
description: Food
|
225
|
-
- amount: "=5000/24"
|
226
|
-
category: "Expenses:House"
|
227
|
-
description: New Kitchen
|
228
|
-
- amount: 125
|
229
|
-
category: "Expenses:Holiday"
|
230
|
-
description: Holiday
|
231
|
-
to: "=12"
|
232
|
-
- account: "Assets:Bank"
|
233
|
-
from: "2023-03-01"
|
234
|
-
to: "2025-01-01"
|
235
|
-
transactions:
|
236
|
-
- amount: 300
|
237
|
-
category: "Assets:Savings"
|
238
|
-
description: "Rainy day fund"
|
239
|
-
- account: "Assets:Pension"
|
240
|
-
from: "2024-01-01"
|
241
|
-
transactions:
|
242
|
-
- amount: -500
|
243
|
-
category: "Income:Pension"
|
244
|
-
description: Pension draw down
|
245
|
-
|
246
|
-
quarterly:
|
247
|
-
- account: "Assets:Bank"
|
248
|
-
from: "2023-04-01"
|
249
|
-
transactions:
|
250
|
-
- amount: -1000.00
|
251
|
-
category: "Income:Bonus"
|
252
|
-
description: Quarterly bonus
|
253
|
-
|
254
|
-
half-yearly:
|
255
|
-
- account: "Assets:Bank"
|
256
|
-
from: "2023-04-01"
|
257
|
-
transactions:
|
258
|
-
- amount: 500
|
259
|
-
category: "Expenses:Holiday"
|
260
|
-
description: Top up holiday funds
|
261
|
-
|
262
|
-
yearly:
|
263
|
-
- account: "Assets:Bank"
|
264
|
-
from: "2023-04-01"
|
265
|
-
transactions:
|
266
|
-
- amount: -2000.00
|
267
|
-
category: "Income:Bonus"
|
268
|
-
description: Annual Bonus
|
269
|
-
|
270
|
-
once:
|
271
|
-
- account: "Assets:Bank"
|
272
|
-
from: "2023-03-05"
|
273
|
-
transactions:
|
274
|
-
- amount: -3000
|
275
|
-
category: "Expenses:Shopping"
|
276
|
-
description: Refund for that damn laptop
|
277
|
-
summary_exclude: true
|
278
|
-
track: true
|
279
|
-
|
280
|
-
custom:
|
281
|
-
- account: "Assets:Bank"
|
282
|
-
from: "2023-03-01"
|
283
|
-
transactions:
|
284
|
-
- amount: 80
|
285
|
-
category: "Expenses:Personal Care"
|
286
|
-
description: Hair and beauty
|
287
|
-
frequency: "every 2 weeks"
|
288
|
-
roll-up: 26
|
289
|
-
- amount: 30
|
290
|
-
category: "Expenses:General Expenses"
|
291
|
-
description: Misc expenses
|
292
|
-
frequency: "every 5 weeks"
|
293
|
-
roll-up: 10.4
|
294
|
-
|
295
|
-
settings:
|
296
|
-
currency: USD
|
297
|
-
```
|
298
|
-
|
299
|
-
#### Modifiers
|
300
|
-
|
301
|
-
> **Note**: For modifiers to be included in your hledger reporting, use the `--auto` flag
|
302
|
-
|
303
|
-
Currently, a YML forecast allows a user to include forecasted % uplifts or downshifts:
|
304
|
-
|
305
|
-
```yml
|
306
|
-
monthly:
|
307
|
-
- account: "Assets:Bank"
|
308
|
-
from: "2023-03-01"
|
309
|
-
transactions:
|
310
|
-
- amount: 500
|
311
|
-
category: "Expenses:Food"
|
312
|
-
description: Food
|
313
|
-
modifiers:
|
314
|
-
- amount: 0.02
|
315
|
-
description: "Inflation"
|
316
|
-
from: "2024-01-01"
|
317
|
-
to: "2024-12-31"
|
318
|
-
- amount: 0.05
|
319
|
-
description: "Inflation"
|
320
|
-
from: "2025-01-01"
|
321
|
-
to: "2025-12-31"
|
322
|
-
```
|
323
|
-
|
324
|
-
This will generate an [auto-posting](https://hledger.org/dev/hledger.html#auto-postings) in your forecast which will uplift any transaction with an `Expenses:Food` category. In the first year the uplift with be 2% and in the following year, 5%.
|
325
|
-
|
326
|
-
#### Additional YML features
|
327
|
-
|
328
|
-
Dates in a YML file can be constrained by the `to` date in two ways:
|
329
|
-
|
330
|
-
```yml
|
331
|
-
monthly:
|
332
|
-
- account: "Assets:Bank"
|
333
|
-
from: "2023-03-01"
|
334
|
-
to: "2025-01-01"
|
335
|
-
transactions:
|
336
|
-
# details omitted for brevity
|
337
|
-
```
|
338
|
-
|
339
|
-
or:
|
340
|
-
|
341
|
-
```yml
|
342
|
-
monthly:
|
343
|
-
- account: "Assets:Bank"
|
344
|
-
from: "2023-03-01"
|
345
|
-
transactions:
|
346
|
-
- amount: 2000
|
347
|
-
category: "Expenses:Mortgage"
|
348
|
-
description: Mortgage
|
349
|
-
to: "2025-01-01"
|
350
|
-
```
|
351
|
-
|
352
201
|
### Tracking
|
353
202
|
|
354
203
|
> **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
|
@@ -362,19 +211,6 @@ type,frequency,account,from,to,description,category,amount,roll-up,summary_exclu
|
|
362
211
|
once,,Assets:Bank,2023-03-05,,Refund for that damn laptop,Expenses:Shopping,-3000,,,TRUE
|
363
212
|
```
|
364
213
|
|
365
|
-
Or:
|
366
|
-
|
367
|
-
```yml
|
368
|
-
once:
|
369
|
-
- account: "Assets:Bank"
|
370
|
-
from: "2023-03-05"
|
371
|
-
transactions:
|
372
|
-
- amount: -3000
|
373
|
-
category: "Expenses:Shopping"
|
374
|
-
description: Refund for that damn laptop
|
375
|
-
track: true
|
376
|
-
```
|
377
|
-
|
378
214
|
> **Note**: This feature has been designed to work with `once` transaction types only
|
379
215
|
|
380
216
|
To use this feature, ensure you pass a filepath to the `-t` flag, such as:
|
data/example.journal
CHANGED
@@ -1,47 +1,47 @@
|
|
1
1
|
~ monthly from 2023-03-01 * Salary, Bills, Food, New Kitchen
|
2
|
-
Income:Salary $-3,500.00; Salary
|
3
|
-
Expenses:Bills $175.00
|
4
|
-
Expenses:Food $500.00
|
5
|
-
Expenses:House $208.33
|
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
|
6
6
|
Assets:Bank
|
7
7
|
|
8
8
|
~ monthly from 2023-03-01 to 2025-01-01 * Mortgage
|
9
|
-
Expenses:Mortgage $2,000.00
|
9
|
+
Expenses:Mortgage $2,000.00 ; Mortgage
|
10
10
|
Assets:Bank
|
11
11
|
|
12
12
|
~ monthly from 2023-03-01 to 2024-02-29 * Holiday
|
13
|
-
Expenses:Holiday $125.00
|
13
|
+
Expenses:Holiday $125.00 ; Holiday
|
14
14
|
Assets:Bank
|
15
15
|
|
16
16
|
~ monthly from 2023-03-01 to 2025-03-01 * Rainy day fund
|
17
|
-
Assets:Savings $300.00
|
17
|
+
Assets:Savings $300.00 ; Rainy day fund
|
18
18
|
Assets:Bank
|
19
19
|
|
20
20
|
~ monthly from 2024-01-01 * Pension draw down
|
21
|
-
Income:Pension $-500.00
|
21
|
+
Income:Pension $-500.00 ; Pension draw down
|
22
22
|
Assets:Pension
|
23
23
|
|
24
24
|
~ every 3 months from 2023-04-01 * Quarterly bonus
|
25
|
-
Income:Bonus $-1,000.00; Quarterly bonus
|
25
|
+
Income:Bonus $-1,000.00 ; Quarterly bonus
|
26
26
|
Assets:Bank
|
27
27
|
|
28
28
|
~ every 6 months from 2023-04-01 * Top up holiday funds
|
29
|
-
Expenses:Holiday $500.00
|
29
|
+
Expenses:Holiday $500.00 ; Top up holiday funds
|
30
30
|
Assets:Bank
|
31
31
|
|
32
32
|
~ yearly from 2023-04-01 * Annual bonus
|
33
|
-
Income:Bonus $-2,000.00; Annual bonus
|
33
|
+
Income:Bonus $-2,000.00 ; Annual bonus
|
34
34
|
Assets:Bank
|
35
35
|
|
36
36
|
~ every 2 weeks from 2023-03-01 * Hair and beauty
|
37
|
-
Expenses:Personal Care $80.00
|
37
|
+
Expenses:Personal Care $80.00 ; Hair and beauty
|
38
38
|
Assets:Bank
|
39
39
|
|
40
40
|
~ every 5 weeks from 2023-03-01 * Misc expenses
|
41
|
-
Expenses:General Expenses $30.00
|
41
|
+
Expenses:General Expenses $30.00 ; Misc expenses
|
42
42
|
Assets:Bank
|
43
43
|
|
44
|
-
~
|
44
|
+
~ 2024-01-01 * [TRACKED] Refund for that damn laptop
|
45
45
|
Expenses:Shopping $-3,000.00; Refund for that damn laptop
|
46
46
|
Assets:Bank
|
47
47
|
|
data/hledger-forecast.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.version = HledgerForecast::VERSION
|
10
10
|
s.authors = ['Oli Morris']
|
11
11
|
s.summary = "An extended wrapper around hledger's forecasting functionality"
|
12
|
-
s.description = 'Use a CSV
|
12
|
+
s.description = 'Use a CSV file for improved forecasting with hledger'
|
13
13
|
s.email = 'olimorris@users.noreply.github.com'
|
14
14
|
s.homepage = 'https://github.com/olimorris/hledger-forecast'
|
15
15
|
s.license = 'MIT'
|
@@ -12,7 +12,11 @@ module HledgerForecast
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def evaluate_date(from, to)
|
15
|
-
|
15
|
+
if to[0] != "="
|
16
|
+
return to if to.is_a?(Date)
|
17
|
+
|
18
|
+
return Date.parse(to)
|
19
|
+
end
|
16
20
|
|
17
21
|
# Subtract a day from the final date
|
18
22
|
(from >> @calculator.evaluate(to.slice(1..-1))) - 1
|
data/lib/hledger_forecast/cli.rb
CHANGED
@@ -79,16 +79,9 @@ module HledgerForecast
|
|
79
79
|
opts.separator ""
|
80
80
|
|
81
81
|
opts.on("-f", "--forecast FILE",
|
82
|
-
"The path to the FORECAST csv
|
82
|
+
"The path to the FORECAST csv file to generate from") do |file|
|
83
83
|
options[:forecast_file] = file
|
84
|
-
|
85
|
-
options[:file_type] = if File.extname(file) == '.csv'
|
86
|
-
"csv"
|
87
|
-
else
|
88
|
-
"yml"
|
89
|
-
end
|
90
|
-
|
91
|
-
options[:output_file] ||= file.sub(options[:file_type], 'journal')
|
84
|
+
options[:output_file] ||= file.sub('csv', 'journal')
|
92
85
|
end
|
93
86
|
|
94
87
|
opts.on("-o", "--output-file FILE",
|
@@ -102,7 +95,7 @@ module HledgerForecast
|
|
102
95
|
end
|
103
96
|
|
104
97
|
opts.on("-v", "--verbose",
|
105
|
-
"
|
98
|
+
"Do not group transactions in the output file") do
|
106
99
|
options[:verbose] = true
|
107
100
|
end
|
108
101
|
|
@@ -112,7 +105,7 @@ module HledgerForecast
|
|
112
105
|
end
|
113
106
|
|
114
107
|
opts.on("--no-track",
|
115
|
-
"
|
108
|
+
"Do not track any transactions") do
|
116
109
|
options[:no_track] = true
|
117
110
|
end
|
118
111
|
|
@@ -150,12 +143,7 @@ module HledgerForecast
|
|
150
143
|
opts.separator ""
|
151
144
|
|
152
145
|
opts.on("-f", "--forecast FILE",
|
153
|
-
"The path to the FORECAST csv
|
154
|
-
options[:file_type] = if File.extname(file) == '.csv'
|
155
|
-
"csv"
|
156
|
-
else
|
157
|
-
"yml"
|
158
|
-
end
|
146
|
+
"The path to the FORECAST csv file to summarize") do |file|
|
159
147
|
options[:forecast_file] = file
|
160
148
|
end
|
161
149
|
|
@@ -240,7 +228,6 @@ module HledgerForecast
|
|
240
228
|
forecast = File.read(options[:forecast_file])
|
241
229
|
|
242
230
|
begin
|
243
|
-
forecast = HledgerForecast::CSVParser.parse(forecast) if options[:file_type] == "csv"
|
244
231
|
transactions = Generator.generate(forecast, options)
|
245
232
|
rescue StandardError => e
|
246
233
|
puts "An error occurred while generating transactions: #{e.message}"
|
@@ -6,61 +6,78 @@ module HledgerForecast
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def generate(config, cli_options = nil)
|
9
|
-
forecast =
|
9
|
+
forecast = CSV.parse(config, headers: true)
|
10
10
|
@settings = Settings.config(forecast, cli_options)
|
11
11
|
|
12
|
-
|
13
|
-
forecast.each do |
|
14
|
-
next if
|
12
|
+
processed = []
|
13
|
+
forecast.each do |row|
|
14
|
+
next if row['type'] == "settings"
|
15
15
|
|
16
|
-
|
17
|
-
|
16
|
+
processed.push(process_forecast(row))
|
17
|
+
end
|
18
|
+
|
19
|
+
unless @settings[:verbose]
|
20
|
+
processed = processed.group_by do |row|
|
21
|
+
[row[:type], row[:frequency], row[:from], row[:to], row[:account], row[:track]]
|
22
|
+
end
|
23
|
+
|
24
|
+
processed = processed.map do |(type, frequency, from, to, account, track), transactions|
|
25
|
+
{
|
26
|
+
type: type,
|
27
|
+
frequency: frequency,
|
28
|
+
from: from,
|
29
|
+
to: to,
|
30
|
+
account: account,
|
31
|
+
track: track || false,
|
32
|
+
transactions: transactions
|
33
|
+
}
|
18
34
|
end
|
19
35
|
end
|
20
36
|
|
21
37
|
Formatter.output_to_ledger(
|
22
|
-
Transactions::Default.generate(
|
23
|
-
Transactions::Trackers.generate(
|
24
|
-
Transactions::Modifiers.generate(output, @settings)
|
38
|
+
Transactions::Default.generate(processed, @settings),
|
39
|
+
Transactions::Trackers.generate(processed, @settings)
|
25
40
|
)
|
26
41
|
end
|
27
42
|
|
28
43
|
private
|
29
44
|
|
30
|
-
def
|
31
|
-
|
45
|
+
def process_forecast(row)
|
46
|
+
row['amount'] = Utilities.convert_amount(row['amount'])
|
32
47
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
48
|
+
{
|
49
|
+
type: row['type'],
|
50
|
+
frequency: row['frequency'] || nil,
|
51
|
+
account: row['account'],
|
52
|
+
from: Date.parse(row['from']),
|
53
|
+
to: row['to'] ? Calculator.new.evaluate_date(Date.parse(row['from']), row['to']) : nil,
|
54
|
+
description: row['description'],
|
55
|
+
category: row['category'],
|
56
|
+
amount: Formatter.format_money(Calculator.new.evaluate(row['amount']), @settings),
|
57
|
+
track: Transactions::Trackers.track?(row, @settings) ? true : false
|
40
58
|
}
|
59
|
+
end
|
41
60
|
|
42
|
-
|
61
|
+
def transform_data(data)
|
62
|
+
transformed_data = []
|
43
63
|
|
44
|
-
|
45
|
-
|
46
|
-
item.merge(transactions: transactions)
|
47
|
-
end
|
48
|
-
end
|
64
|
+
data.each do |group_key, transactions|
|
65
|
+
next if group_key == "settings"
|
49
66
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
track: Transactions::Trackers.track?(t, block, @settings) ? true : false,
|
59
|
-
frequency: t['frequency'] || nil
|
67
|
+
split_keys = group_key.split("@@")
|
68
|
+
|
69
|
+
group_info = {
|
70
|
+
type: split_keys[0],
|
71
|
+
from: split_keys[1],
|
72
|
+
to: split_keys[2],
|
73
|
+
account: split_keys[3],
|
74
|
+
transactions: transactions
|
60
75
|
}
|
76
|
+
|
77
|
+
transformed_data << group_info
|
61
78
|
end
|
62
79
|
|
63
|
-
|
80
|
+
transformed_data
|
64
81
|
end
|
65
82
|
end
|
66
83
|
end
|
@@ -1,41 +1,56 @@
|
|
1
1
|
module HledgerForecast
|
2
|
-
# Set the options from a user's
|
2
|
+
# Set the options from a user's config
|
3
3
|
class Settings
|
4
4
|
def self.config(forecast, cli_options)
|
5
5
|
settings = {}
|
6
|
+
settings[:max_amount] = 0
|
7
|
+
settings[:max_category] = 0
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
+
forecast.each do |row|
|
10
|
+
if row['type'] != 'settings'
|
11
|
+
category_length = row['category'].length
|
12
|
+
settings[:max_category] = category_length if category_length > settings[:max_category]
|
9
13
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
+
amount = if row['amount'].is_a?(Integer) || row['amount'].is_a?(Float)
|
15
|
+
((row['amount'] + 3) * 100).to_s
|
16
|
+
else
|
17
|
+
row['amount'].to_s
|
18
|
+
end
|
14
19
|
|
15
|
-
|
16
|
-
|
17
|
-
settings
|
18
|
-
end
|
20
|
+
settings[:max_amount] = amount.length if amount.length > settings[:max_amount]
|
21
|
+
end
|
19
22
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
23
|
+
if row['type'] == 'settings'
|
24
|
+
|
25
|
+
settings[:currency] = if row['frequency'] == "currency"
|
26
|
+
row['account']
|
27
|
+
else
|
28
|
+
"USD"
|
29
|
+
end
|
30
|
+
|
31
|
+
settings[:show_symbol] = if row['frequency'] == "show_symbol"
|
32
|
+
row['account']
|
33
|
+
else
|
34
|
+
true
|
35
|
+
end
|
36
|
+
|
37
|
+
settings[:sign_before_symbol] = if row['frequency'] == "sign_before_symbol"
|
38
|
+
row['account']
|
39
|
+
else
|
40
|
+
false
|
41
|
+
end
|
42
|
+
|
43
|
+
settings[:thousands_separator] = if row['frequency'] == "thousands_separator"
|
44
|
+
row['account']
|
45
|
+
else
|
46
|
+
","
|
47
|
+
end
|
35
48
|
end
|
49
|
+
|
50
|
+
settings.merge!(cli_options) if cli_options
|
36
51
|
end
|
37
52
|
|
38
|
-
|
53
|
+
settings
|
39
54
|
end
|
40
55
|
end
|
41
56
|
end
|