hledger-forecast 1.5.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/release.yml +22 -0
  3. data/.github/workflows/{ci.yml → test.yml} +5 -5
  4. data/.rubocop.yml +17 -17
  5. data/README.md +8 -172
  6. data/example.journal +14 -14
  7. data/hledger-forecast.gemspec +1 -1
  8. data/lib/hledger_forecast/calculator.rb +5 -1
  9. data/lib/hledger_forecast/cli.rb +5 -18
  10. data/lib/hledger_forecast/generator.rb +52 -35
  11. data/lib/hledger_forecast/settings.rb +42 -27
  12. data/lib/hledger_forecast/summarizer.rb +28 -62
  13. data/lib/hledger_forecast/summarizer_formatter.rb +12 -3
  14. data/lib/hledger_forecast/transactions/default.rb +28 -57
  15. data/lib/hledger_forecast/transactions/trackers.rb +34 -40
  16. data/lib/hledger_forecast/utilities.rb +14 -0
  17. data/lib/hledger_forecast/version.rb +1 -1
  18. data/lib/hledger_forecast.rb +1 -2
  19. data/spec/cli_spec.rb +3 -12
  20. data/spec/computed_amounts_spec.rb +11 -22
  21. data/spec/custom_spec.rb +15 -35
  22. data/spec/half-yearly_spec.rb +6 -13
  23. data/spec/monthly_end_date_spec.rb +8 -18
  24. data/spec/monthly_end_date_transaction_spec.rb +20 -45
  25. data/spec/monthly_spec.rb +11 -28
  26. data/spec/once_spec.rb +6 -13
  27. data/spec/quarterly_spec.rb +5 -12
  28. data/spec/summarizer_spec.rb +11 -42
  29. data/spec/track_spec.rb +19 -49
  30. data/spec/verbose_output_spec.rb +3 -3
  31. data/spec/yearly_spec.rb +5 -12
  32. metadata +10 -18
  33. data/example.yml +0 -98
  34. data/lib/hledger_forecast/csv_parser.rb +0 -106
  35. data/spec/csv_and_yml_comparison_spec.rb +0 -32
  36. data/spec/csv_parser_spec.rb +0 -110
  37. data/spec/modifier_spec.rb +0 -102
  38. data/spec/stubs/forecast.yml +0 -19
data/example.yml DELETED
@@ -1,98 +0,0 @@
1
- monthly:
2
- - account: "Assets:Bank"
3
- from: "2023-03-01"
4
- transactions:
5
- - amount: -3500
6
- category: "Income:Salary"
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
15
- - amount: 500
16
- category: "Expenses:Food"
17
- description: Food
18
- modifiers:
19
- - amount: 0.02
20
- description: "Inflation"
21
- from: "2024-01-01"
22
- to: "2024-12-31"
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
31
- category: "Expenses:Holiday"
32
- description: Holiday
33
- to: "=12"
34
- - account: "Assets:Bank"
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"
43
- transactions:
44
- - amount: -500
45
- category: "Income:Pension"
46
- description: Pension draw down
47
-
48
- quarterly:
49
- - account: "Assets:Bank"
50
- from: "2023-04-01"
51
- transactions:
52
- - amount: -1000.00
53
- category: "Income:Bonus"
54
- description: Quarterly bonus
55
-
56
- half-yearly:
57
- - account: "Assets:Bank"
58
- from: "2023-04-01"
59
- transactions:
60
- - amount: 500
61
- category: "Expenses:Holiday"
62
- description: Top up holiday funds
63
-
64
- yearly:
65
- - account: "Assets:Bank"
66
- from: "2023-04-01"
67
- transactions:
68
- - amount: -2000.00
69
- category: "Income:Bonus"
70
- description: Annual Bonus
71
-
72
- once:
73
- - account: "Assets:Bank"
74
- from: "2023-03-05"
75
- transactions:
76
- - amount: -3000
77
- category: "Expenses:Shopping"
78
- description: Refund for that damn laptop
79
- summary_exclude: true
80
- track: true
81
-
82
- custom:
83
- - account: "Assets:Bank"
84
- from: "2023-03-01"
85
- transactions:
86
- - amount: 80
87
- category: "Expenses:Personal Care"
88
- description: Hair and beauty
89
- frequency: "every 2 weeks"
90
- roll-up: 26
91
- - amount: 30
92
- category: "Expenses:General Expenses"
93
- description: Misc expenses
94
- frequency: "every 5 weeks"
95
- roll-up: 10.4
96
-
97
- settings:
98
- currency: USD
@@ -1,106 +0,0 @@
1
- module HledgerForecast
2
- # Formats various items used throughout the application
3
- class CSVParser
4
- def self.parse(csv_data, cli_options = nil)
5
- new.parse(csv_data, cli_options)
6
- end
7
-
8
- def parse(csv_data, _cli_options)
9
- csv_data = CSV.parse(csv_data, headers: true)
10
- yaml_data = {}
11
- group_by_type(csv_data, yaml_data)
12
- yaml_data.to_yaml
13
- end
14
-
15
- private
16
-
17
- def group_by_type(csv_data, yaml_data)
18
- csv_data.group_by { |row| row['type'] }.each do |type, rows|
19
- if type == 'settings'
20
- handle_settings(rows, yaml_data)
21
- else
22
- yaml_data[type] ||= []
23
- group_by_account_and_from(rows, yaml_data[type], type)
24
- end
25
- end
26
- end
27
-
28
- def handle_settings(rows, yaml_data)
29
- yaml_data['settings'] ||= {}
30
- rows.each do |row|
31
- yaml_data['settings'][row['frequency']] = cast_to_proper_type(row['account'])
32
- end
33
- end
34
-
35
- def group_by_account_and_from(rows, yaml_rows, type)
36
- rows.group_by { |row| [row['account'], row['from']] }.each do |(account, from), transactions|
37
- yaml_rows << if type == 'custom'
38
- build_custom_transaction(account, from, transactions)
39
- else
40
- build_transaction(account, from, transactions)
41
- end
42
- end
43
- end
44
-
45
- def build_transaction(account, from, transactions)
46
- transaction = {
47
- 'account' => account,
48
- 'from' => Date.parse(from).strftime('%Y-%m-%d'),
49
- 'transactions' => []
50
- }
51
-
52
- transactions.each do |row|
53
- transaction['transactions'] << build_transaction_data(row)
54
- end
55
-
56
- transaction
57
- end
58
-
59
- def build_custom_transaction(account, from, transactions)
60
- transaction = {
61
- 'account' => account,
62
- 'from' => Date.parse(from).strftime('%Y-%m-%d'),
63
- 'transactions' => []
64
- }
65
-
66
- transactions.each do |row|
67
- transaction_data = build_transaction_data(row)
68
- transaction_data['frequency'] = row['frequency']
69
- transaction_data['roll-up'] = row['roll-up'].to_f if row['roll-up']
70
- transaction['transactions'] << transaction_data
71
- end
72
-
73
- transaction
74
- end
75
-
76
- def build_transaction_data(row)
77
- transaction_data = {
78
- 'amount' => row['amount'].start_with?("=") ? row['amount'].to_s : row['amount'].to_f,
79
- 'category' => row['category'],
80
- 'description' => row['description']
81
- }
82
-
83
- if row['to']
84
- transaction_data['to'] = if row['to'].start_with?("=")
85
- row['to']
86
- else
87
- Date.parse(row['to']).strftime('%Y-%m-%d')
88
- end
89
- end
90
-
91
- transaction_data['summary_exclude'] = true if row['summary_exclude'] && row['summary_exclude'].downcase == "true"
92
- transaction_data['track'] = true if row['track'] && row['track'].downcase == "true"
93
-
94
- transaction_data
95
- end
96
-
97
- def cast_to_proper_type(str)
98
- case str.downcase
99
- when 'true', 'false'
100
- str.downcase == 'true'
101
- else
102
- str
103
- end
104
- end
105
- end
106
- end
@@ -1,32 +0,0 @@
1
- require_relative '../lib/hledger_forecast'
2
-
3
- RSpec.describe 'CSV and yml outputs' do
4
- it 'should return the same value when ran through hledger' do
5
- generated_journal = './test_output.journal'
6
- File.delete(generated_journal) if File.exist?(generated_journal)
7
-
8
- system("./bin/hledger-forecast generate -f example.csv -o ./test_output.journal -t ./spec/stubs/transactions_not_found.journal --force")
9
- csv_output = `hledger -f ./test_output.journal --forecast bal -b=2023-01 -e=2023-06`
10
-
11
- system("./bin/hledger-forecast generate -f example.yml -o ./test_output.journal -t ./spec/stubs/transactions_not_found.journal --force")
12
- yml_output = `hledger -f ./test_output.journal --forecast bal -b=2023-01 -e=2023-06`
13
-
14
- expect(csv_output).to eq(yml_output)
15
- end
16
-
17
- # it 'check that it can fail!' do
18
- # generated_journal = './test_output.journal'
19
- # File.delete(generated_journal) if File.exist?(generated_journal)
20
- #
21
- # system("./bin/hledger-forecast generate -f ./spec/stubs/csv_and_yml/forecast.csv -o ./test_output.journal --force > /dev/null 2>&1")
22
- #
23
- # ### CHANGE DATE!!!!!!!!!!!!!!!!
24
- # csv_output = `hledger -f ./test_output.journal --forecast bal -b=2023-01 -e=2023-03`
25
- # ### CHANGE DATE!!!!!!!!!!!!!!!!
26
- #
27
- # system("./bin/hledger-forecast generate -f ./spec/stubs/csv_and_yml/forecast.yml -o ./test_output.journal --force > /dev/null 2>&1")
28
- # yml_output = `hledger -f ./test_output.journal --forecast bal -b=2023-01 -e=2023-06`
29
- #
30
- # expect(csv_output).not_to eq(yml_output)
31
- # end
32
- end
@@ -1,110 +0,0 @@
1
- require_relative '../lib/hledger_forecast'
2
-
3
- input = <<~CSV
4
- type,frequency,account,from,to,description,category,amount,roll-up,summary_exclude,track
5
- monthly,,Assets:Bank,01/03/2023,,Salary,Income:Salary,-3500,,,
6
- monthly,,Assets:Bank,01/03/2023,01/01/2025,Mortgage,Expenses:Mortgage,2000,,,
7
- monthly,,Assets:Bank,01/03/2023,,Bills,Expenses:Bills,175,,,
8
- monthly,,Assets:Bank,01/03/2023,,Food,Expenses:Food,500,,,
9
- monthly,,Assets:Bank,01/03/2023,,New Kitchen,Expenses:House,=5000/24,,,
10
- monthly,,Assets:Bank,01/03/2023,=12,Holiday,Expenses:Holiday,125,,,
11
- monthly,,Assets:Bank,01/03/2023,01/01/2025,Rainy day fund,Assets:Savings,300,,,
12
- monthly,,Assets:Pension,01/01/2024,,Pension draw down,Income:Pension,-500,,,
13
- quarterly,,Assets:Bank,01/04/2023,,Quarterly bonus,Income:Bonus,-1000,,,
14
- half-yearly,,Assets:Bank,01/04/2023,,Top up holiday funds,Expenses:Holiday,500,,,
15
- yearly,,Assets:Bank,01/04/2023,,Annual bonus,Income:Bonus,-2000,,,
16
- once,,Assets:Bank,05/03/2023,,Refund for that damn laptop,Expenses:Shopping,-3000,,TRUE,TRUE
17
- custom,every 2 weeks,Assets:Bank,01/03/2023,,Hair and beauty,Expenses:Personal Care,80,26,,
18
- settings,currency,USD,,,,,,,,
19
- settings,show_symbol,TRUE,,,,,,,,
20
- settings,thousands_separator,TRUE,,,,,,,,
21
- CSV
22
-
23
- output = <<~YAML
24
- ---
25
- monthly:
26
- - account: Assets:Bank
27
- from: '2023-03-01'
28
- transactions:
29
- - amount: -3500.0
30
- category: Income:Salary
31
- description: Salary
32
- - amount: 2000.0
33
- category: Expenses:Mortgage
34
- description: Mortgage
35
- to: '2025-01-01'
36
- - amount: 175.0
37
- category: Expenses:Bills
38
- description: Bills
39
- - amount: 500.0
40
- category: Expenses:Food
41
- description: Food
42
- - amount: "=5000/24"
43
- category: Expenses:House
44
- description: New Kitchen
45
- - amount: 125.0
46
- category: Expenses:Holiday
47
- description: Holiday
48
- to: "=12"
49
- - amount: 300.0
50
- category: Assets:Savings
51
- description: Rainy day fund
52
- to: '2025-01-01'
53
- - account: Assets:Pension
54
- from: '2024-01-01'
55
- transactions:
56
- - amount: -500.0
57
- category: Income:Pension
58
- description: Pension draw down
59
- quarterly:
60
- - account: Assets:Bank
61
- from: '2023-04-01'
62
- transactions:
63
- - amount: -1000.0
64
- category: Income:Bonus
65
- description: Quarterly bonus
66
- half-yearly:
67
- - account: Assets:Bank
68
- from: '2023-04-01'
69
- transactions:
70
- - amount: 500.0
71
- category: Expenses:Holiday
72
- description: Top up holiday funds
73
- yearly:
74
- - account: Assets:Bank
75
- from: '2023-04-01'
76
- transactions:
77
- - amount: -2000.0
78
- category: Income:Bonus
79
- description: Annual bonus
80
- once:
81
- - account: Assets:Bank
82
- from: '2023-03-05'
83
- transactions:
84
- - amount: -3000.0
85
- category: Expenses:Shopping
86
- description: Refund for that damn laptop
87
- summary_exclude: true
88
- track: true
89
- custom:
90
- - account: Assets:Bank
91
- from: '2023-03-01'
92
- transactions:
93
- - amount: 80.0
94
- category: Expenses:Personal Care
95
- description: Hair and beauty
96
- frequency: every 2 weeks
97
- roll-up: 26.0
98
- settings:
99
- currency: USD
100
- show_symbol: true
101
- thousands_separator: true
102
- YAML
103
-
104
- RSpec.describe 'CSV parser' do
105
- it 'converts a CSV file to the YML output needed for the plugin' do
106
- computed_yaml = HledgerForecast::CSVParser.parse(input)
107
-
108
- expect(computed_yaml).to eq(output)
109
- end
110
- end
@@ -1,102 +0,0 @@
1
- require_relative '../lib/hledger_forecast'
2
-
3
- base_config = <<~YAML
4
- monthly:
5
- - account: "Assets:Bank"
6
- from: "2023-01-01"
7
- transactions:
8
- - amount: 300
9
- category: "Expenses:Groceries"
10
- description: Food shopping
11
- modifiers:
12
- - amount: 0.02
13
- description: "Y1 inflation"
14
- from: "2024-01-01"
15
- to: "2024-12-31"
16
- - amount: 0.05
17
- description: "Y2 inflation"
18
- from: "2025-01-01"
19
- to: "2025-12-31"
20
- - account: "Assets:Savings"
21
- from: "2023-05-01"
22
- transactions:
23
- - amount: 500
24
- category: "Assets:Bank"
25
- description: Savings
26
- modifiers:
27
- - amount: 0.1
28
- description: "Savings uplift"
29
- from: "2024-05-01"
30
- to: "2025-04-30"
31
-
32
- settings:
33
- currency: USD
34
- YAML
35
-
36
- base_journal = <<~JOURNAL
37
- ~ monthly from 2023-01-01 * Food shopping
38
- Expenses:Groceries $300.00; Food shopping
39
- Assets:Bank
40
-
41
- ~ monthly from 2023-05-01 * Savings
42
- Assets:Bank $500.00; Savings
43
- Assets:Savings
44
-
45
- = Expenses:Groceries date:2024-01-01..2024-12-31
46
- Expenses:Groceries *0.02 ; Food shopping - Y1 inflation
47
- Assets:Bank *-0.02
48
-
49
- = Expenses:Groceries date:2025-01-01..2025-12-31
50
- Expenses:Groceries *0.05 ; Food shopping - Y2 inflation
51
- Assets:Bank *-0.05
52
-
53
- = Assets:Bank date:2024-05-01..2025-04-30
54
- Assets:Bank *0.1 ; Savings - Savings uplift
55
- Assets:Savings *-0.1
56
-
57
- JOURNAL
58
-
59
- no_date_config = <<~YAML
60
- monthly:
61
- - account: "Assets:Bank"
62
- from: "2023-01-01"
63
- transactions:
64
- - amount: 500
65
- category: "Expenses:Groceries"
66
- description: Food shopping
67
- modifiers:
68
- - amount: 0.1
69
- description: "Inflation"
70
-
71
- settings:
72
- currency: USD
73
- YAML
74
-
75
- no_date_journal = <<~JOURNAL
76
- ~ monthly from 2023-01-01 * Food shopping
77
- Expenses:Groceries $500.00; Food shopping
78
- Assets:Bank
79
-
80
- = Expenses:Groceries date:2023-01-01
81
- Expenses:Groceries *0.1 ; Food shopping - Inflation
82
- Assets:Bank *-0.1
83
-
84
- JOURNAL
85
-
86
- RSpec.describe 'Applying modifiers to transactions -' do
87
- it 'Auto-postings should be created correctly' do
88
- generated = HledgerForecast::Generator
89
-
90
- generated_journal = generated.generate(base_config)
91
-
92
- expect(generated_journal).to eq(base_journal)
93
- end
94
-
95
- it 'Auto-postings should be created correctly if no dates are set' do
96
- generated = HledgerForecast::Generator
97
-
98
- generated_journal = generated.generate(no_date_config)
99
-
100
- expect(generated_journal).to eq(no_date_journal)
101
- end
102
- end
@@ -1,19 +0,0 @@
1
- monthly:
2
- - account: "Assets:Bank"
3
- from: "2023-03-01"
4
- transactions:
5
- - amount: 2000.55
6
- category: "Expenses:Mortgage"
7
- description: Mortgage
8
- - amount: 100
9
- category: "Expenses:Food"
10
- description: Food
11
- - account: "Assets:Savings"
12
- from: "2023-03-01"
13
- transactions:
14
- - amount: -1000
15
- category: "Assets:Bank"
16
- description: Savings
17
-
18
- settings:
19
- currency: GBP