Class: InterestCalc::LineOfCreditCalculator

Inherits:
Object
  • Object
show all
Defined in:
lib/interest_calc/calculators/line_of_credit_calculator.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(interest_rate = 0.05) ⇒ LineOfCreditCalculator

Returns a new instance of LineOfCreditCalculator.



15
16
17
18
# File 'lib/interest_calc/calculators/line_of_credit_calculator.rb', line 15

def initialize(interest_rate = 0.05)
  @interest_rate = interest_rate
  @logger = Logger.new(STDOUT)
end

Instance Attribute Details

#interest_rateObject

Returns the value of attribute interest_rate.



12
13
14
# File 'lib/interest_calc/calculators/line_of_credit_calculator.rb', line 12

def interest_rate
  @interest_rate
end

#loggerObject

Returns the value of attribute logger.



13
14
15
# File 'lib/interest_calc/calculators/line_of_credit_calculator.rb', line 13

def logger
  @logger
end

Instance Method Details

#calculate(data) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/interest_calc/calculators/line_of_credit_calculator.rb', line 20

def calculate(data)
  return_values = []
  nitem = nil
  changes = data[:changes]
  end_date = data[:end_date]

  if changes.nil? || changes.count < 1
    raise Exception.new "No changes to the line of credit provided. Please provide an array of changes data[:changes]"
  end

  changes.reverse!
  citem = changes.pop
  cdate = citem[:date]
  camount = citem[:amount]

  
  interest = 0
  nitem = changes.pop

  logger.debug "#{self.class.name}##{__method__}:calculation starts: #{cdate.at_beginning_of_month}"

  while(cdate <= cdate.at_end_of_month) do

    # amount has changed
    if(!nitem.nil? && nitem[:date] == cdate)
      logger.debug "#{self.class.name}##{__method__}: amount changing. OLD:#{camount} -- change:#{nitem[:amount]} -- NEW:#{camount + nitem[:amount]}"
      camount += nitem[:amount]
      nitem = changes.pop # pops nil if changes.empty?
    end

    interest += camount * interest_rate / 365.0

    if(cdate == cdate.at_end_of_month)
      return_values << {
        interest: interest,
        year: cdate.year,
        month: cdate.month
      }

      interest = 0
      logger.debug "#{self.class.name}##{__method__}: stored:#{return_values.last}"

      # if there are no further changes and this month is over, abort
      break if nitem.nil? && (end_date.nil? || cdate >= end_date)
    end

    

    cdate = cdate + 1.day
  end
  
  return return_values

end

#calculate_old(data) ⇒ Object

calculates the interest per month for an open line of credit



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/interest_calc/calculators/line_of_credit_calculator.rb', line 77

def calculate_old(data)

  return_values = []
  nitem = nil
  changes = data[:changes]

  if changes.nil? || changes.count < 1
    raise Exception.new "No changes to the line of credit provided. Please provide an array of changes data[:changes]"
  end

  changes = changes.reverse # allows us to use #pop
  citem = changes.pop
  cdate = citem[:date]
  camount = citem[:amount]

  puts "#{self.class.name}##{__method__}:calculation starts: #{cdate.at_beginning_of_month}"


  return_values << {year: cdate.year,
    month: cdate.month,
    interest: self.calculate_interest(camount, cdate)
  }

  # after this point the calculations for the first month are done

  cdate = cdate.at_beginning_of_month # normalize value to always be the first of the month
  i = 0

  # at the start changes won't be empty and
  # when all the changes have been popped from the stack nitem won't be empty
  while(!changes.empty? || !nitem.nil?)
    puts
    puts
    puts "#{self.class.name}##{__method__}: RUN #{i}"
    i+=1
    # only pop the next item if the previously popped item was used
    nitem = nitem || changes.pop
    ndate = nitem[:date]
    cdate = cdate.next_month
    new_return_value = {year: cdate.year, month: cdate.month}
    # the whole month needs to be calculated at the old amount
    if(ndate.at_beginning_of_month != cdate)
      puts "#{self.class.name}##{__method__}: FULL month calculation"
      return_values << {
        year: cdate.year,
        month: cdate.month,
        interest: self.calculate_interest(camount,cdate)
      }
    else # withdrawal/deposit within this month
      puts "#{self.class.name}##{__method__}: SPLIT month calculation"
      # calculate for first half of month with the old amount

      interest = calculate_interest(camount, cdate, ndate )
      puts "#{self.class.name}##{__method__}: amount changing. OLD:#{camount} -- change:#{nitem[:amount]} -- NEW:#{camount + nitem[:amount]}"
      # change the calculation amount by adding the withdrawal/deposit
      camount += nitem[:amount]

      # calculate interest for 2nd half of month
      interest += calculate_interest(camount, ndate)

      return_values << {
        year: cdate.year,
        month: cdate.month,
        interest: interest
      }

      # reset these variables to pop the next changes-item from the stack
      ndate = nil
      nitem = nil

      # do NOT change cdate as this is already on the 1st of the month and will
      # increase in the while loop

    end


  end # while !changes.empty?
  cdate = cdate.next_month
  # add one final month after the last month with changes
  # so that users know how much interest is per month going forward
  return_values << {year: cdate.year,
    month: cdate.month,
    interest: self.calculate_interest(camount, cdate)
  }

  return return_values

end


167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/interest_calc/calculators/line_of_credit_calculator.rb', line 167

def print(data)
  values = calculate data

  total_interest = 0.0

  puts "--------------------------------------"
  puts "|    year-month  |     interest      |"
  puts "--------------------------------------"
  values.each do |item|
    ym = "#{item[:year]}-#{item[:month]}".ljust(16)
    i = item[:interest].to_f.round(2).to_s.rjust(19)
    puts "|#{ym}|#{i}|"

    total_interest += item[:interest].to_f
  end
  puts "|#{"2022".ljust(16)}|#{total_interest.round(2).to_s.rjust(19)}|"
  puts "--------------------------------------"
  return values
end