loan_creator 0.2.3 → 0.5.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.
- checksums.yaml +4 -4
- data/CapSens_Loan.xlsx +0 -0
- data/README.md +43 -1
- data/lib/loan_creator/bullet.rb +1 -0
- data/lib/loan_creator/common.rb +44 -6
- data/lib/loan_creator/excel_formulas.rb +4 -0
- data/lib/loan_creator/in_fine.rb +1 -3
- data/lib/loan_creator/linear.rb +10 -2
- data/lib/loan_creator/standard.rb +8 -0
- data/lib/loan_creator/term.rb +4 -4
- data/lib/loan_creator/timetable.rb +39 -31
- data/lib/loan_creator/version.rb +1 -1
- metadata +2 -1
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: ce94717f0c667263653597ea2037844157e6cebe
         | 
| 4 | 
            +
              data.tar.gz: e498fe9069ca0ff9c3d765083a182f28ddc3ca22
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: da8108111a04280719eba3143444bd2ceac35abaade6521c2e9a5a3297266037c7d8e194156c3a373602fe766bbce49c23ebe515a2db1b64e1a35ac67a4aff06
         | 
| 7 | 
            +
              data.tar.gz: 5e49dd7114a25fc67e9230ea0d6120b7a12bb83b6b6c50d28eecbfb7c92cc7bbd68da4ca26d0bf7dffe0b7b1fc2a7ec9acbbbb9369bf2cdfb1eb6837625dd2be
         | 
    
        data/CapSens_Loan.xlsx
    ADDED
    
    | Binary file | 
    
        data/README.md
    CHANGED
    
    | @@ -46,6 +46,7 @@ Each instance of one of the previous classes has the following attributes: | |
| 46 46 | 
             
                :starts_at
         | 
| 47 47 | 
             
                :duration_in_periods
         | 
| 48 48 | 
             
                :deferred_in_periods (default to zero)
         | 
| 49 | 
            +
                :interests_start_date (optional)
         | 
| 49 50 | 
             
            ```
         | 
| 50 51 |  | 
| 51 52 | 
             
            There is also a `LoanCreator::Timetable` class dedicated to record the data of the loans' terms. Each instance of `LoanCreator::Timetable` represents an array of `LoanCreator::Term` records, each having the following attributes:
         | 
| @@ -55,7 +56,7 @@ There is also a `LoanCreator::Timetable` class dedicated to record the data of t | |
| 55 56 | 
             
                  :index
         | 
| 56 57 |  | 
| 57 58 | 
             
                  # Term date
         | 
| 58 | 
            -
                  : | 
| 59 | 
            +
                  :due_on
         | 
| 59 60 |  | 
| 60 61 | 
             
                  # Remaining due capital at the beginning of the term
         | 
| 61 62 | 
             
                  :crd_beginning_of_period
         | 
| @@ -99,8 +100,29 @@ support all those differences. | |
| 99 100 | 
             
            `.borrower_timetable(*lenders_timetables)` (class method) intends to sum each attribute of each provided `lender_timetable` on each term and thus to provide an ascending order array of `LoanCreator::Term`. It should be used for the borrower of a loan, once all lenders and their lending amounts
         | 
| 100 101 | 
             
            are known. It makes the borrower support all financial rounding differences.
         | 
| 101 102 |  | 
| 103 | 
            +
            ## Example
         | 
| 104 | 
            +
             | 
| 105 | 
            +
            ```ruby
         | 
| 106 | 
            +
            loan_creator = LoanCreator::Standard.new(
         | 
| 107 | 
            +
              period: :year,
         | 
| 108 | 
            +
              amount: 42_000,
         | 
| 109 | 
            +
              annual_interests_rate: 4,
         | 
| 110 | 
            +
              starts_on: '2019-03-01',
         | 
| 111 | 
            +
              duration_in_periods: 5,
         | 
| 112 | 
            +
              deferred_in_periods: 1,
         | 
| 113 | 
            +
              interests_start_date: '2019-02-10'
         | 
| 114 | 
            +
            )
         | 
| 115 | 
            +
            loan_creator.lender_timetable
         | 
| 116 | 
            +
            # => #<LoanCreator::Timetable:0x0000000003198bd0 @terms=[...] ...>
         | 
| 117 | 
            +
            loan_creator.lender_timetable.terms.first
         | 
| 118 | 
            +
            # => #<LoanCreator::Term:0x00000000030f1a88 @crd_beginning_of_period=0.42e5,
         | 
| 119 | 
            +
            # [...] @period_amount_to_pay=0.8745e2, @index=0, @due_on=Sun, 10 Feb 2019>
         | 
| 120 | 
            +
            ````
         | 
| 121 | 
            +
             | 
| 102 122 | 
             
            ## Explanation
         | 
| 103 123 |  | 
| 124 | 
            +
            ### Classes
         | 
| 125 | 
            +
             | 
| 104 126 | 
             
            `Standard` loan generates terms with constant payments.
         | 
| 105 127 |  | 
| 106 128 | 
             
            `Linear` loan generates terms with constant capital share payment.
         | 
| @@ -117,6 +139,26 @@ Capital share shall be repaid in full and all interests paid at loan's end. | |
| 117 139 |  | 
| 118 140 | 
             
            There is no deferred time for `InFine` and `Bullet` loans as it would be equivalent to increasing loan's duration.
         | 
| 119 141 |  | 
| 142 | 
            +
            ### Attributes
         | 
| 143 | 
            +
             | 
| 144 | 
            +
            `period`: A `Symbol`. `:month`, `:quarter`, `:semester` or `:year`.
         | 
| 145 | 
            +
             | 
| 146 | 
            +
            `duration_in_periods`: An `Integer`.
         | 
| 147 | 
            +
             | 
| 148 | 
            +
            `amount`: Any number that can be converted to `BigDecimal`.
         | 
| 149 | 
            +
             | 
| 150 | 
            +
            `annual_interests_rate`: In percentage. Any number that can be converted to `BigDecimal`.
         | 
| 151 | 
            +
             | 
| 152 | 
            +
            `starts_at`: A `Date`, or a `String` that can be parsed.
         | 
| 153 | 
            +
             | 
| 154 | 
            +
            `deferred_in_periods`: Optional. An `Integer`, smaller than `duration_in_periods`. Number of periods during which no
         | 
| 155 | 
            +
            capital is refunded, only interest. Only relevant for `Standard` and `Linear` loans.
         | 
| 156 | 
            +
             | 
| 157 | 
            +
            `interests_start_date`: Optional. To be used when the loan starts before the first full term date. This then compute an
         | 
| 158 | 
            +
            additional term with only interests for the time difference.  
         | 
| 159 | 
            +
            For example, with a `start_at` in january 2020 and a `interests_start_date` in october 2019, the timetable will include a
         | 
| 160 | 
            +
            first term corresponding to 3 months of interests.
         | 
| 161 | 
            +
             | 
| 120 162 | 
             
            ## Development
         | 
| 121 163 |  | 
| 122 164 | 
             
            After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
         | 
    
        data/lib/loan_creator/bullet.rb
    CHANGED
    
    | @@ -2,6 +2,7 @@ module LoanCreator | |
| 2 2 | 
             
              class Bullet < LoanCreator::Common
         | 
| 3 3 | 
             
                def lender_timetable
         | 
| 4 4 | 
             
                  raise ArgumentError.new(:deferred_in_periods) unless deferred_in_periods == 0
         | 
| 5 | 
            +
                  raise ArgumentError.new(:interests_start_date) unless interests_start_date.nil?
         | 
| 5 6 | 
             
                  timetable = new_timetable
         | 
| 6 7 | 
             
                  reset_current_term
         | 
| 7 8 | 
             
                  @crd_beginning_of_period = amount
         | 
    
        data/lib/loan_creator/common.rb
    CHANGED
    
    | @@ -19,7 +19,8 @@ module LoanCreator | |
| 19 19 |  | 
| 20 20 | 
             
                OPTIONAL_ATTRIBUTES = {
         | 
| 21 21 | 
             
                  # attribute: default_value
         | 
| 22 | 
            -
                  deferred_in_periods: 0
         | 
| 22 | 
            +
                  deferred_in_periods: 0,
         | 
| 23 | 
            +
                  interests_start_date: nil,
         | 
| 23 24 | 
             
                }.freeze
         | 
| 24 25 |  | 
| 25 26 | 
             
                attr_reader *REQUIRED_ATTRIBUTES
         | 
| @@ -48,7 +49,7 @@ module LoanCreator | |
| 48 49 | 
             
                end
         | 
| 49 50 |  | 
| 50 51 | 
             
                def self.bigd(value)
         | 
| 51 | 
            -
                  BigDecimal | 
| 52 | 
            +
                  BigDecimal(value, BIG_DECIMAL_DIGITS)
         | 
| 52 53 | 
             
                end
         | 
| 53 54 |  | 
| 54 55 | 
             
                def bigd(value)
         | 
| @@ -65,7 +66,8 @@ module LoanCreator | |
| 65 66 | 
             
                  @options[:period] = @options[:period].to_sym
         | 
| 66 67 | 
             
                  @options[:amount] = bigd(@options[:amount])
         | 
| 67 68 | 
             
                  @options[:annual_interests_rate] = bigd(@options[:annual_interests_rate])
         | 
| 68 | 
            -
                  @options[:starts_on] = @options[:starts_on] | 
| 69 | 
            +
                  @options[:starts_on] = Date.parse(@options[:starts_on]) if @options[:starts_on].is_a?(String)
         | 
| 70 | 
            +
                  @options[:interests_start_date] = Date.parse(@options[:interests_start_date]) if @options[:interests_start_date].is_a?(String)
         | 
| 69 71 | 
             
                end
         | 
| 70 72 |  | 
| 71 73 | 
             
                def set_attributes
         | 
| @@ -83,7 +85,7 @@ module LoanCreator | |
| 83 85 | 
             
                  validate(:period) { |v| PERIODS_IN_MONTHS.keys.include?(v) }
         | 
| 84 86 | 
             
                  validate(:amount) { |v| v.is_a?(BigDecimal) && v > 0 }
         | 
| 85 87 | 
             
                  validate(:annual_interests_rate) { |v| v.is_a?(BigDecimal) && v >= 0 }
         | 
| 86 | 
            -
                  validate(:starts_on) { |v|  | 
| 88 | 
            +
                  validate(:starts_on) { |v| v.is_a?(Date) }
         | 
| 87 89 | 
             
                  validate(:duration_in_periods) { |v| v.is_a?(Integer) && v > 0 }
         | 
| 88 90 | 
             
                  validate(:deferred_in_periods) { |v| v.is_a?(Integer) && v >= 0 && v < duration_in_periods }
         | 
| 89 91 | 
             
                end
         | 
| @@ -100,6 +102,8 @@ module LoanCreator | |
| 100 102 | 
             
                  @total_paid_capital_end_of_period = bigd('0')
         | 
| 101 103 | 
             
                  @total_paid_interests_end_of_period = bigd('0')
         | 
| 102 104 | 
             
                  @period_amount_to_pay = bigd('0')
         | 
| 105 | 
            +
                  @due_on = nil
         | 
| 106 | 
            +
                  @index = nil
         | 
| 103 107 | 
             
                end
         | 
| 104 108 |  | 
| 105 109 | 
             
                def current_term
         | 
| @@ -114,12 +118,46 @@ module LoanCreator | |
| 114 118 | 
             
                    period_capital: @period_capital,
         | 
| 115 119 | 
             
                    total_paid_capital_end_of_period: @total_paid_capital_end_of_period,
         | 
| 116 120 | 
             
                    total_paid_interests_end_of_period: @total_paid_interests_end_of_period,
         | 
| 117 | 
            -
                    period_amount_to_pay: @period_amount_to_pay
         | 
| 121 | 
            +
                    period_amount_to_pay: @period_amount_to_pay,
         | 
| 122 | 
            +
                    due_on: @due_on,
         | 
| 123 | 
            +
                    index: @index
         | 
| 118 124 | 
             
                  )
         | 
| 119 125 | 
             
                end
         | 
| 120 126 |  | 
| 121 127 | 
             
                def new_timetable
         | 
| 122 | 
            -
                  LoanCreator::Timetable.new(starts_on: starts_on, period: period)
         | 
| 128 | 
            +
                  LoanCreator::Timetable.new(starts_on: starts_on, period: period, interests_start_date: interests_start_date)
         | 
| 129 | 
            +
                end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                def compute_term_zero
         | 
| 132 | 
            +
                  @crd_beginning_of_period = @crd_end_of_period
         | 
| 133 | 
            +
                  @period_theoric_interests = term_zero_interests
         | 
| 134 | 
            +
                  @delta_interests = @period_theoric_interests - @period_theoric_interests.round(2)
         | 
| 135 | 
            +
                  @accrued_delta_interests += @delta_interests
         | 
| 136 | 
            +
                  @period_interests = @period_theoric_interests.round(2)
         | 
| 137 | 
            +
                  @total_paid_interests_end_of_period += @period_interests
         | 
| 138 | 
            +
                  @period_amount_to_pay = @period_interests
         | 
| 139 | 
            +
                  @index = 0
         | 
| 140 | 
            +
                end
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                def term_zero_interests
         | 
| 143 | 
            +
                  @crd_beginning_of_period * term_zero_interests_rate
         | 
| 144 | 
            +
                end
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                def term_zero_interests_rate
         | 
| 147 | 
            +
                  term_zero_interests_rate_percentage = (annual_interests_rate * term_zero_duration).div(365, BIG_DECIMAL_DIGITS)
         | 
| 148 | 
            +
                  term_zero_interests_rate_percentage.div(100, BIG_DECIMAL_DIGITS)
         | 
| 149 | 
            +
                end
         | 
| 150 | 
            +
             | 
| 151 | 
            +
                def term_zero_duration
         | 
| 152 | 
            +
                  (term_zero_date - interests_start_date).to_i
         | 
| 153 | 
            +
                end
         | 
| 154 | 
            +
             | 
| 155 | 
            +
                def term_zero_date
         | 
| 156 | 
            +
                  starts_on.advance(months: -PERIODS_IN_MONTHS.fetch(@period))
         | 
| 157 | 
            +
                end
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                def term_zero?
         | 
| 160 | 
            +
                  interests_start_date && interests_start_date < term_zero_date
         | 
| 123 161 | 
             
                end
         | 
| 124 162 | 
             
              end
         | 
| 125 163 | 
             
            end
         | 
| @@ -1,12 +1,16 @@ | |
| 1 1 | 
             
            # Source: https://gist.github.com/mattetti/1015948
         | 
| 2 2 |  | 
| 3 3 | 
             
            module LoanCreator::ExcelFormulas
         | 
| 4 | 
            +
              # Returns the interest payment
         | 
| 5 | 
            +
              # for a given period for an investment based on periodic, constant payments and a constant interest rate.
         | 
| 4 6 | 
             
              def ipmt(rate, per, nper, pv, fv=0, type=0)
         | 
| 5 7 | 
             
                p = _pmt(rate, nper, pv, fv, 0);
         | 
| 6 8 | 
             
                ip = -(pv * _pow1p(rate, per - 1) * rate + p * _pow1pm1(rate, per - 1))
         | 
| 7 9 | 
             
                (type == 0) ? ip : ip / (1 + rate)
         | 
| 8 10 | 
             
              end
         | 
| 9 11 |  | 
| 12 | 
            +
              # Returns the payment on the principal
         | 
| 13 | 
            +
              # for a given period for an investment based on periodic, constant payments and a constant interest rate.
         | 
| 10 14 | 
             
              def ppmt(rate, per, nper, pv, fv=0, type=0)
         | 
| 11 15 | 
             
                p = _pmt(rate, nper, pv, fv, type)
         | 
| 12 16 | 
             
                ip = ipmt(rate, per, nper, pv, fv, type)
         | 
    
        data/lib/loan_creator/in_fine.rb
    CHANGED
    
    | @@ -3,9 +3,7 @@ module LoanCreator | |
| 3 3 | 
             
                # InFine is the same as a Linear loan with (duration - 1) deferred periods.
         | 
| 4 4 | 
             
                # Thus we're generating a Linear loan instead of rewriting already existing code.
         | 
| 5 5 | 
             
                def lender_timetable
         | 
| 6 | 
            -
                   | 
| 7 | 
            -
                  options = { deferred_in_periods: duration_in_periods - 1 }
         | 
| 8 | 
            -
                  options = REQUIRED_ATTRIBUTES.each_with_object(options) { |k,h| h[k] = send(k) }
         | 
| 6 | 
            +
                  options = @options.merge(deferred_in_periods: duration_in_periods - 1)
         | 
| 9 7 | 
             
                  LoanCreator::Linear.new(options).lender_timetable
         | 
| 10 8 | 
             
                end
         | 
| 11 9 | 
             
              end
         | 
    
        data/lib/loan_creator/linear.rb
    CHANGED
    
    | @@ -5,10 +5,16 @@ module LoanCreator | |
| 5 5 | 
             
                  timetable = new_timetable
         | 
| 6 6 | 
             
                  reset_current_term
         | 
| 7 7 | 
             
                  @crd_end_of_period = amount
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  if term_zero?
         | 
| 10 | 
            +
                    compute_term_zero
         | 
| 11 | 
            +
                    timetable << current_term
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 8 14 | 
             
                  duration_in_periods.times do |idx|
         | 
| 9 15 | 
             
                    @last_period = last_period?(idx)
         | 
| 10 16 | 
             
                    @deferred_period = idx < deferred_in_periods
         | 
| 11 | 
            -
                    compute_current_term
         | 
| 17 | 
            +
                    compute_current_term(idx)
         | 
| 12 18 | 
             
                    timetable << current_term
         | 
| 13 19 | 
             
                  end
         | 
| 14 20 | 
             
                  timetable
         | 
| @@ -20,7 +26,7 @@ module LoanCreator | |
| 20 26 | 
             
                  idx == (duration_in_periods - 1)
         | 
| 21 27 | 
             
                end
         | 
| 22 28 |  | 
| 23 | 
            -
                def compute_current_term
         | 
| 29 | 
            +
                def compute_current_term(idx)
         | 
| 24 30 | 
             
                  # Reminder: CRD beginning of period = CRD end of period **of previous period**
         | 
| 25 31 | 
             
                  @crd_beginning_of_period = @crd_end_of_period
         | 
| 26 32 | 
             
                  @period_theoric_interests = @crd_beginning_of_period * periodic_interests_rate
         | 
| @@ -42,6 +48,8 @@ module LoanCreator | |
| 42 48 | 
             
                  @total_paid_interests_end_of_period += @period_interests
         | 
| 43 49 | 
             
                  @period_amount_to_pay = @period_interests + @period_capital
         | 
| 44 50 | 
             
                  @crd_end_of_period -= @period_capital
         | 
| 51 | 
            +
                  @due_on = nil
         | 
| 52 | 
            +
                  @index = idx + 1
         | 
| 45 53 | 
             
                end
         | 
| 46 54 |  | 
| 47 55 | 
             
                def period_capital
         | 
| @@ -6,6 +6,12 @@ module LoanCreator | |
| 6 6 | 
             
                  timetable = new_timetable
         | 
| 7 7 | 
             
                  reset_current_term
         | 
| 8 8 | 
             
                  @crd_end_of_period = amount
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  if term_zero?
         | 
| 11 | 
            +
                    compute_term_zero
         | 
| 12 | 
            +
                    timetable << current_term
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 9 15 | 
             
                  duration_in_periods.times do |idx|
         | 
| 10 16 | 
             
                    @last_period = last_period?(idx)
         | 
| 11 17 | 
             
                    @deferred_period = idx < deferred_in_periods
         | 
| @@ -42,6 +48,8 @@ module LoanCreator | |
| 42 48 | 
             
                  @total_paid_interests_end_of_period += @period_interests
         | 
| 43 49 | 
             
                  @period_amount_to_pay = @period_interests + @period_capital
         | 
| 44 50 | 
             
                  @crd_end_of_period -= @period_capital
         | 
| 51 | 
            +
                  @due_on = nil
         | 
| 52 | 
            +
                  @index = idx + 1
         | 
| 45 53 | 
             
                end
         | 
| 46 54 |  | 
| 47 55 | 
             
                def period_theoric_interests(idx)
         | 
    
        data/lib/loan_creator/term.rb
    CHANGED
    
    | @@ -36,7 +36,7 @@ module LoanCreator | |
| 36 36 | 
             
                  :period_amount_to_pay
         | 
| 37 37 | 
             
                ].freeze
         | 
| 38 38 |  | 
| 39 | 
            -
                 | 
| 39 | 
            +
                OPTIONAL_ARGUMENTS = [
         | 
| 40 40 | 
             
                  # Term number (starts at 1)
         | 
| 41 41 | 
             
                  # This value is to be set by Timetable
         | 
| 42 42 | 
             
                  :index,
         | 
| @@ -44,15 +44,15 @@ module LoanCreator | |
| 44 44 | 
             
                  # Term date
         | 
| 45 45 | 
             
                  # This value is to be set by Timetable
         | 
| 46 46 | 
             
                  :due_on,
         | 
| 47 | 
            +
                ]
         | 
| 47 48 |  | 
| 48 | 
            -
             | 
| 49 | 
            -
                  *ARGUMENTS
         | 
| 50 | 
            -
                ].freeze
         | 
| 49 | 
            +
                ATTRIBUTES = (ARGUMENTS + OPTIONAL_ARGUMENTS).freeze
         | 
| 51 50 |  | 
| 52 51 | 
             
                attr_accessor *ATTRIBUTES
         | 
| 53 52 |  | 
| 54 53 | 
             
                def initialize(**options)
         | 
| 55 54 | 
             
                  ARGUMENTS.each { |k| instance_variable_set(:"@#{k}", options.fetch(k)) }
         | 
| 55 | 
            +
                  OPTIONAL_ARGUMENTS.each { |k| instance_variable_set(:"@#{k}", options.fetch(k, nil)) }
         | 
| 56 56 | 
             
                end
         | 
| 57 57 |  | 
| 58 58 | 
             
                def to_csv
         | 
| @@ -3,39 +3,34 @@ module LoanCreator | |
| 3 3 | 
             
              class Timetable
         | 
| 4 4 | 
             
                # Used to calculate next term's date (see ActiveSupport#advance)
         | 
| 5 5 | 
             
                PERIODS = {
         | 
| 6 | 
            -
                  month: | 
| 7 | 
            -
                  quarter: | 
| 8 | 
            -
                  semester: { | 
| 9 | 
            -
                  year: | 
| 6 | 
            +
                  month:    {months: 1},
         | 
| 7 | 
            +
                  quarter:  {months: 3},
         | 
| 8 | 
            +
                  semester: {months: 6},
         | 
| 9 | 
            +
                  year:     {years: 1}
         | 
| 10 10 | 
             
                }
         | 
| 11 11 |  | 
| 12 | 
            -
                attr_reader :terms, :starts_on, :period
         | 
| 12 | 
            +
                attr_reader :terms, :starts_on, :period #, :interests_start_date
         | 
| 13 13 |  | 
| 14 | 
            -
                def initialize(starts_on:, period:)
         | 
| 15 | 
            -
                  @terms = []
         | 
| 16 | 
            -
                  @starts_on = (Date === starts_on ? starts_on : Date.parse(starts_on))
         | 
| 14 | 
            +
                def initialize(starts_on:, period:, interests_start_date: nil)
         | 
| 17 15 | 
             
                  raise ArgumentError.new(:period) unless PERIODS.keys.include?(period)
         | 
| 18 | 
            -
             | 
| 16 | 
            +
             | 
| 17 | 
            +
                  @terms     = []
         | 
| 18 | 
            +
                  @starts_on = (starts_on.is_a?(Date) ? starts_on : Date.parse(starts_on))
         | 
| 19 | 
            +
                  @period    = period
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  if interests_start_date
         | 
| 22 | 
            +
                    @interests_start_date = (interests_start_date.is_a?(Date) ? interests_start_date : Date.parse(interests_start_date))
         | 
| 23 | 
            +
                  end
         | 
| 19 24 | 
             
                end
         | 
| 20 25 |  | 
| 21 26 | 
             
                def <<(term)
         | 
| 22 | 
            -
                  raise ArgumentError.new('LoanCreator::Term expected') unless LoanCreator::Term | 
| 23 | 
            -
                  term.index  | 
| 24 | 
            -
                  term.due_on  | 
| 27 | 
            +
                  raise ArgumentError.new('LoanCreator::Term expected') unless term.is_a?(LoanCreator::Term)
         | 
| 28 | 
            +
                  term.index  ||= autoincrement_index
         | 
| 29 | 
            +
                  term.due_on ||= date_for(term.index)
         | 
| 25 30 | 
             
                  @terms << term
         | 
| 26 31 | 
             
                  self
         | 
| 27 32 | 
             
                end
         | 
| 28 33 |  | 
| 29 | 
            -
                def reset_indexes_and_due_on_dates
         | 
| 30 | 
            -
                  @autoincrement_index = 0
         | 
| 31 | 
            -
                  @autoincrement_date = @starts_on
         | 
| 32 | 
            -
                  @terms.each do |term|
         | 
| 33 | 
            -
                    term[:index] = autoincrement_index
         | 
| 34 | 
            -
                    term[:due_on] = autoincrement_date
         | 
| 35 | 
            -
                  end
         | 
| 36 | 
            -
                  self
         | 
| 37 | 
            -
                end
         | 
| 38 | 
            -
             | 
| 39 34 | 
             
                def to_csv(header: true)
         | 
| 40 35 | 
             
                  output = []
         | 
| 41 36 | 
             
                  output << terms.first.to_h.keys.join(',') if header
         | 
| @@ -43,20 +38,33 @@ module LoanCreator | |
| 43 38 | 
             
                  output
         | 
| 44 39 | 
             
                end
         | 
| 45 40 |  | 
| 41 | 
            +
                def term(index)
         | 
| 42 | 
            +
                  @terms.find { |term| term.index == index }
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 46 45 | 
             
                private
         | 
| 47 46 |  | 
| 48 | 
            -
                # First term index of a timetable term is 1
         | 
| 49 47 | 
             
                def autoincrement_index
         | 
| 50 | 
            -
                  @ | 
| 51 | 
            -
             | 
| 48 | 
            +
                  @current_index = @current_index.nil? ? 1 : @current_index + 1
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                def date_for(index)
         | 
| 52 | 
            +
                  @_dates ||= Hash.new do |dates, index|
         | 
| 53 | 
            +
                    dates[index] =
         | 
| 54 | 
            +
                      if index < 1
         | 
| 55 | 
            +
                        dates[index + 1].advance(PERIODS.fetch(period).transform_values {|n| -n})
         | 
| 56 | 
            +
                      elsif index == 1
         | 
| 57 | 
            +
                        starts_on
         | 
| 58 | 
            +
                      else
         | 
| 59 | 
            +
                        dates[index - 1].advance(PERIODS.fetch(period))
         | 
| 60 | 
            +
                      end
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                  @_dates[index]
         | 
| 52 64 | 
             
                end
         | 
| 53 65 |  | 
| 54 | 
            -
                 | 
| 55 | 
            -
             | 
| 56 | 
            -
                  @autoincrement_date ||= @starts_on
         | 
| 57 | 
            -
                  date = @autoincrement_date
         | 
| 58 | 
            -
                  @autoincrement_date = @autoincrement_date.advance(PERIODS.fetch(@period))
         | 
| 59 | 
            -
                  date
         | 
| 66 | 
            +
                def reset_dates
         | 
| 67 | 
            +
                  @_dates = nil
         | 
| 60 68 | 
             
                end
         | 
| 61 69 | 
             
              end
         | 
| 62 70 | 
             
            end
         | 
    
        data/lib/loan_creator/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: loan_creator
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.5.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - thibaulth
         | 
| @@ -126,6 +126,7 @@ files: | |
| 126 126 | 
             
            - ".ruby-gemset"
         | 
| 127 127 | 
             
            - ".ruby-version"
         | 
| 128 128 | 
             
            - ".travis.yml"
         | 
| 129 | 
            +
            - CapSens_Loan.xlsx
         | 
| 129 130 | 
             
            - Gemfile
         | 
| 130 131 | 
             
            - LICENSE.txt
         | 
| 131 132 | 
             
            - README.md
         |