hledger-forecast 1.5.2 → 2.0.1
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 +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
| @@ -1,66 +1,41 @@ | |
| 1 1 | 
             
            require_relative '../lib/hledger_forecast'
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 4 | 
            -
               | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
              monthly:
         | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
                      to: "2023-06-01"
         | 
| 13 | 
            -
                      category: "Expenses:Mortgage"
         | 
| 14 | 
            -
                      amount: 2000.00
         | 
| 15 | 
            -
                    - description: Mortgage top up
         | 
| 16 | 
            -
                      to: "2023-06-01"
         | 
| 17 | 
            -
                      category: "Expenses:Mortgage Top Up"
         | 
| 18 | 
            -
                      amount: 200.00
         | 
| 19 | 
            -
                    - description: Food
         | 
| 20 | 
            -
                      category: "Expenses:Food"
         | 
| 21 | 
            -
                      amount: 100.00
         | 
| 22 | 
            -
                    - description: Party time
         | 
| 23 | 
            -
                      category: "Expenses:Going Out"
         | 
| 24 | 
            -
                      amount: 50.00
         | 
| 25 | 
            -
            YAML
         | 
| 26 | 
            -
             | 
| 27 | 
            -
            base_output = <<~JOURNAL
         | 
| 3 | 
            +
            config = <<~CSV
         | 
| 4 | 
            +
              type,frequency,account,from,to,description,category,amount,roll-up,summary_exclude,track
         | 
| 5 | 
            +
              monthly,,Assets:Bank,01/03/2023,01/06/2023,Mortgage,Expenses:Mortgage,2000.00,,,
         | 
| 6 | 
            +
              monthly,,Assets:Bank,01/03/2023,01/06/2023,Mortgage top up,Expenses:Mortgage,200.00,,,
         | 
| 7 | 
            +
              monthly,,Assets:Bank,01/03/2023,,Food,Expenses:Food,100.00,,,
         | 
| 8 | 
            +
              settings,currency,GBP,,,,,,,,
         | 
| 9 | 
            +
            CSV
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            output = <<~JOURNAL
         | 
| 28 12 | 
             
              ~ monthly from 2023-03-01 to 2023-06-01  * Mortgage, Mortgage top up
         | 
| 29 | 
            -
                  Expenses:Mortgage | 
| 30 | 
            -
                  Expenses:Mortgage | 
| 13 | 
            +
                  Expenses:Mortgage    £2,000.00   ;  Mortgage
         | 
| 14 | 
            +
                  Expenses:Mortgage    £200.00     ;  Mortgage top up
         | 
| 31 15 | 
             
                  Assets:Bank
         | 
| 32 16 |  | 
| 33 | 
            -
              ~ monthly from 2023-03-01  * Food | 
| 34 | 
            -
                  Expenses:Food | 
| 35 | 
            -
                  Expenses:Going Out          £50.00   ;  Party time
         | 
| 17 | 
            +
              ~ monthly from 2023-03-01  * Food
         | 
| 18 | 
            +
                  Expenses:Food        £100.00     ;  Food
         | 
| 36 19 | 
             
                  Assets:Bank
         | 
| 37 20 |  | 
| 38 21 | 
             
            JOURNAL
         | 
| 39 22 |  | 
| 40 | 
            -
            computed_config = <<~ | 
| 41 | 
            -
               | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 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
         | 
| 23 | 
            +
            computed_config = <<~CSV
         | 
| 24 | 
            +
              type,frequency,account,from,to,description,category,amount,roll-up,summary_exclude,track
         | 
| 25 | 
            +
              monthly,,Assets:Bank,01/03/2023,=12,Mortgage,Expenses:Mortgage,2000.00,,,
         | 
| 26 | 
            +
              settings,currency,GBP,,,,,,,,
         | 
| 27 | 
            +
            CSV
         | 
| 53 28 |  | 
| 54 29 | 
             
            computed_output = <<~JOURNAL
         | 
| 55 30 | 
             
              ~ monthly from 2023-03-01 to 2024-02-29  * Mortgage
         | 
| 56 | 
            -
                  Expenses:Mortgage    £2,000.00;  Mortgage
         | 
| 31 | 
            +
                  Expenses:Mortgage    £2,000.00   ;  Mortgage
         | 
| 57 32 | 
             
                  Assets:Bank
         | 
| 58 33 |  | 
| 59 34 | 
             
            JOURNAL
         | 
| 60 35 |  | 
| 61 36 | 
             
            RSpec.describe 'generate' do
         | 
| 62 37 | 
             
              it 'generates a forecast with correct MONTHLY transactions that have an end date' do
         | 
| 63 | 
            -
                expect(HledgerForecast::Generator.generate( | 
| 38 | 
            +
                expect(HledgerForecast::Generator.generate(config)).to eq(output)
         | 
| 64 39 | 
             
              end
         | 
| 65 40 |  | 
| 66 41 | 
             
              it 'generates a forecast with correct MONTHLY transactions that have a COMPUTED end date' do
         | 
    
        data/spec/monthly_spec.rb
    CHANGED
    
    | @@ -1,37 +1,20 @@ | |
| 1 1 | 
             
            require_relative '../lib/hledger_forecast'
         | 
| 2 2 |  | 
| 3 | 
            -
            config = <<~ | 
| 4 | 
            -
               | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
                      description: Mortgage
         | 
| 11 | 
            -
                    - amount: 100
         | 
| 12 | 
            -
                      category: "Expenses:Food"
         | 
| 13 | 
            -
                      description: Food
         | 
| 14 | 
            -
                - account: "Assets:Savings"
         | 
| 15 | 
            -
                  from: "2023-03-01"
         | 
| 16 | 
            -
                  transactions:
         | 
| 17 | 
            -
                    - amount: -1000
         | 
| 18 | 
            -
                      category: "Assets:Bank"
         | 
| 19 | 
            -
                      description: Savings
         | 
| 20 | 
            -
             | 
| 21 | 
            -
              settings:
         | 
| 22 | 
            -
                currency: GBP
         | 
| 23 | 
            -
            YAML
         | 
| 3 | 
            +
            config = <<~CSV
         | 
| 4 | 
            +
              type,frequency,account,from,to,description,category,amount,roll-up,summary_exclude,track
         | 
| 5 | 
            +
              monthly,,Assets:Bank,01/03/2023,,Bills,Expenses:Bills,175,,,
         | 
| 6 | 
            +
              monthly,,Assets:Bank,01/03/2023,,Food,Expenses:Food,500,,,
         | 
| 7 | 
            +
              monthly,,Assets:Bank,01/03/2023,,Savings,Assets:Savings,-1000,,,
         | 
| 8 | 
            +
              settings,currency,GBP,,,,,,,,
         | 
| 9 | 
            +
            CSV
         | 
| 24 10 |  | 
| 25 11 | 
             
            output = <<~JOURNAL
         | 
| 26 | 
            -
              ~ monthly from 2023-03-01  *  | 
| 27 | 
            -
                  Expenses: | 
| 28 | 
            -
                  Expenses:Food | 
| 12 | 
            +
              ~ monthly from 2023-03-01  * Bills, Food, Savings
         | 
| 13 | 
            +
                  Expenses:Bills    £175.00   ;  Bills
         | 
| 14 | 
            +
                  Expenses:Food     £500.00   ;  Food
         | 
| 15 | 
            +
                  Assets:Savings    £-1,000.00;  Savings
         | 
| 29 16 | 
             
                  Assets:Bank
         | 
| 30 17 |  | 
| 31 | 
            -
              ~ monthly from 2023-03-01  * Savings
         | 
| 32 | 
            -
                  Assets:Bank          £-1,000.00;  Savings
         | 
| 33 | 
            -
                  Assets:Savings
         | 
| 34 | 
            -
             | 
| 35 18 | 
             
            JOURNAL
         | 
| 36 19 |  | 
| 37 20 | 
             
            RSpec.describe 'generate' do
         | 
    
        data/spec/once_spec.rb
    CHANGED
    
    | @@ -1,21 +1,14 @@ | |
| 1 1 | 
             
            require_relative '../lib/hledger_forecast'
         | 
| 2 2 |  | 
| 3 | 
            -
            config = <<~ | 
| 4 | 
            -
               | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
                - from: "2023-07-01"
         | 
| 9 | 
            -
                  account: "Assets:Bank"
         | 
| 10 | 
            -
                  transactions:
         | 
| 11 | 
            -
                    - description: New Kitchen
         | 
| 12 | 
            -
                      category: "Expense:House"
         | 
| 13 | 
            -
                      amount: 5,000.00
         | 
| 14 | 
            -
            YAML
         | 
| 3 | 
            +
            config = <<~CSV
         | 
| 4 | 
            +
              type,frequency,account,from,to,description,category,amount,roll-up,summary_exclude,track
         | 
| 5 | 
            +
              once,,Assets:Bank,01/07/2023,,New Kitchen,Expenses:House,5000,,,
         | 
| 6 | 
            +
              settings,currency,GBP,,,,,,,,
         | 
| 7 | 
            +
            CSV
         | 
| 15 8 |  | 
| 16 9 | 
             
            output = <<~JOURNAL
         | 
| 17 10 | 
             
              ~ 2023-07-01  * New Kitchen
         | 
| 18 | 
            -
                   | 
| 11 | 
            +
                  Expenses:House    £5,000.00;  New Kitchen
         | 
| 19 12 | 
             
                  Assets:Bank
         | 
| 20 13 |  | 
| 21 14 | 
             
            JOURNAL
         | 
    
        data/spec/quarterly_spec.rb
    CHANGED
    
    | @@ -1,17 +1,10 @@ | |
| 1 1 | 
             
            require_relative '../lib/hledger_forecast'
         | 
| 2 2 |  | 
| 3 | 
            -
            config = <<~ | 
| 4 | 
            -
               | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
                - from: "2023-04-01"
         | 
| 9 | 
            -
                  account: "Assets:Bank"
         | 
| 10 | 
            -
                  transactions:
         | 
| 11 | 
            -
                    - description: Bonus
         | 
| 12 | 
            -
                      category: "Income:Bonus"
         | 
| 13 | 
            -
                      amount: -1,000.00
         | 
| 14 | 
            -
            YAML
         | 
| 3 | 
            +
            config = <<~CSV
         | 
| 4 | 
            +
              type,frequency,account,from,to,description,category,amount,roll-up,summary_exclude,track
         | 
| 5 | 
            +
              quarterly,,Assets:Bank,01/04/2023,,Bonus,Income:Bonus,-1000,,,
         | 
| 6 | 
            +
              settings,currency,GBP,,,,,,,,
         | 
| 7 | 
            +
            CSV
         | 
| 15 8 |  | 
| 16 9 | 
             
            output = <<~JOURNAL
         | 
| 17 10 | 
             
              ~ every 3 months from 2023-04-01  * Bonus
         | 
    
        data/spec/summarizer_spec.rb
    CHANGED
    
    | @@ -1,51 +1,20 @@ | |
| 1 1 | 
             
            require_relative '../lib/hledger_forecast'
         | 
| 2 2 |  | 
| 3 | 
            -
            config = <<~ | 
| 4 | 
            -
               | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
                    - amount: 100
         | 
| 13 | 
            -
                      category: "Expenses:Food"
         | 
| 14 | 
            -
                      description: Food
         | 
| 15 | 
            -
                - account: "Assets:Savings"
         | 
| 16 | 
            -
                  from: "2023-03-01"
         | 
| 17 | 
            -
                  transactions:
         | 
| 18 | 
            -
                    - amount: -1000
         | 
| 19 | 
            -
                      category: "Assets:Bank"
         | 
| 20 | 
            -
                      description: Savings
         | 
| 21 | 
            -
             | 
| 22 | 
            -
              custom:
         | 
| 23 | 
            -
                - account: "[Assets:Bank]"
         | 
| 24 | 
            -
                  from: "2023-05-01"
         | 
| 25 | 
            -
                  transactions:
         | 
| 26 | 
            -
                    - amount: 80
         | 
| 27 | 
            -
                      category: "[Expenses:Personal Care]"
         | 
| 28 | 
            -
                      description: Hair and beauty
         | 
| 29 | 
            -
                      frequency: "every 2 weeks"
         | 
| 30 | 
            -
                      roll-up: 26
         | 
| 31 | 
            -
                - account: "[Assets:Checking]"
         | 
| 32 | 
            -
                  from: "2023-05-01"
         | 
| 33 | 
            -
                  transactions:
         | 
| 34 | 
            -
                    - amount: 50
         | 
| 35 | 
            -
                      category: "[Expenses:Groceries]"
         | 
| 36 | 
            -
                      description: Gotta feed that stomach
         | 
| 37 | 
            -
                      frequency: "every 5 days"
         | 
| 38 | 
            -
                      roll-up: 73
         | 
| 39 | 
            -
             | 
| 40 | 
            -
              settings:
         | 
| 41 | 
            -
                currency: GBP
         | 
| 42 | 
            -
            YAML
         | 
| 3 | 
            +
            config = <<~CSV
         | 
| 4 | 
            +
              type,frequency,account,from,to,description,category,amount,roll-up,summary_exclude,track
         | 
| 5 | 
            +
              monthly,,Assets:Bank,01/03/2023,=24,Mortgage,Expenses:Mortgage,2000.55,,,
         | 
| 6 | 
            +
              monthly,,Assets:Bank,01/03/2023,,Food,Expenses:Food,100,,,
         | 
| 7 | 
            +
              monthly,,Assets:Savings,01/03/2023,,Savings,Assets:Bank,-1000,,,
         | 
| 8 | 
            +
              custom,every 2 weeks,[Assets:Bank],01/05/2023,,Hair and beauty,[Expenses:Personal Care],80,26,,
         | 
| 9 | 
            +
              custom,every 2 weeks,[Assets:Checking],01/05/2023,,Extra Food,[Expenses:Groceries],50,73,,
         | 
| 10 | 
            +
              settings,currency,GBP,,,,,,,,
         | 
| 11 | 
            +
            CSV
         | 
| 43 12 |  | 
| 44 13 | 
             
            RSpec.describe HledgerForecast::Summarizer do
         | 
| 45 14 | 
             
              let(:summarizer) { described_class.new }
         | 
| 46 15 |  | 
| 47 16 | 
             
              describe '#generate with roll_up' do
         | 
| 48 | 
            -
                let(:forecast) {  | 
| 17 | 
            +
                let(:forecast) { CSV.parse(config, headers: true) }
         | 
| 49 18 | 
             
                let(:cli_options) { { roll_up: 'monthly' } }
         | 
| 50 19 |  | 
| 51 20 | 
             
                before do
         | 
| @@ -69,7 +38,7 @@ RSpec.describe HledgerForecast::Summarizer do | |
| 69 38 | 
             
              end
         | 
| 70 39 |  | 
| 71 40 | 
             
              describe '#generate' do
         | 
| 72 | 
            -
                let(:forecast) {  | 
| 41 | 
            +
                let(:forecast) { CSV.parse(config, headers: true) }
         | 
| 73 42 | 
             
                let(:cli_options) { nil }
         | 
| 74 43 |  | 
| 75 44 | 
             
                before do
         | 
    
        data/spec/track_spec.rb
    CHANGED
    
    | @@ -4,31 +4,17 @@ current_month = Date.new(Date.today.year, Date.today.month, 1) | |
| 4 4 | 
             
            previous_month = current_month.prev_month
         | 
| 5 5 | 
             
            next_month = current_month.next_month
         | 
| 6 6 |  | 
| 7 | 
            -
            base_config = <<~ | 
| 8 | 
            -
               | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
                      description: Tax owed
         | 
| 15 | 
            -
                      track: true
         | 
| 16 | 
            -
                    - amount: 100
         | 
| 17 | 
            -
                      category: "Expenses:Food"
         | 
| 18 | 
            -
                      description: Food expenses
         | 
| 19 | 
            -
                    - amount: -1500
         | 
| 20 | 
            -
                      category: "Income:Salary"
         | 
| 21 | 
            -
                      description: Salary
         | 
| 22 | 
            -
                      to: "2023-08-01"
         | 
| 23 | 
            -
                      track: true
         | 
| 24 | 
            -
             | 
| 25 | 
            -
              settings:
         | 
| 26 | 
            -
                currency: GBP
         | 
| 27 | 
            -
            YAML
         | 
| 7 | 
            +
            base_config = <<~CSV
         | 
| 8 | 
            +
              type,frequency,account,from,to,description,category,amount,roll-up,summary_exclude,track
         | 
| 9 | 
            +
              once,,Assets:Bank,05/03/2023,,Tax owed,Expenses:Tax,3000,,,true
         | 
| 10 | 
            +
              once,,Assets:Bank,05/03/2023,,Food expenses,Expenses:Food,100,,,
         | 
| 11 | 
            +
              once,,Assets:Bank,05/03/2023,01/08/2023,Salary,Income:Salary,-1500,,,true
         | 
| 12 | 
            +
              settings,currency,GBP,,,,,,,,
         | 
| 13 | 
            +
            CSV
         | 
| 28 14 |  | 
| 29 15 | 
             
            base_output = <<~JOURNAL
         | 
| 30 16 | 
             
              ~ 2023-03-05  * Food expenses
         | 
| 31 | 
            -
                  Expenses:Food    £100.00 | 
| 17 | 
            +
                  Expenses:Food    £100.00   ;  Food expenses
         | 
| 32 18 | 
             
                  Assets:Bank
         | 
| 33 19 |  | 
| 34 20 | 
             
              ~ #{next_month}  * [TRACKED] Tax owed
         | 
| @@ -54,19 +40,11 @@ RSpec.describe 'Tracking transactions -' do | |
| 54 40 | 
             
              it 'writes a NON-FOUND entry for dates that are close to the current period' do
         | 
| 55 41 | 
             
                require 'tempfile'
         | 
| 56 42 |  | 
| 57 | 
            -
                forecast_config = <<~ | 
| 58 | 
            -
                   | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 62 | 
            -
                        - amount: 5000
         | 
| 63 | 
            -
                          category: "Expenses:House"
         | 
| 64 | 
            -
                          description: New kitchen
         | 
| 65 | 
            -
                          track: true
         | 
| 66 | 
            -
             | 
| 67 | 
            -
                  settings:
         | 
| 68 | 
            -
                    currency: GBP
         | 
| 69 | 
            -
                YAML
         | 
| 43 | 
            +
                forecast_config = <<~CSV
         | 
| 44 | 
            +
                  type,frequency,account,from,to,description,category,amount,roll-up,summary_exclude,track
         | 
| 45 | 
            +
                  once,,Assets:Bank,"#{previous_month}",,New kitchen,Expenses:House,5000,,,true
         | 
| 46 | 
            +
                  settings,currency,GBP,,,,,,,,
         | 
| 47 | 
            +
                CSV
         | 
| 70 48 |  | 
| 71 49 | 
             
                journal = <<~JOURNAL
         | 
| 72 50 | 
             
                  #{previous_month} * Opening balance
         | 
| @@ -104,19 +82,11 @@ RSpec.describe 'Tracking transactions -' do | |
| 104 82 | 
             
              end
         | 
| 105 83 |  | 
| 106 84 | 
             
              it 'treats a future tracked transaction as a regular transaction' do
         | 
| 107 | 
            -
                forecast_config = <<~ | 
| 108 | 
            -
                   | 
| 109 | 
            -
             | 
| 110 | 
            -
             | 
| 111 | 
            -
             | 
| 112 | 
            -
                        - amount: 100
         | 
| 113 | 
            -
                          category: "Expenses:Food"
         | 
| 114 | 
            -
                          description: Food expenses
         | 
| 115 | 
            -
                          track: true
         | 
| 116 | 
            -
             | 
| 117 | 
            -
                  settings:
         | 
| 118 | 
            -
                    currency: GBP
         | 
| 119 | 
            -
                YAML
         | 
| 85 | 
            +
                forecast_config = <<~CSV
         | 
| 86 | 
            +
                  type,frequency,account,from,to,description,category,amount,roll-up,summary_exclude,track
         | 
| 87 | 
            +
                  monthly,,Assets:Bank,"#{next_month}",,Food expenses,Expenses:Food,100,,,true
         | 
| 88 | 
            +
                  settings,currency,GBP,,,,,,,,
         | 
| 89 | 
            +
                CSV
         | 
| 120 90 |  | 
| 121 91 | 
             
                options = {}
         | 
| 122 92 | 
             
                options[:transaction_file] = 'spec/stubs/transactions_not_found.journal'
         | 
| @@ -125,7 +95,7 @@ RSpec.describe 'Tracking transactions -' do | |
| 125 95 |  | 
| 126 96 | 
             
                output = <<~JOURNAL
         | 
| 127 97 | 
             
                  ~ monthly from #{next_month}  * Food expenses
         | 
| 128 | 
            -
                      Expenses:Food    £100.00;  Food expenses
         | 
| 98 | 
            +
                      Expenses:Food    £100.00 ;  Food expenses
         | 
| 129 99 | 
             
                      Assets:Bank
         | 
| 130 100 |  | 
| 131 101 | 
             
                JOURNAL
         | 
    
        data/spec/verbose_output_spec.rb
    CHANGED
    
    | @@ -2,15 +2,15 @@ require_relative '../lib/hledger_forecast' | |
| 2 2 |  | 
| 3 3 | 
             
            output = <<~JOURNAL
         | 
| 4 4 | 
             
              ~ monthly from 2023-03-01  * Mortgage
         | 
| 5 | 
            -
                  Expenses:Mortgage    £2,000.55;  Mortgage
         | 
| 5 | 
            +
                  Expenses:Mortgage    £2,000.55   ;  Mortgage
         | 
| 6 6 | 
             
                  Assets:Bank
         | 
| 7 7 |  | 
| 8 8 | 
             
              ~ monthly from 2023-03-01  * Food
         | 
| 9 | 
            -
                  Expenses:Food        £100.00 | 
| 9 | 
            +
                  Expenses:Food        £100.00     ;  Food
         | 
| 10 10 | 
             
                  Assets:Bank
         | 
| 11 11 |  | 
| 12 12 | 
             
              ~ monthly from 2023-03-01  * Savings
         | 
| 13 | 
            -
                  Assets:Bank          £-1,000.00;  Savings
         | 
| 13 | 
            +
                  Assets:Bank          £-1,000.00  ;  Savings
         | 
| 14 14 | 
             
                  Assets:Savings
         | 
| 15 15 |  | 
| 16 16 | 
             
            JOURNAL
         | 
    
        data/spec/yearly_spec.rb
    CHANGED
    
    | @@ -1,17 +1,10 @@ | |
| 1 1 | 
             
            require_relative '../lib/hledger_forecast'
         | 
| 2 2 |  | 
| 3 | 
            -
            config = <<~ | 
| 4 | 
            -
               | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
                - account: "Assets:Bank"
         | 
| 9 | 
            -
                  from: "2023-04-01"
         | 
| 10 | 
            -
                  transactions:
         | 
| 11 | 
            -
                    - description: Bonus
         | 
| 12 | 
            -
                      category: "Income:Bonus"
         | 
| 13 | 
            -
                      amount: -3,000.00
         | 
| 14 | 
            -
            YAML
         | 
| 3 | 
            +
            config = <<~CSV
         | 
| 4 | 
            +
              type,frequency,account,from,to,description,category,amount,roll-up,summary_exclude,track
         | 
| 5 | 
            +
              yearly,,Assets:Bank,01/04/2023,,Bonus,Income:Bonus,-3000,,,
         | 
| 6 | 
            +
              settings,currency,GBP,,,,,,,,
         | 
| 7 | 
            +
            CSV
         | 
| 15 8 |  | 
| 16 9 | 
             
            output = <<~JOURNAL
         | 
| 17 10 | 
             
              ~ yearly from 2023-04-01  * Bonus
         | 
    
        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:  | 
| 4 | 
            +
              version: 2.0.1
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Oli Morris
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 11 | 
            +
            date: 2024-02-03 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: colorize
         | 
| @@ -94,7 +94,7 @@ dependencies: | |
| 94 94 | 
             
                - - "~>"
         | 
| 95 95 | 
             
                  - !ruby/object:Gem::Version
         | 
| 96 96 | 
             
                    version: '3.12'
         | 
| 97 | 
            -
            description: Use a CSV  | 
| 97 | 
            +
            description: Use a CSV file for improved forecasting with hledger
         | 
| 98 98 | 
             
            email: olimorris@users.noreply.github.com
         | 
| 99 99 | 
             
            executables:
         | 
| 100 100 | 
             
            - hledger-forecast
         | 
| @@ -111,13 +111,11 @@ files: | |
| 111 111 | 
             
            - bin/hledger-forecast
         | 
| 112 112 | 
             
            - example.csv
         | 
| 113 113 | 
             
            - example.journal
         | 
| 114 | 
            -
            - example.yml
         | 
| 115 114 | 
             
            - hledger-forecast.gemspec
         | 
| 116 115 | 
             
            - lib/hledger_forecast.rb
         | 
| 117 116 | 
             
            - lib/hledger_forecast/calculator.rb
         | 
| 118 117 | 
             
            - lib/hledger_forecast/cli.rb
         | 
| 119 118 | 
             
            - lib/hledger_forecast/comparator.rb
         | 
| 120 | 
            -
            - lib/hledger_forecast/csv_parser.rb
         | 
| 121 119 | 
             
            - lib/hledger_forecast/formatter.rb
         | 
| 122 120 | 
             
            - lib/hledger_forecast/generator.rb
         | 
| 123 121 | 
             
            - lib/hledger_forecast/settings.rb
         | 
| @@ -126,22 +124,19 @@ files: | |
| 126 124 | 
             
            - lib/hledger_forecast/transactions/default.rb
         | 
| 127 125 | 
             
            - lib/hledger_forecast/transactions/modifiers.rb
         | 
| 128 126 | 
             
            - lib/hledger_forecast/transactions/trackers.rb
         | 
| 127 | 
            +
            - lib/hledger_forecast/utilities.rb
         | 
| 129 128 | 
             
            - lib/hledger_forecast/version.rb
         | 
| 130 129 | 
             
            - spec/cli_spec.rb
         | 
| 131 130 | 
             
            - spec/compare_spec.rb
         | 
| 132 131 | 
             
            - spec/computed_amounts_spec.rb
         | 
| 133 | 
            -
            - spec/csv_and_yml_comparison_spec.rb
         | 
| 134 | 
            -
            - spec/csv_parser_spec.rb
         | 
| 135 132 | 
             
            - spec/custom_spec.rb
         | 
| 136 133 | 
             
            - spec/half-yearly_spec.rb
         | 
| 137 | 
            -
            - spec/modifier_spec.rb
         | 
| 138 134 | 
             
            - spec/monthly_end_date_spec.rb
         | 
| 139 135 | 
             
            - spec/monthly_end_date_transaction_spec.rb
         | 
| 140 136 | 
             
            - spec/monthly_spec.rb
         | 
| 141 137 | 
             
            - spec/once_spec.rb
         | 
| 142 138 | 
             
            - spec/quarterly_spec.rb
         | 
| 143 139 | 
             
            - spec/stubs/forecast.csv
         | 
| 144 | 
            -
            - spec/stubs/forecast.yml
         | 
| 145 140 | 
             
            - spec/stubs/output1.csv
         | 
| 146 141 | 
             
            - spec/stubs/output2.csv
         | 
| 147 142 | 
             
            - spec/stubs/transactions_found.journal
         | 
| @@ -178,18 +173,14 @@ test_files: | |
| 178 173 | 
             
            - spec/cli_spec.rb
         | 
| 179 174 | 
             
            - spec/compare_spec.rb
         | 
| 180 175 | 
             
            - spec/computed_amounts_spec.rb
         | 
| 181 | 
            -
            - spec/csv_and_yml_comparison_spec.rb
         | 
| 182 | 
            -
            - spec/csv_parser_spec.rb
         | 
| 183 176 | 
             
            - spec/custom_spec.rb
         | 
| 184 177 | 
             
            - spec/half-yearly_spec.rb
         | 
| 185 | 
            -
            - spec/modifier_spec.rb
         | 
| 186 178 | 
             
            - spec/monthly_end_date_spec.rb
         | 
| 187 179 | 
             
            - spec/monthly_end_date_transaction_spec.rb
         | 
| 188 180 | 
             
            - spec/monthly_spec.rb
         | 
| 189 181 | 
             
            - spec/once_spec.rb
         | 
| 190 182 | 
             
            - spec/quarterly_spec.rb
         | 
| 191 183 | 
             
            - spec/stubs/forecast.csv
         | 
| 192 | 
            -
            - spec/stubs/forecast.yml
         | 
| 193 184 | 
             
            - spec/stubs/output1.csv
         | 
| 194 185 | 
             
            - spec/stubs/output2.csv
         | 
| 195 186 | 
             
            - spec/stubs/transactions_found.journal
         | 
    
        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
         |