interest_calc 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7b9270952b4db924510e32a7767e8938c0087bfb2808f5f91083f469fdc2f0f9
4
+ data.tar.gz: 7f35803f477a96ce89afef7fe150c02e7b53de92c33dd2027521e67420d29206
5
+ SHA512:
6
+ metadata.gz: 7b433d79cc59d0d6a6368205d92d54fff8c877511693b9ce6e51cd230f0c2a04d074c4526d3a82b112ba0836d17c9b6be64d1c8f068c6c72fbe70c3c9a4f4812
7
+ data.tar.gz: f09d1dc9b2b0290b281f43e707f42737fe364d57d2a979f428ad811f57324a2f9cf6c63e1c588877eec12f1bc5d77b08b321f05f8a17bfebf4dce297fbad616e
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ .bundle/
2
+ log/*.log
3
+ pkg/
4
+ test/dummy/db/*.sqlite3
5
+ test/dummy/log/*.log
6
+ test/dummy/tmp/
7
+ test/dummy/.sass-cache
8
+
9
+ *.sh
10
+ sample_data.rb
11
+ gre.rb
12
+ gpm.rb
13
+ ghug.rb
14
+ .DS_Store
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 yas4891
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,2 @@
1
+ # interest_calc
2
+ Ruby gem to calculate interests
@@ -0,0 +1,25 @@
1
+ require_relative 'lib/interest_calc/version'
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'interest_calc'
5
+ s.version = InterestCalc::VERSION
6
+ s.summary = "Useful methods around calculating interests, especially for open lines of credit"
7
+ s.description = "Helps you calculate interest for open lines of credit"
8
+ s.authors = ["Christoph Engelhardt"]
9
+ s.email = 'christoph@christophengelhardt.com'
10
+
11
+ # Specify which files should be added to the gem when it is released.
12
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
13
+ s.files = Dir.chdir(File.expand_path(__dir__)) do
14
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
15
+ end
16
+
17
+ s.homepage = 'https://rubygems.org/gems/interest_calc'
18
+ s.license = 'MIT'
19
+
20
+ s.add_dependency('ostruct')
21
+ s.add_dependency('active_support')
22
+
23
+ s.add_dependency('interest_days')
24
+
25
+ end
@@ -0,0 +1,159 @@
1
+ require 'ostruct'
2
+ require 'active_support'
3
+ require 'active_support/core_ext'
4
+
5
+ require 'date'
6
+
7
+
8
+ module InterestCalc
9
+ class OpenLineCalculator
10
+
11
+ attr_accessor :interest_rate
12
+
13
+ def initialize(interest_rate = 0.05)
14
+ @interest_rate = interest_rate
15
+ end
16
+
17
+ # calculates the interest per month for an open line of credit
18
+ def calculate(data)
19
+
20
+ return_values = []
21
+ nitem = nil
22
+ changes = data[:changes]
23
+
24
+ if changes.nil? || changes.count < 1
25
+ raise Exception.new "No changes to the line of credit provided. Please provide an array of changes data[:changes]"
26
+ end
27
+
28
+ changes = changes.reverse # allows us to use #pop
29
+ citem = changes.pop
30
+ cdate = citem[:date]
31
+ camount = citem[:amount]
32
+
33
+ puts "#{self.class.name}##{__method__}:calculation starts: #{cdate.at_beginning_of_month}"
34
+
35
+
36
+ return_values << {year: cdate.year,
37
+ month: cdate.month,
38
+ interest: self.calculate_interest(camount, cdate)
39
+ }
40
+
41
+ # after this point the calculations for the first month are done
42
+
43
+ cdate = cdate.at_beginning_of_month # normalize value to always be the first of the month
44
+ i = 0
45
+
46
+ # at the start changes won't be empty and
47
+ # when all the changes have been popped from the stack nitem won't be empty
48
+ while(!changes.empty? || !nitem.nil?)
49
+ puts
50
+ puts
51
+ puts "#{self.class.name}##{__method__}: RUN #{i}"
52
+ i+=1
53
+ # only pop the next item if the previously popped item was used
54
+ nitem = nitem || changes.pop
55
+ ndate = nitem[:date]
56
+ cdate = cdate.next_month
57
+ new_return_value = {year: cdate.year, month: cdate.month}
58
+ # the whole month needs to be calculated at the old amount
59
+ if(ndate.at_beginning_of_month != cdate)
60
+ puts "#{self.class.name}##{__method__}: FULL month calculation"
61
+ return_values << {
62
+ year: cdate.year,
63
+ month: cdate.month,
64
+ interest: self.calculate_interest(camount,cdate)
65
+ }
66
+ else # withdrawal/deposit within this month
67
+ puts "#{self.class.name}##{__method__}: SPLIT month calculation"
68
+ # calculate for first half of month with the old amount
69
+
70
+ interest = calculate_interest(camount, cdate, ndate )
71
+ puts "#{self.class.name}##{__method__}: amount changing. OLD:#{camount} -- change:#{nitem[:amount]} -- NEW:#{camount + nitem[:amount]}"
72
+ # change the calculation amount by adding the withdrawal/deposit
73
+ camount += nitem[:amount]
74
+
75
+ # calculate interest for 2nd half of month
76
+ interest += calculate_interest(camount, ndate)
77
+
78
+ return_values << {
79
+ year: cdate.year,
80
+ month: cdate.month,
81
+ interest: interest
82
+ }
83
+
84
+ # reset these variables to pop the next changes-item from the stack
85
+ ndate = nil
86
+ nitem = nil
87
+
88
+ # do NOT change cdate as this is already on the 1st of the month and will
89
+ # increase in the while loop
90
+
91
+ end
92
+
93
+
94
+ end # while !changes.empty?
95
+ cdate = cdate.next_month
96
+ # add one final month after the last month with changes
97
+ # so that users know how much interest is per month going forward
98
+ return_values << {year: cdate.year,
99
+ month: cdate.month,
100
+ interest: self.calculate_interest(camount, cdate)
101
+ }
102
+
103
+ return return_values
104
+
105
+ end
106
+
107
+
108
+ def print(data)
109
+ values = calculate data
110
+
111
+ puts "--------------------------------------"
112
+ puts "| year-month | interest |"
113
+ puts "--------------------------------------"
114
+ values.each do |item|
115
+ ym = "#{item[:year]}-#{item[:month]}".ljust(16)
116
+ i = item[:interest].to_f.round(2).to_s.rjust(19)
117
+ puts "|#{ym}|#{i}|"
118
+ end
119
+ puts "--------------------------------------"
120
+ return values
121
+ end
122
+
123
+ private
124
+ # calculates the interest for current time until either the end of the month (if no end_date given)
125
+ # or the given end_date
126
+ def calculate_interest(camount, cdate, end_date = nil)
127
+ if camount.nil?
128
+ raise "amount can't be nil"
129
+ end
130
+
131
+ puts "#{self.class.name}##{__method__}: date:#{cdate} -- end_date:#{end_date}"
132
+ # calculate until end of month if no end_date given.
133
+ # Add one day to include last day in calculations
134
+ end_date = end_date || (cdate.at_end_of_month)
135
+
136
+ puts "#{self.class.name}##{__method__}: interest rate: #{@interest_rate}"
137
+
138
+ result = interest_days_counter_factor(cdate, end_date) * @interest_rate * camount
139
+
140
+ puts "#{self.class.name}##{__method__}: calculated interest: #{result}"
141
+ return result
142
+ end
143
+
144
+ # returns the days counter factor based on European act/360 calculation strategy
145
+ def interest_days_counter_factor(date, end_date)
146
+
147
+ # use European style of calculation where any date on the 31st is
148
+ # counted as 30st
149
+ date = date - 1.day if 31 == date.mday
150
+ end_date = end_date - 1.day if 31 == end_date.mday
151
+
152
+ # add 1 to count the first day as well
153
+ days = ((end_date - date).to_i + 1)
154
+ factor = days / 360.0
155
+ puts "#{self.class.name}##{__method__}: days #{days}-- factor:#{factor}"
156
+ factor
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,3 @@
1
+ module InterestCalc
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,2 @@
1
+ require_relative 'interest_calc/version'
2
+ require_relative 'interest_calc/calculators/open_line_calculator'
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: interest_calc
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Christoph Engelhardt
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-06-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ostruct
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: active_support
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: interest_days
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Helps you calculate interest for open lines of credit
56
+ email: christoph@christophengelhardt.com
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - ".gitignore"
62
+ - LICENSE
63
+ - README.md
64
+ - interest_calc.gemspec
65
+ - lib/interest_calc.rb
66
+ - lib/interest_calc/calculators/open_line_calculator.rb
67
+ - lib/interest_calc/version.rb
68
+ homepage: https://rubygems.org/gems/interest_calc
69
+ licenses:
70
+ - MIT
71
+ metadata: {}
72
+ post_install_message:
73
+ rdoc_options: []
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ requirements: []
87
+ rubygems_version: 3.2.15
88
+ signing_key:
89
+ specification_version: 4
90
+ summary: Useful methods around calculating interests, especially for open lines of
91
+ credit
92
+ test_files: []