hledger-forecast 1.2.1 → 1.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.
data/example.journal CHANGED
@@ -1,51 +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 ; Bills
4
- Expenses:Food $500.00 ; Food
5
- Expenses:House $208.33 ; 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
6
6
  Assets:Bank
7
7
 
8
8
  ~ monthly from 2023-03-01 to 2025-01-01 * Mortgage
9
- Expenses:Mortgage $2,000.00 ; Mortgage
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 ; Holiday
13
+ Expenses:Holiday $125.00 ; Holiday
14
14
  Assets:Bank
15
15
 
16
- ~ monthly from 2023-03-01 to 2025-01-01 * Rainy day fund
17
- Assets:Savings $300.00 ; Rainy day fund
16
+ ~ monthly from 2023-03-01 to 2025-03-01 * Rainy day fund
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 ; Pension draw down
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 ; Top up holiday funds
29
+ Expenses:Holiday $500.00 ; Top up holiday funds
30
30
  Assets:Bank
31
31
 
32
- ~ yearly from 2023-04-01 * Annual Bonus
33
- Income:Bonus $-2,000.00; Annual Bonus
32
+ ~ yearly from 2023-04-01 * 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 ; Hair and beauty
37
+ Expenses:Personal Care $80.00 ; Hair and beauty
38
38
  Assets:Bank
39
39
 
40
- ~ 2023-06-01 * [TRACKED] Refund for that damn laptop
41
- Expenses:Shopping $-3,000.00; Refund for that damn laptop
40
+ ~ every 5 weeks from 2023-03-01 * Misc expenses
41
+ Expenses:General Expenses $30.00 ; Misc expenses
42
42
  Assets:Bank
43
43
 
44
- = Expenses:Food date:2024-01-01..2024-12-31
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
44
+ ~ 2023-07-01 * [TRACKED] Refund for that damn laptop
45
+ Expenses:Shopping $-3,000.00; Refund for that damn laptop
46
+ Assets:Bank
51
47
 
data/example.yml CHANGED
@@ -80,14 +80,19 @@ once:
80
80
  track: true
81
81
 
82
82
  custom:
83
- - frequency: "every 2 weeks"
84
- account: "Assets:Bank"
83
+ - account: "Assets:Bank"
85
84
  from: "2023-03-01"
86
- roll-up: 26
87
85
  transactions:
88
86
  - amount: 80
89
87
  category: "Expenses:Personal Care"
90
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
91
96
 
92
97
  settings:
93
98
  currency: USD
@@ -6,7 +6,7 @@ module HledgerForecast
6
6
  end
7
7
 
8
8
  def evaluate(amount)
9
- return amount unless amount.is_a?(String)
9
+ return amount.to_f unless amount.is_a?(String)
10
10
 
11
11
  @calculator.evaluate(amount.slice(1..-1))
12
12
  end
@@ -69,9 +69,16 @@ module HledgerForecast
69
69
  opts.separator ""
70
70
 
71
71
  opts.on("-f", "--forecast FILE",
72
- "The path to the FORECAST yaml file to generate from") do |file|
72
+ "The path to the FORECAST csv/yml file to generate from") do |file|
73
73
  options[:forecast_file] = file
74
- options[:output_file] ||= file.sub(/\.yml$/, '.journal')
74
+
75
+ options[:file_type] = if File.extname(file) == '.csv'
76
+ "csv"
77
+ else
78
+ "yml"
79
+ end
80
+
81
+ options[:output_file] ||= file.sub(options[:file_type], 'journal')
75
82
  end
76
83
 
77
84
  opts.on("-o", "--output-file FILE",
@@ -84,6 +91,11 @@ module HledgerForecast
84
91
  options[:transaction_file] = file
85
92
  end
86
93
 
94
+ opts.on("-v", "--verbose",
95
+ "Don't group transactions by type in the output file") do
96
+ options[:verbose] = true
97
+ end
98
+
87
99
  opts.on("--force",
88
100
  "Force an overwrite of the output file") do
89
101
  options[:force] = true
@@ -100,7 +112,8 @@ module HledgerForecast
100
112
  end
101
113
  end.parse!(args)
102
114
 
103
- options[:forecast_file] = "forecast.yml" unless options[:forecast_file]
115
+ options[:forecast_file] = "forecast.csv" unless options[:forecast_file]
116
+ options[:file_type] = "csv" unless options[:file_type]
104
117
  options[:output_file] = "forecast.journal" unless options[:output_file]
105
118
 
106
119
  options
@@ -114,7 +127,12 @@ module HledgerForecast
114
127
  opts.separator ""
115
128
 
116
129
  opts.on("-f", "--forecast FILE",
117
- "The path to the FORECAST yaml file to summarize") do |file|
130
+ "The path to the FORECAST csv/yml file to summarize") do |file|
131
+ options[:file_type] = if File.extname(file) == '.csv'
132
+ "csv"
133
+ else
134
+ "yml"
135
+ end
118
136
  options[:forecast_file] = file
119
137
  end
120
138
 
@@ -159,6 +177,7 @@ module HledgerForecast
159
177
  forecast = File.read(options[:forecast_file])
160
178
 
161
179
  begin
180
+ forecast = HledgerForecast::CSVParser.parse(forecast) if options[:file_type] == "csv"
162
181
  transactions = Generator.generate(forecast, options)
163
182
  rescue StandardError => e
164
183
  puts "An error occurred while generating transactions: #{e.message}"
@@ -166,6 +185,7 @@ module HledgerForecast
166
185
  end
167
186
 
168
187
  output_file = options[:output_file]
188
+
169
189
  if File.exist?(output_file) && !options[:force]
170
190
  print "\nFile '#{output_file}' already exists. Overwrite? (y/n): "
171
191
  overwrite = gets.chomp.downcase
@@ -184,6 +204,8 @@ module HledgerForecast
184
204
 
185
205
  def self.summarize(options)
186
206
  config = File.read(options[:forecast_file])
207
+ config = HledgerForecast::CSVParser.parse(config) if options[:file_type] == "csv"
208
+
187
209
  summarizer = Summarizer.summarize(config, options)
188
210
 
189
211
  puts SummarizerFormatter.format(summarizer[:output], summarizer[:settings])
@@ -0,0 +1,106 @@
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
@@ -55,7 +55,8 @@ module HledgerForecast
55
55
  description: t['description'],
56
56
  to: t['to'] ? Calculator.new.evaluate_date(Date.parse(block['from']), t['to']) : nil,
57
57
  modifiers: t['modifiers'] ? Transactions::Modifiers.get_modifiers(t, block) : [],
58
- track: Transactions::Trackers.track?(t, block, @settings) ? true : false
58
+ track: Transactions::Trackers.track?(t, block, @settings) ? true : false,
59
+ frequency: t['frequency'] || nil
59
60
  }
60
61
  end
61
62
 
@@ -58,7 +58,7 @@ module HledgerForecast
58
58
 
59
59
  output.last[:transactions] << {
60
60
  amount: amount,
61
- annualised_amount: amount * (block['roll-up'] || annualise(period)),
61
+ annualised_amount: amount * (t['roll-up'] || annualise(period)),
62
62
  rolled_up_amount: 0,
63
63
  category: t['category'],
64
64
  exclude: t['summary_exclude'],
@@ -33,14 +33,56 @@ module HledgerForecast
33
33
  def process_block(block)
34
34
  block[:transactions].each do |to, transactions|
35
35
  to = get_header(block[:to], to)
36
- block[:descriptions] = get_descriptions(transactions)
37
- frequency = get_periodic_rules(block[:type], block[:frequency])
38
36
 
39
- header = "#{frequency} #{block[:from]}#{to} * #{block[:descriptions]}\n"
40
- footer = " #{block[:account]}\n\n"
37
+ if block[:type] == "custom"
38
+ process_custom_transactions(block, to, transactions)
39
+ else
40
+ process_standard_transactions(block, to, transactions)
41
+ end
42
+ end
43
+ end
44
+
45
+ def process_custom_transactions(block, to, transactions)
46
+ transactions.each do |t|
47
+ frequency = get_periodic_rules(block[:type], t[:frequency])
48
+
49
+ header = build_header(block, to, frequency, t[:description])
50
+ footer = build_footer(block)
51
+ output << build_transaction(header, [t], footer)
52
+ end
53
+ end
54
+
55
+ def process_standard_transactions(block, to, transactions)
56
+ if @options[:verbose]
57
+ transactions.map do |t|
58
+ # Skip transactions that have been marked as tracked
59
+ next if t[:track]
41
60
 
42
- output << { header: header, transactions: write_transactions(transactions), footer: footer }
61
+ frequency = get_periodic_rules(block[:type], block[:frequency])
62
+ header = build_header(block, to, frequency, t[:description])
63
+ footer = build_footer(block)
64
+ output << build_transaction(header, [t], footer)
65
+ end
66
+ return
43
67
  end
68
+
69
+ block[:descriptions] = get_descriptions(transactions)
70
+ frequency = get_periodic_rules(block[:type], block[:frequency])
71
+ header = build_header(block, to, frequency, block[:descriptions])
72
+ footer = build_footer(block)
73
+ output << build_transaction(header, transactions, footer)
74
+ end
75
+
76
+ def build_header(block, to, frequency, description)
77
+ "#{frequency} #{block[:from]}#{to} * #{description}\n"
78
+ end
79
+
80
+ def build_footer(block)
81
+ " #{block[:account]}\n\n"
82
+ end
83
+
84
+ def build_transaction(header, transactions, footer)
85
+ { header: header, transactions: write_transactions(transactions), footer: footer }
44
86
  end
45
87
 
46
88
  def get_header(block, transaction)
@@ -32,6 +32,13 @@ module HledgerForecast
32
32
  end
33
33
 
34
34
  def self.exists?(transaction, account, from, to, options)
35
+
36
+ if !options[:transaction_file]
37
+ puts "\nWarning: ".bold.yellow + "For tracked transactions, please specify a file with the `-t` flag"
38
+ puts "ERROR: ".bold.red + "Tracked transactions ignored for now"
39
+ return
40
+ end
41
+
35
42
  # Format the money
36
43
  amount = Formatter.format_money(transaction['amount'], options)
37
44
  inverse_amount = Formatter.format_money(transaction['amount'] * -1, options)
@@ -1,3 +1,3 @@
1
1
  module HledgerForecast
2
- VERSION = "1.2.1"
2
+ VERSION = "1.4.0"
3
3
  end
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'colorize'
4
+ require 'csv'
4
5
  require 'date'
5
6
  require 'dentaku'
6
7
  require 'highline'
@@ -14,6 +15,7 @@ Money.rounding_mode = BigDecimal::ROUND_HALF_UP
14
15
 
15
16
  require_relative 'hledger_forecast/calculator'
16
17
  require_relative 'hledger_forecast/cli'
18
+ require_relative 'hledger_forecast/csv_parser'
17
19
  require_relative 'hledger_forecast/formatter'
18
20
  require_relative 'hledger_forecast/generator'
19
21
  require_relative 'hledger_forecast/settings'
@@ -24,4 +26,3 @@ require_relative 'hledger_forecast/version'
24
26
  require_relative 'hledger_forecast/transactions/default'
25
27
  require_relative 'hledger_forecast/transactions/modifiers'
26
28
  require_relative 'hledger_forecast/transactions/trackers'
27
-
data/spec/command_spec.rb CHANGED
@@ -14,7 +14,6 @@ JOURNAL
14
14
 
15
15
  RSpec.describe 'command' do
16
16
  it 'uses the CLI to generate an output' do
17
- # Delete the file if it exists
18
17
  generated_journal = './test_output.journal'
19
18
  File.delete(generated_journal) if File.exist?(generated_journal)
20
19
 
@@ -22,4 +21,13 @@ RSpec.describe 'command' do
22
21
 
23
22
  expect(File.read(generated_journal)).to eq(output)
24
23
  end
24
+
25
+ it 'uses the CLI to generate an output with a CSV config file' do
26
+ generated_journal = './test_output.journal'
27
+ File.delete(generated_journal) if File.exist?(generated_journal)
28
+
29
+ system("./bin/hledger-forecast generate -f ./spec/stubs/forecast.csv -o ./test_output.journal --force")
30
+
31
+ expect(File.read(generated_journal)).to eq(output)
32
+ end
25
33
  end
@@ -0,0 +1,32 @@
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
@@ -0,0 +1,110 @@
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
data/spec/custom_spec.rb CHANGED
@@ -2,20 +2,17 @@ require_relative '../lib/hledger_forecast'
2
2
 
3
3
  base_config = <<~YAML
4
4
  custom:
5
- - frequency: "every 2 weeks"
5
+ - account: "[Assets:Bank]"
6
6
  from: "2023-05-01"
7
- account: "[Assets:Bank]"
8
7
  transactions:
9
8
  - amount: 80
10
9
  category: "[Expenses:Personal Care]"
11
10
  description: Hair and beauty
12
- - frequency: "every 5 days"
13
- from: "2023-05-01"
14
- account: "[Assets:Checking]"
15
- transactions:
11
+ frequency: "every 2 weeks"
16
12
  - amount: 50
17
13
  category: "[Expenses:Groceries]"
18
14
  description: Gotta feed that stomach
15
+ frequency: "every 5 days"
19
16
 
20
17
  settings:
21
18
  currency: GBP
@@ -28,19 +25,19 @@ base_output = <<~JOURNAL
28
25
 
29
26
  ~ every 5 days from 2023-05-01 * Gotta feed that stomach
30
27
  [Expenses:Groceries] £50.00; Gotta feed that stomach
31
- [Assets:Checking]
28
+ [Assets:Bank]
32
29
 
33
30
  JOURNAL
34
31
 
35
32
  calculated_config = <<~YAML
36
33
  custom:
37
- - frequency: "every 2 weeks"
34
+ - account: "[Assets:Bank]"
38
35
  from: "2023-05-01"
39
- account: "[Assets:Bank]"
40
36
  transactions:
41
37
  - amount: 80
42
38
  category: "[Expenses:Personal Care]"
43
39
  description: Hair and beauty
40
+ frequency: "every 2 weeks"
44
41
  to: "=6"
45
42
 
46
43
  settings:
@@ -0,0 +1,5 @@
1
+ type,frequency,account,from,to,description,category,amount,roll-up,summary_exclude,track
2
+ monthly,,Assets:Bank,01/03/2023,,Mortgage,Expenses:Mortgage,2000.55,,,
3
+ monthly,,Assets:Bank,01/03/2023,,Food,Expenses:Food,100,,,
4
+ monthly,,Assets:Savings,01/03/2023,,Savings,Assets:Bank,-1000,,,
5
+ settings,currency,GBP,,,,,,,,
@@ -20,22 +20,22 @@ config = <<~YAML
20
20
  description: Savings
21
21
 
22
22
  custom:
23
- - frequency: "every 2 weeks"
23
+ - account: "[Assets:Bank]"
24
24
  from: "2023-05-01"
25
- account: "[Assets:Bank]"
26
- roll-up: 26
27
25
  transactions:
28
26
  - amount: 80
29
27
  category: "[Expenses:Personal Care]"
30
28
  description: Hair and beauty
31
- - frequency: "every 5 days"
29
+ frequency: "every 2 weeks"
30
+ roll-up: 26
31
+ - account: "[Assets:Checking]"
32
32
  from: "2023-05-01"
33
- account: "[Assets:Checking]"
34
- roll-up: 73
35
33
  transactions:
36
34
  - amount: 50
37
35
  category: "[Expenses:Groceries]"
38
36
  description: Gotta feed that stomach
37
+ frequency: "every 5 days"
38
+ roll-up: 73
39
39
 
40
40
  settings:
41
41
  currency: GBP
@@ -57,7 +57,7 @@ RSpec.describe HledgerForecast::Summarizer do
57
57
 
58
58
  expect(output.first).to include(:account, :from, :to, :type, :frequency)
59
59
  expect(output.first[:amount]).to eq(2000.55)
60
- expect(output.last[:rolled_up_amount]).to eq(304) # ((50 * 73) / 12)
60
+ expect(output.last[:rolled_up_amount]).to eq((50.0 * 73.0) / 12.0) # ((50 * 73) / 12)
61
61
  expect(output.length).to eq(5)
62
62
  end
63
63