hledger-forecast 0.4.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,32 +1,69 @@
1
1
  require_relative '../lib/hledger_forecast'
2
2
 
3
- config = <<~YAML
3
+ base_config = <<~YAML
4
4
  settings:
5
5
  currency: GBP
6
6
 
7
7
  monthly:
8
8
  - from: "2023-03-01"
9
- to: "2023-06-01"
10
9
  account: "Assets:Bank"
11
10
  transactions:
12
11
  - description: Mortgage
12
+ to: "2023-06-01"
13
13
  category: "Expenses:Mortgage"
14
14
  amount: 2000.00
15
+ - description: Mortgage top up
16
+ to: "2023-06-01"
17
+ category: "Expenses:Mortgage Top Up"
18
+ amount: 200.00
15
19
  - description: Food
16
20
  category: "Expenses:Food"
17
21
  amount: 100.00
22
+ - description: Party time
23
+ category: "Expenses:Going Out"
24
+ amount: 50.00
18
25
  YAML
19
26
 
20
- output = <<~JOURNAL
21
- ~ monthly from 2023-03-01 to 2023-06-01 * Mortgage, Food
27
+ base_output = <<~JOURNAL
28
+ ~ monthly from 2023-03-01 to 2023-06-01 * Mortgage, Mortgage top up
29
+ Expenses:Mortgage £2,000.00; Mortgage
30
+ Expenses:Mortgage Top Up £200.00 ; Mortgage top up
31
+ Assets:Bank
32
+
33
+ ~ monthly from 2023-03-01 * Food, Party time
34
+ Expenses:Food £100.00 ; Food
35
+ Expenses:Going Out £50.00 ; Party time
36
+ Assets:Bank
37
+
38
+ JOURNAL
39
+
40
+ computed_config = <<~YAML
41
+ settings:
42
+ currency: GBP
43
+
44
+ monthly:
45
+ - from: "2023-03-01"
46
+ account: "Assets:Bank"
47
+ transactions:
48
+ - description: Mortgage
49
+ category: "Expenses:Mortgage"
50
+ to: "=12"
51
+ amount: 2000.00
52
+ YAML
53
+
54
+ computed_output = <<~JOURNAL
55
+ ~ monthly from 2023-03-01 to 2024-02-29 * Mortgage
22
56
  Expenses:Mortgage £2,000.00; Mortgage
23
- Expenses:Food £100.00 ; Food
24
57
  Assets:Bank
25
58
 
26
59
  JOURNAL
27
60
 
28
61
  RSpec.describe 'generate' do
29
- it 'generates a forecast with correct MONTHLY transactions that have an end date, at the top level' do
30
- expect(HledgerForecast::Generator.generate(config)).to eq(output)
62
+ it 'generates a forecast with correct MONTHLY transactions that have an end date' do
63
+ expect(HledgerForecast::Generator.generate(base_config)).to eq(base_output)
64
+ end
65
+
66
+ it 'generates a forecast with correct MONTHLY transactions that have a COMPUTED end date' do
67
+ expect(HledgerForecast::Generator.generate(computed_config)).to eq(computed_output)
31
68
  end
32
69
  end
data/spec/track_spec.rb CHANGED
@@ -42,70 +42,13 @@ base_output = <<~JOURNAL
42
42
  JOURNAL
43
43
 
44
44
  RSpec.describe 'Tracking transactions -' do
45
- it 'Determines which transactions should be tracked' do
46
- generated = HledgerForecast::Generator
47
- generated.generate(base_config)
48
- tracked = generated.tracked
49
-
50
- expect(tracked[0]['transaction']).to eq(
51
- { "amount" => "£3,000.00", "category" => "Expenses:Tax", "description" => "Tax owed",
52
- "inverse_amount" => "£-3,000.00", "track" => true }
53
- )
54
- expect(tracked[0]['account']).to eq("Assets:Bank")
55
-
56
- expect(tracked[1]['transaction']).to eq(
57
- { "amount" => "£-1,500.00", "category" => "Income:Salary", "description" => "Salary", "to" => "2023-08-01",
58
- "inverse_amount" => "£1,500.00", "track" => true }
59
- )
60
- expect(tracked[1]['account']).to eq("Assets:Bank")
61
- end
62
-
63
- it 'marks a transaction as NOT FOUND if it doesnt exist' do
64
- generated = HledgerForecast::Generator
65
- generated.tracked = {} # Clear tracked transactions
66
- generated.generate(base_config)
67
- transactions_to_track = generated.tracked
68
-
69
- track = HledgerForecast::Tracker.track(transactions_to_track, 'spec/stubs/transactions_not_found.journal')
70
-
71
- expect(track[0]['found']).to eq(false)
72
- expect(track[1]['found']).to eq(false)
73
- end
74
-
75
- it 'marks a transaction as FOUND if it exists' do
76
- generated = HledgerForecast::Generator
77
- generated.tracked = {} # Clear tracked transactions
78
- generated.generate(base_config)
79
- transactions_to_track = generated.tracked
80
-
81
- track = HledgerForecast::Tracker.track(transactions_to_track, 'spec/stubs/transactions_found.journal')
82
-
83
- expect(track[0]['found']).to eq(true)
84
- expect(track[1]['found']).to eq(true)
85
- end
86
-
87
- it 'marks a transaction as FOUND if it exists, even if the category/amount are inversed' do
88
- generated = HledgerForecast::Generator
89
- generated.tracked = {} # Clear tracked transactions
90
- generated.generate(base_config)
91
- transactions_to_track = generated.tracked
92
-
93
- track = HledgerForecast::Tracker.track(transactions_to_track, 'spec/stubs/transactions_found_inverse.journal')
94
-
95
- expect(track[0]['found']).to eq(true)
96
- end
97
-
98
45
  it 'writes a NON-FOUND entry into a journal' do
99
46
  options = {}
100
47
  options[:transaction_file] = 'spec/stubs/transactions_not_found.journal'
101
48
 
102
- generated = HledgerForecast::Generator
103
- generated.tracked = {} # Clear tracked transactions
104
-
105
- generated_journal = generated.generate(base_config, options)
49
+ generated_journal = HledgerForecast::Generator.generate(base_config, options)
106
50
 
107
- expected_output = base_output
108
- expect(generated_journal).to eq(expected_output)
51
+ expect(generated_journal).to eq(base_output)
109
52
  end
110
53
 
111
54
  it 'writes a NON-FOUND entry for dates that are close to the current period' do
@@ -147,12 +90,10 @@ RSpec.describe 'Tracking transactions -' do
147
90
  options = {}
148
91
  options[:transaction_file] = temp_file.path
149
92
 
150
- generated = HledgerForecast::Generator
151
- generated.tracked = {} # Clear tracked transactions
152
-
153
- generated_journal = generated.generate(forecast_config, options)
93
+ generated_journal = HledgerForecast::Generator.generate(forecast_config, options)
154
94
 
155
95
  expected_output = <<~JOURNAL
96
+
156
97
  ~ #{next_month} * [TRACKED] New kitchen
157
98
  Expenses:House £5,000.00; New kitchen
158
99
  Assets:Bank
@@ -180,10 +121,7 @@ RSpec.describe 'Tracking transactions -' do
180
121
  options = {}
181
122
  options[:transaction_file] = 'spec/stubs/transactions_not_found.journal'
182
123
 
183
- generated = HledgerForecast::Generator
184
- generated.tracked = {} # Clear tracked transactions
185
-
186
- generated_journal = generated.generate(forecast_config, options)
124
+ generated_journal = HledgerForecast::Generator.generate(forecast_config, options)
187
125
 
188
126
  output = <<~JOURNAL
189
127
  ~ monthly from #{next_month} * Food expenses
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.0
4
+ version: 1.0.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-09 00:00:00.000000000 Z
11
+ date: 2023-05-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -113,10 +113,15 @@ files:
113
113
  - example.yml
114
114
  - hledger-forecast.gemspec
115
115
  - lib/hledger_forecast.rb
116
+ - lib/hledger_forecast/calculator.rb
116
117
  - lib/hledger_forecast/cli.rb
118
+ - lib/hledger_forecast/formatter.rb
117
119
  - lib/hledger_forecast/generator.rb
118
- - lib/hledger_forecast/summarize.rb
119
- - lib/hledger_forecast/tracker.rb
120
+ - lib/hledger_forecast/settings.rb
121
+ - lib/hledger_forecast/summarizer.rb
122
+ - lib/hledger_forecast/transactions/default.rb
123
+ - lib/hledger_forecast/transactions/modifiers.rb
124
+ - lib/hledger_forecast/transactions/trackers.rb
120
125
  - lib/hledger_forecast/version.rb
121
126
  - spec/command_spec.rb
122
127
  - spec/computed_amounts_spec.rb
@@ -144,16 +149,16 @@ require_paths:
144
149
  - lib
145
150
  required_ruby_version: !ruby/object:Gem::Requirement
146
151
  requirements:
147
- - - ">="
152
+ - - "~>"
148
153
  - !ruby/object:Gem::Version
149
- version: '0'
154
+ version: '3.0'
150
155
  required_rubygems_version: !ruby/object:Gem::Requirement
151
156
  requirements:
152
157
  - - ">="
153
158
  - !ruby/object:Gem::Version
154
159
  version: '0'
155
160
  requirements: []
156
- rubygems_version: 3.4.12
161
+ rubygems_version: 3.2.3
157
162
  signing_key:
158
163
  specification_version: 4
159
164
  summary: An extended wrapper around hledger's forecasting functionality
@@ -1,37 +0,0 @@
1
- module HledgerForecast
2
- # Checks for the existence of a transaction in a journal file and tracks it
3
- class Tracker
4
- def self.track(transactions, transaction_file)
5
- next_month = Date.new(Date.today.year, Date.today.month, 1).next_month
6
-
7
- transactions.each_with_object({}) do |(key, transaction), updated_transactions|
8
- found = transaction_exists?(transaction_file, transaction['from'], Date.today, transaction['account'],
9
- transaction['transaction'])
10
- updated_transactions[key] = transaction.merge('from' => next_month, 'found' => found)
11
- end
12
- end
13
-
14
- def self.latest_date(file)
15
- command = %(hledger print --file #{file} | grep '^[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}' | awk '{print $1}' | sort -r | head -n 1)
16
-
17
- date_output = `#{command}`
18
- date_output.strip
19
- end
20
-
21
- def self.transaction_exists?(file, from, to, account, transaction)
22
- category = escape_str(transaction['category'])
23
- amount = transaction['amount']
24
- inverse_amount = transaction['inverse_amount']
25
-
26
- # We run two commands and check to see if category +/- amount or account +/- amount exists
27
- command1 = %(hledger print -f #{file} "date:#{from}..#{to}" | tr -s '[:space:]' ' ' | grep -q -Eo "#{category} (#{amount}|#{inverse_amount})")
28
- command2 = %(hledger print -f #{file} "date:#{from}..#{to}" | tr -s '[:space:]' ' ' | grep -q -Eo "#{account} (#{amount}|#{inverse_amount})")
29
-
30
- system(command1) || system(command2)
31
- end
32
-
33
- def self.escape_str(str)
34
- str.gsub('[', '\\[').gsub(']', '\\]').gsub('(', '\\(').gsub(')', '\\)')
35
- end
36
- end
37
- end