hledger-forecast 0.1.4 → 0.1.6

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d7bd2190c7f86b3d6a1fe76583a8f7e959f4429719b9903de343d25e0bf3b51
4
- data.tar.gz: 7bb59da35fc2f9f3c47b6ed8b45d2ef38fb9c5c084c6bce9d6ee66fd004157a8
3
+ metadata.gz: 60e8bd939c2bb57d5d1fdf01d39d4fd7bc1cd59886a189b8b0d8a8fe7a7b6640
4
+ data.tar.gz: e752946a04d49b531ca303a8832d11a686d610392ce29d5a7d96c5aae2658dee
5
5
  SHA512:
6
- metadata.gz: 3251f466cd2072685cf063268aca5c9ddc6231e9ac5c217049369c3e6b1c1d729967059441d4318247b7477ebaf357dc317e4f40df6b8e44dbe59a14b5005b9a
7
- data.tar.gz: 55251b35a8cfea885fbbcb861ad650635a0fed4c91e618942ddd4eb76c38b9d3826d1b35e9078c1fae9c2ea96aa311cef750cc37fd88d5e4aed75ecb5c6db21f
6
+ metadata.gz: a7b44e5ceebc727be1a578a1210741fc5bbb9ec5e6d5a13feb36012bd35fb253173594ef0a35fb8448e1da697575ecdc97797473f7d5751db032a5065cce2bf8
7
+ data.tar.gz: c341817f928c9120662319a6ef9c1434d22b8872e685283b162ad4043efd9a0d1366eeeed4a58196e54708689833fa24af1b6b9e92dc59b8a75a98ad77810390
data/Gemfile CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem 'colorize'
5
6
  gem 'money'
6
7
 
7
8
  gemspec
data/README.md CHANGED
@@ -37,6 +37,7 @@ Running `hledger-forecast -h` shows the available options:
37
37
  -s, --start-date DATE The date to start generating from (yyyy-mm-dd)
38
38
  -e, --end-date DATE The date to start generating to (yyyy-mm-dd)
39
39
  --force Force an overwrite of the output file
40
+ --summarize Summarize the forecast file and output to the terminal
40
41
  -h, --help Show this message
41
42
  --version Show version
42
43
 
@@ -73,16 +74,17 @@ Let's examine what's going on in this config file:
73
74
 
74
75
  - Firstly, we're telling the app to create two monthly transactions and repeat them, forever, starting from March 2023. In this case, forever will be the `end_date` specified when running the app
75
76
  - If you ran the app with `hledger-forecast -s 2023-04-01` then no transactions would be generated for March as the start date is greater than the periodic start date
76
- - Notice we're also using [virtual postings](https://hledger.org/1.29/hledger.html#virtual-postings) (designated by the brackets) to be explicit to Hledger. This also makes it easy to filter them out with the `-R` or `--real` option in Hledger
77
+ - Notice we're also using [virtual postings](https://hledger.org/1.29/hledger.html#virtual-postings) (designated by the brackets). This makes it easy to filter them out with the `-R` or `--real` option in Hledger
77
78
  - We also have not specified a currency; the default (`USD`) will be used
78
79
 
79
80
  ### Extending the config file
80
81
 
81
82
  #### Periods
82
83
 
83
- If you'd like to add quarterly, yearly or one-off transactions, use the following keys:
84
+ If you'd like to add quarterly, half-yearly, yearly or one-off transactions, use the following keys:
84
85
 
85
86
  - `quarterly`
87
+ - `half-yearly`
86
88
  - `yearly`
87
89
  - `once`
88
90
 
@@ -112,6 +114,14 @@ settings:
112
114
  thousands_separator: true # Separate thousands with a comma?
113
115
  ```
114
116
 
117
+ ### Summarizing the config file
118
+
119
+ As your config file grows, it can be helpful to sum up the total amounts and output them in the CLI. This can be achieved by:
120
+
121
+ hledger-forecast -f forecast.yml --summarize
122
+
123
+ where `forecast.yml` is the config file to sum up.
124
+
115
125
  ## :brain: Rationale
116
126
 
117
127
  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!
data/bin/hledger-forecast CHANGED
@@ -9,4 +9,4 @@ rescue RuntimeError => e
9
9
  exit(1)
10
10
  end
11
11
 
12
- HledgerForecast::Command.run(options)
12
+ HledgerForecast::CLI.run(options)
data/example.yml CHANGED
@@ -17,6 +17,14 @@ quarterly:
17
17
  category: "[Income:Bonus]"
18
18
  description: Bonus
19
19
 
20
+ half-yearly:
21
+ - account: "[Assets:Bank]"
22
+ date: "2023-04-01"
23
+ transactions:
24
+ - amount: 500
25
+ category: "[Expenses:Holiday]"
26
+ description: Holiday
27
+
20
28
  yearly:
21
29
  - account: "[Assets:Bank]"
22
30
  date: "2023-04-01"
@@ -35,6 +43,6 @@ once:
35
43
 
36
44
  settings:
37
45
  currency: GBP
38
- show_symbol: false
46
+ show_symbol: true
39
47
  sign_before_symbol: true
40
- thousands_separator: false
48
+ thousands_separator: true
@@ -14,6 +14,7 @@ Gem::Specification.new do |s|
14
14
 
15
15
  s.add_dependency "highline", "~> 2.1.0"
16
16
  s.add_dependency "money", "~> 6.16.0"
17
+ s.add_dependency "colorize", "~> 0.8.1"
17
18
  s.add_development_dependency 'rspec', '~> 3.12'
18
19
 
19
20
  s.files = `git ls-files`.split("\n")
@@ -1,11 +1,13 @@
1
1
  module HledgerForecast
2
- class Command
2
+ class CLI
3
3
  def self.run(args)
4
4
  end_date = args[:end_date]
5
5
  start_date = args[:start_date]
6
6
  forecast = File.read(args[:forecast_file])
7
7
  transactions = args[:transactions_file] ? File.read(args[:transactions_file]) : nil
8
8
 
9
+ return HledgerForecast::Summarize.generate(forecast) if args[:summarize]
10
+
9
11
  puts "[Using default dates: #{start_date} to #{end_date}]" if args[:default_dates]
10
12
 
11
13
  transactions = Generator.create_journal_entries(transactions, forecast, start_date, end_date)
@@ -29,7 +29,7 @@ module HledgerForecast
29
29
  Money.from_cents(formatted_transaction['amount'].to_i * 100, @settings[:currency]).format(
30
30
  symbol: @settings[:show_symbol],
31
31
  sign_before_symbol: @settings[:sign_before_symbol],
32
- thousands_separator: @settings[:thousands_separator] ? ',' : nil
32
+ thousands_separator: @settings[:thousands_separator] ? ',' : nil,
33
33
  )
34
34
 
35
35
  formatted_transaction
@@ -48,6 +48,8 @@ module HledgerForecast
48
48
  date.day == start_date.day
49
49
  when 'quarterly'
50
50
  date.day == start_date.day && date.month % 3 == start_date.month % 3
51
+ when 'half-yearly'
52
+ date.day == start_date.day && (date.month - start_date.month) % 6 == 0
51
53
  when 'yearly'
52
54
  date.day == start_date.day && date.month == start_date.month
53
55
  when 'once'
@@ -81,6 +83,7 @@ module HledgerForecast
81
83
  while date <= end_date
82
84
  process_forecast(output, forecast_data, 'monthly', date)
83
85
  process_forecast(output, forecast_data, 'quarterly', date)
86
+ process_forecast(output, forecast_data, 'half-yearly', date)
84
87
  process_forecast(output, forecast_data, 'yearly', date)
85
88
  process_forecast(output, forecast_data, 'once', date)
86
89
 
@@ -32,6 +32,11 @@ module HledgerForecast
32
32
  options[:end_date] = a
33
33
  end
34
34
 
35
+ opts.on("--summarize",
36
+ "Summarize the forecast file and output to the terminal") do |a|
37
+ options[:summarize] = a
38
+ end
39
+
35
40
  opts.on("--force",
36
41
  "Force an overwrite of the output file") do |a|
37
42
  options[:force] = a
@@ -0,0 +1,68 @@
1
+ module HledgerForecast
2
+ # Summarise a forecast YAML file and output it to the CLI
3
+ class Summarize
4
+ def self.sum_transactions(forecast_data, period)
5
+ category_totals = Hash.new(0)
6
+ forecast_data[period]&.each do |entry|
7
+ entry['transactions'].each do |transaction|
8
+ category_totals[transaction['category']] += transaction['amount']
9
+ end
10
+ end
11
+ category_totals
12
+ end
13
+
14
+ def self.print_category_totals(period, category_totals, generator)
15
+ puts "#{period.capitalize}:"
16
+ period_total = 0
17
+
18
+ category_totals.each do |category, amount|
19
+ formatted_amount = generator.format_transaction({ 'amount' => amount })['amount']
20
+ formatted_amount = amount.to_i < 0 ? formatted_amount.red : formatted_amount.green
21
+ puts " #{category.ljust(40)}#{formatted_amount}"
22
+ period_total += amount
23
+ end
24
+
25
+ formatted_period_total = generator.format_transaction({ 'amount' => period_total })['amount']
26
+ formatted_period_total = period_total.to_i < 0 ? formatted_period_total.red : formatted_period_total.green
27
+ puts " TOTAL".ljust(42) + formatted_period_total
28
+ end
29
+
30
+ def self.sum_all_periods(forecast_data)
31
+ periods = %w[monthly quarterly half-yearly yearly once]
32
+ total = {}
33
+ grand_total = 0
34
+
35
+ periods.each do |period|
36
+ total[period] = sum_transactions(forecast_data, period)
37
+ grand_total += total[period]
38
+ end
39
+
40
+ total['total'] = grand_total
41
+ total
42
+ end
43
+
44
+ def self.generate(forecast)
45
+ forecast_data = YAML.safe_load(forecast)
46
+
47
+ category_totals_by_period = {}
48
+ %w[monthly quarterly half-yearly yearly once].each do |period|
49
+ category_totals_by_period[period] = sum_transactions(forecast_data, period)
50
+ end
51
+
52
+ grand_total = category_totals_by_period.values.map(&:values).flatten.sum
53
+
54
+ generator = HledgerForecast::Generator
55
+ generator.configure_settings(forecast_data)
56
+
57
+ puts
58
+ category_totals_by_period.each do |period, category_totals|
59
+ print_category_totals(period, category_totals, generator)
60
+ puts
61
+ end
62
+
63
+ formatted_grand_total = generator.format_transaction({ 'amount' => grand_total })['amount']
64
+ formatted_grand_total = grand_total.to_i < 0 ? formatted_grand_total.red : formatted_grand_total.green
65
+ puts "TOTAL:".ljust(42) + formatted_grand_total
66
+ end
67
+ end
68
+ end
@@ -1,3 +1,3 @@
1
1
  module HledgerForecast
2
- VERSION = "0.1.4"
2
+ VERSION = "0.1.6"
3
3
  end
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'colorize'
3
4
  require 'date'
4
5
  require 'highline'
5
6
  require 'money'
@@ -12,4 +13,5 @@ Money.rounding_mode = BigDecimal::ROUND_HALF_UP
12
13
  require_relative 'hledger_forecast/version'
13
14
  require_relative 'hledger_forecast/options'
14
15
  require_relative 'hledger_forecast/generator'
15
- require_relative 'hledger_forecast/command'
16
+ require_relative 'hledger_forecast/summarize'
17
+ require_relative 'hledger_forecast/CLI'
@@ -0,0 +1,13 @@
1
+ require_relative '../lib/hledger_forecast'
2
+
3
+ RSpec.describe 'generate' do
4
+ it 'generates a forecast with correct HALF-YEARLY transactions' do
5
+ transactions = File.read('spec/stubs/transactions.journal')
6
+ forecast = File.read('spec/stubs/half-yearly/forecast_half-yearly.yml')
7
+
8
+ generated_journal = HledgerForecast::Generator.create_journal_entries(transactions, forecast, '2023-03-01', '2024-04-30')
9
+
10
+ expected_output = File.read('spec/stubs/half-yearly/output_half-yearly.journal')
11
+ expect(generated_journal).to eq(expected_output)
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ settings:
2
+ currency: GBP
3
+
4
+ half-yearly:
5
+ - start: "2023-04-01"
6
+ account: "[Assets:Bank]"
7
+ transactions:
8
+ - description: Holiday
9
+ category: "[Expenses:Holiday]"
10
+ amount: 500
@@ -0,0 +1,20 @@
1
+ 2023-02-01 * Opening balance
2
+ Assets:Bank £1,000.00
3
+ Equity:Opening balance
4
+
5
+ 2023-02-05 * Mortgage payment
6
+ Expenses:Mortgage £1,500.00
7
+ Assets:Bank
8
+
9
+ 2023-04-01 * Holiday
10
+ [Expenses:Holiday] £500.00
11
+ [Assets:Bank]
12
+
13
+ 2023-10-01 * Holiday
14
+ [Expenses:Holiday] £500.00
15
+ [Assets:Bank]
16
+
17
+ 2024-04-01 * Holiday
18
+ [Expenses:Holiday] £500.00
19
+ [Assets:Bank]
20
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hledger-forecast
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oli Morris
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: 6.16.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: colorize
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.8.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.8.1
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rspec
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -70,14 +84,18 @@ files:
70
84
  - example.yml
71
85
  - hledger-forecast.gemspec
72
86
  - lib/hledger_forecast.rb
73
- - lib/hledger_forecast/command.rb
87
+ - lib/hledger_forecast/cli.rb
74
88
  - lib/hledger_forecast/generator.rb
75
89
  - lib/hledger_forecast/options.rb
90
+ - lib/hledger_forecast/summarize.rb
76
91
  - lib/hledger_forecast/version.rb
77
92
  - spec/command_spec.rb
93
+ - spec/half-yearly_spec.rb
78
94
  - spec/monthly_spec.rb
79
95
  - spec/once_spec.rb
80
96
  - spec/quarterly_spec.rb
97
+ - spec/stubs/half-yearly/forecast_half-yearly.yml
98
+ - spec/stubs/half-yearly/output_half-yearly.journal
81
99
  - spec/stubs/monthly/forecast_monthly.yml
82
100
  - spec/stubs/monthly/forecast_monthly_enddate.yml
83
101
  - spec/stubs/monthly/forecast_monthly_enddate_top.yml
@@ -119,9 +137,12 @@ specification_version: 4
119
137
  summary: Utility to generate forecasts in Hledger
120
138
  test_files:
121
139
  - spec/command_spec.rb
140
+ - spec/half-yearly_spec.rb
122
141
  - spec/monthly_spec.rb
123
142
  - spec/once_spec.rb
124
143
  - spec/quarterly_spec.rb
144
+ - spec/stubs/half-yearly/forecast_half-yearly.yml
145
+ - spec/stubs/half-yearly/output_half-yearly.journal
125
146
  - spec/stubs/monthly/forecast_monthly.yml
126
147
  - spec/stubs/monthly/forecast_monthly_enddate.yml
127
148
  - spec/stubs/monthly/forecast_monthly_enddate_top.yml