loan_creator 0.8.2 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +8 -2
- data/lib/loan_creator/bullet.rb +13 -5
- data/lib/loan_creator/common.rb +64 -19
- data/lib/loan_creator/linear.rb +15 -2
- data/lib/loan_creator/standard.rb +1 -1
- data/lib/loan_creator/term_dates_validator.rb +75 -0
- data/lib/loan_creator/time_helper.rb +62 -0
- data/lib/loan_creator/timetable.rb +4 -0
- data/lib/loan_creator/uncapitalized_bullet.rb +1 -1
- data/lib/loan_creator/version.rb +1 -1
- data/lib/loan_creator.rb +12 -10
- data/scripts/convert_export_to_spec.rb +51 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3f7d2dcd74aa8a01bb25577eaf1c6ea05daba9eef071d76119d7ad00773fe0f7
|
4
|
+
data.tar.gz: ed40fe1ff5610cbef9bc5c5c92f31095a0eaa6ad745a8f194861e65d5b8e316b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16256ac04047a1b505e37dddec9299d5409d1940dfe2d7271ebc0cc5207bfb5301f3375fbf3f793cb5a70dbacab3e5a7c3c6bd87d07c6449faeba2dd73368f71
|
7
|
+
data.tar.gz: 4fe77879f1dfa61adecaf5d30dcf2dd5d6c501c1d82b75232cd106ffa827c440d52326a37c25bc939f445010ab7c4d256527e92edef2124d3c6ed8369337c0eb
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
v0.9.1
|
2
|
+
-------------------------
|
3
|
+
- add spec importer `scripts/convert_export_to_spec.rb {csv_url}`
|
4
|
+
- fix period interests rate for realistic duration period overlapping leap & non leap years
|
5
|
+
|
6
|
+
v0.9.0
|
7
|
+
-------------------------
|
8
|
+
- add possibility to pass the argument `term_dates` for `LoanCreator::Bullet`, `LoanCreator::InFine` and `LoanCreator::Linear`
|
9
|
+
- `term_dates` option is based on `realistic_durations` and allow to compute terms custom date to custom date
|
10
|
+
|
1
11
|
v0.8.2
|
2
12
|
-------------------------
|
3
13
|
|
data/README.md
CHANGED
@@ -180,8 +180,14 @@ additional term with only interests for the time difference.
|
|
180
180
|
For example, with a `start_at` in january 2020 and a `interests_start_date` in october 2019, the timetable will include a
|
181
181
|
first term corresponding to 3 months of interests.
|
182
182
|
|
183
|
-
`realistic_durations`: Optional. A boolean
|
184
|
-
|
183
|
+
`realistic_durations`: Optional. A boolean that specifies whether or not to use the real number of days in each month when calculating the periodic interests rate (ie: for a period between January 1st 2021 and February 1st 2021 the period rate is annual_interests_rate * 31/355).
|
184
|
+
Note that leap years are taken into account (ie: for a period between January 1st 2020 and February 1st 2020 the period rate is annual_interests_rate * 31/356). Also, an overlaping period
|
185
|
+
take each parts into account (ie: for a period between December 1st 2020 and February 1st 2021, the period rate is (annual_interests_rate * (31/355) + annual_interests_rate * (31/356)))
|
186
|
+
Default: `false`.
|
187
|
+
The default behaviour is to use the `period` in relation to the number of months in a year (ie: for a monthly timetable annual_interests_rate * 1/12, for quarter annual_interests_rate * 3/12, etc.)
|
188
|
+
|
189
|
+
|
190
|
+
`term_dates`: Optional. Implemented for `LoanCreator::Bullet`, `LoanCreator::InFine` and `LoanCreator::Linear`. Can be used if you want to implement custom due dates for terms. Terms will be computed from date to date. Must be an array with following dates. Must contain duration + 1 dates. The first element of the array is the first period start_date and last is the last period pay day.
|
185
191
|
|
186
192
|
## Calculation
|
187
193
|
|
data/lib/loan_creator/bullet.rb
CHANGED
@@ -24,7 +24,7 @@ module LoanCreator
|
|
24
24
|
def compute_last_term(timetable)
|
25
25
|
@crd_end_of_period = bigd('0')
|
26
26
|
@due_interests_beginning_of_period = @due_interests_end_of_period
|
27
|
-
@period_interests = @due_interests_end_of_period + compute_capitalized_interests(
|
27
|
+
@period_interests = @due_interests_end_of_period + compute_capitalized_interests(timetable)
|
28
28
|
@due_interests_end_of_period = 0
|
29
29
|
@period_capital = @crd_beginning_of_period
|
30
30
|
@total_paid_capital_end_of_period += @period_capital
|
@@ -32,14 +32,22 @@ module LoanCreator
|
|
32
32
|
@period_amount_to_pay = @period_capital + @period_interests
|
33
33
|
end
|
34
34
|
|
35
|
-
def compute_capitalized_interests(
|
36
|
-
|
37
|
-
|
35
|
+
def compute_capitalized_interests(timetable)
|
36
|
+
if multi_part_interests_calculation && term_dates? && (timetable_term_dates[timetable.current_index] + 1.year) < @due_on
|
37
|
+
multi_part_interests(
|
38
|
+
timetable_term_dates[timetable.current_index],
|
39
|
+
@due_on,
|
40
|
+
annual_interests_rate,
|
41
|
+
amount_to_capitalize
|
42
|
+
)
|
43
|
+
else
|
44
|
+
compute_period_generated_interests(periodic_interests_rate(timetable_term_dates[timetable.current_index], @due_on))
|
45
|
+
end
|
38
46
|
end
|
39
47
|
|
40
48
|
def compute_term(timetable)
|
41
49
|
@due_interests_beginning_of_period = @due_interests_end_of_period
|
42
|
-
@due_interests_end_of_period += compute_capitalized_interests(
|
50
|
+
@due_interests_end_of_period += compute_capitalized_interests(timetable)
|
43
51
|
end
|
44
52
|
end
|
45
53
|
end
|
data/lib/loan_creator/common.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module LoanCreator
|
2
2
|
class Common
|
3
3
|
extend BorrowerTimetable
|
4
|
+
include TimeHelper
|
4
5
|
|
5
6
|
PERIODS_IN_MONTHS = {
|
6
7
|
month: 1,
|
@@ -17,14 +18,24 @@ module LoanCreator
|
|
17
18
|
:duration_in_periods
|
18
19
|
].freeze
|
19
20
|
|
21
|
+
REQUIRED_ATTRIBUTES_TERM_DATES = [
|
22
|
+
:amount,
|
23
|
+
:annual_interests_rate,
|
24
|
+
:starts_on,
|
25
|
+
:duration_in_periods,
|
26
|
+
:term_dates
|
27
|
+
].freeze
|
28
|
+
|
20
29
|
OPTIONAL_ATTRIBUTES = {
|
21
30
|
# attribute: default_value
|
22
31
|
deferred_in_periods: 0,
|
23
32
|
interests_start_date: nil,
|
24
33
|
initial_values: {},
|
25
|
-
realistic_durations: false
|
34
|
+
realistic_durations: false,
|
35
|
+
multi_part_interests_calculation: true
|
26
36
|
}.freeze
|
27
37
|
|
38
|
+
|
28
39
|
attr_reader *REQUIRED_ATTRIBUTES
|
29
40
|
attr_reader *OPTIONAL_ATTRIBUTES.keys
|
30
41
|
|
@@ -36,11 +47,12 @@ module LoanCreator
|
|
36
47
|
validate_attributes
|
37
48
|
set_initial_values
|
38
49
|
validate_initial_values
|
50
|
+
prepare_custom_term_dates if term_dates?
|
39
51
|
end
|
40
52
|
|
41
|
-
def periodic_interests_rate(
|
53
|
+
def periodic_interests_rate(start_date, end_date)
|
42
54
|
if realistic_durations?
|
43
|
-
|
55
|
+
compute_realistic_periodic_interests_rate(start_date, end_date, annual_interests_rate)
|
44
56
|
else
|
45
57
|
@periodic_interests_rate ||=
|
46
58
|
annual_interests_rate.div(12 / PERIODS_IN_MONTHS[period], BIG_DECIMAL_DIGITS).div(100, BIG_DECIMAL_DIGITS)
|
@@ -75,35 +87,49 @@ module LoanCreator
|
|
75
87
|
private
|
76
88
|
|
77
89
|
def require_attributes
|
78
|
-
|
90
|
+
required_attributes.each { |k| raise ArgumentError.new(k) unless @options.fetch(k, nil) }
|
79
91
|
end
|
80
92
|
|
81
93
|
def reinterpret_attributes
|
82
|
-
@options[:period] = @options[:period].to_sym
|
94
|
+
@options[:period] = @options[:period].to_sym unless term_dates?
|
83
95
|
@options[:amount] = bigd(@options[:amount])
|
84
96
|
@options[:annual_interests_rate] = bigd(@options[:annual_interests_rate])
|
85
97
|
@options[:starts_on] = Date.parse(@options[:starts_on]) if @options[:starts_on].is_a?(String)
|
86
98
|
@options[:interests_start_date] = Date.parse(@options[:interests_start_date]) if @options[:interests_start_date].is_a?(String)
|
99
|
+
|
100
|
+
if term_dates?
|
101
|
+
@options[:term_dates].map!{ |term_date| Date.parse(term_date.to_s) }
|
102
|
+
end
|
87
103
|
end
|
88
104
|
|
89
105
|
def set_attributes
|
90
|
-
|
91
|
-
OPTIONAL_ATTRIBUTES.each { |k,v| instance_variable_set(:"@#{k}", @options.fetch(k, v)) }
|
106
|
+
required_attributes.each { |k| instance_variable_set(:"@#{k}", @options.fetch(k)) }
|
107
|
+
OPTIONAL_ATTRIBUTES.each { |k, v| instance_variable_set(:"@#{k}", @options.fetch(k, v)) }
|
92
108
|
end
|
93
109
|
|
94
110
|
def validate(key, &block)
|
95
111
|
raise unless block.call(instance_variable_get(:"@#{key}"))
|
96
|
-
rescue
|
97
|
-
raise ArgumentError.new(key)
|
112
|
+
rescue => e
|
113
|
+
raise ArgumentError.new([key, e.message].join(': '))
|
98
114
|
end
|
99
115
|
|
100
116
|
def validate_attributes
|
101
|
-
validate(:period) { |v| PERIODS_IN_MONTHS.keys.include?(v) }
|
117
|
+
validate(:period) { |v| PERIODS_IN_MONTHS.keys.include?(v) } unless term_dates?
|
102
118
|
validate(:amount) { |v| v.is_a?(BigDecimal) && v > 0 }
|
103
119
|
validate(:annual_interests_rate) { |v| v.is_a?(BigDecimal) && v >= 0 }
|
104
120
|
validate(:starts_on) { |v| v.is_a?(Date) }
|
105
121
|
validate(:duration_in_periods) { |v| v.is_a?(Integer) && v > 0 }
|
106
122
|
validate(:deferred_in_periods) { |v| v.is_a?(Integer) && v >= 0 && v < duration_in_periods }
|
123
|
+
validate_term_dates if term_dates?
|
124
|
+
end
|
125
|
+
|
126
|
+
def validate_term_dates
|
127
|
+
TermDatesValidator.call(
|
128
|
+
term_dates: @options[:term_dates],
|
129
|
+
duration_in_periods: @options[:duration_in_periods],
|
130
|
+
interests_start_date: @options[:interests_start_date],
|
131
|
+
loan_class: self.class.name
|
132
|
+
)
|
107
133
|
end
|
108
134
|
|
109
135
|
def validate_initial_values
|
@@ -210,23 +236,42 @@ module LoanCreator
|
|
210
236
|
end
|
211
237
|
|
212
238
|
def term_zero?
|
213
|
-
interests_start_date && interests_start_date < term_zero_date
|
239
|
+
(interests_start_date && interests_start_date < term_zero_date) && !term_dates?
|
214
240
|
end
|
215
241
|
|
216
|
-
def
|
217
|
-
|
218
|
-
|
219
|
-
realistic_days_in_period = (date - relative_to_date).to_i
|
242
|
+
def realistic_durations?
|
243
|
+
term_dates? || @realistic_durations.present?
|
244
|
+
end
|
220
245
|
|
221
|
-
|
246
|
+
def required_attributes
|
247
|
+
if term_dates?
|
248
|
+
REQUIRED_ATTRIBUTES_TERM_DATES
|
249
|
+
else
|
250
|
+
REQUIRED_ATTRIBUTES
|
251
|
+
end
|
222
252
|
end
|
223
253
|
|
224
|
-
def
|
225
|
-
|
254
|
+
def term_dates?
|
255
|
+
@options[:term_dates].present?
|
256
|
+
end
|
257
|
+
|
258
|
+
def prepare_custom_term_dates
|
259
|
+
term_dates = @options[:term_dates].each_with_index.with_object({}) do |(term_date, index), obj|
|
260
|
+
obj[index + @starting_index - 1] = term_date
|
261
|
+
end
|
262
|
+
|
263
|
+
# if starting_index > 1 term_dates[0] is not set
|
264
|
+
term_dates[0] ||= starts_on
|
265
|
+
@_timetable_term_dates = term_dates
|
266
|
+
@realistic_durations = true
|
226
267
|
end
|
227
268
|
|
228
269
|
def compute_period_generated_interests(interests_rate)
|
229
|
-
|
270
|
+
amount_to_capitalize.mult(interests_rate, BIG_DECIMAL_DIGITS)
|
271
|
+
end
|
272
|
+
|
273
|
+
def amount_to_capitalize
|
274
|
+
@crd_beginning_of_period + @due_interests_beginning_of_period
|
230
275
|
end
|
231
276
|
end
|
232
277
|
end
|
data/lib/loan_creator/linear.rb
CHANGED
@@ -23,12 +23,25 @@ module LoanCreator
|
|
23
23
|
@last_period = last_period?(idx)
|
24
24
|
@deferred_period = @index <= deferred_in_periods
|
25
25
|
@due_on = timetable_term_dates[timetable.next_index]
|
26
|
-
computed_periodic_interests_rate = periodic_interests_rate(@due_on, relative_to_date: timetable_term_dates[timetable.next_index - 1])
|
27
26
|
|
28
27
|
# Reminder: CRD beginning of period = CRD end of period **of previous period**
|
29
28
|
@crd_beginning_of_period = @crd_end_of_period
|
30
29
|
@due_interests_beginning_of_period = @due_interests_end_of_period
|
31
|
-
|
30
|
+
|
31
|
+
@period_theoric_interests = (
|
32
|
+
# if period is more than a year
|
33
|
+
if multi_part_interests_calculation && term_dates? && (timetable_term_dates[timetable.current_index] + 1.year) < @due_on
|
34
|
+
multi_part_interests(
|
35
|
+
timetable_term_dates[timetable.current_index],
|
36
|
+
@due_on,
|
37
|
+
annual_interests_rate,
|
38
|
+
amount_to_capitalize
|
39
|
+
)
|
40
|
+
else
|
41
|
+
period_theoric_interests(periodic_interests_rate(timetable_term_dates[timetable.current_index], @due_on))
|
42
|
+
end
|
43
|
+
)
|
44
|
+
|
32
45
|
@delta_interests = @period_theoric_interests - @period_theoric_interests.round(2)
|
33
46
|
@accrued_delta_interests += @delta_interests
|
34
47
|
@amount_to_add = bigd(
|
@@ -24,7 +24,7 @@ module LoanCreator
|
|
24
24
|
@last_period = last_period?(idx)
|
25
25
|
@deferred_period = @index <= deferred_in_periods
|
26
26
|
@due_on = timetable_term_dates[timetable.next_index]
|
27
|
-
computed_periodic_interests_rate = periodic_interests_rate(
|
27
|
+
computed_periodic_interests_rate = periodic_interests_rate(timetable_term_dates[timetable.current_index], @due_on)
|
28
28
|
|
29
29
|
@crd_beginning_of_period = @crd_end_of_period
|
30
30
|
@period_theoric_interests = period_theoric_interests(@index, computed_periodic_interests_rate)
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module LoanCreator
|
2
|
+
module TermDatesValidator
|
3
|
+
def self.call(term_dates:, duration_in_periods:, interests_start_date:, loan_class:)
|
4
|
+
is_array(term_dates)
|
5
|
+
matches_duration(term_dates, duration_in_periods)
|
6
|
+
interests_start_date_present(interests_start_date)
|
7
|
+
coherent_dates_for_non_bullet(term_dates)
|
8
|
+
coherent_dates_for_bullet(term_dates) if bullet?(loan_class)
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def self.is_array(term_dates)
|
14
|
+
unless term_dates.is_a?(Array)
|
15
|
+
raise TypeError, 'the :term_dates option must be an Array'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.matches_duration(term_dates, duration_in_periods)
|
20
|
+
unless term_dates.size == duration_in_periods + 1
|
21
|
+
error_message = "the size of :term_dates (#{term_dates.size}) do not match the :duration_in_periods (#{duration_in_periods})."
|
22
|
+
advice = "You must pass the previous term date (or start_on if starting_index == 1) as the first term date"
|
23
|
+
raise ArgumentError, "#{error_message} #{advice}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.interests_start_date_present(interests_start_date)
|
28
|
+
if interests_start_date.present?
|
29
|
+
raise ArgumentError, ":interests_start_date is no compatible with :term_dates"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.coherent_dates_for_non_bullet(term_dates)
|
34
|
+
term_dates.each_with_index do |term_date, index|
|
35
|
+
next if index.zero?
|
36
|
+
|
37
|
+
previous_term_date = term_dates[index - 1]
|
38
|
+
|
39
|
+
unless term_date > previous_term_date
|
40
|
+
previous_term_date_description =
|
41
|
+
":term_dates[#{index - 1}] (#{term_dates[index - 1].strftime('%Y-%m-%d')})"
|
42
|
+
|
43
|
+
error_message = "#{previous_term_date_description} must be before :term_dates[#{index}] (#{term_date.strftime('%Y-%m-%d')})"
|
44
|
+
|
45
|
+
raise ArgumentError, error_message
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.coherent_dates_for_bullet(term_dates)
|
51
|
+
term_dates.each_with_index do |term_date, index|
|
52
|
+
next if index.zero?
|
53
|
+
|
54
|
+
days_in_year = 365
|
55
|
+
days_in_year += 1 if term_date.leap?
|
56
|
+
|
57
|
+
previous_term_date = term_dates[index - 1]
|
58
|
+
days_between = (term_date - previous_term_date).to_i.abs
|
59
|
+
|
60
|
+
if days_between > days_in_year
|
61
|
+
previous_term_date_description =
|
62
|
+
":term_dates[#{index - 1}] (#{term_dates[index - 1].strftime('%Y-%m-%d')})"
|
63
|
+
|
64
|
+
error_description = "There are #{days_between} days between #{previous_term_date_description} and :term_dates[#{index}]"
|
65
|
+
|
66
|
+
raise ArgumentError, "term dates can't be more than 1 year apart. #{error_description}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.bullet?(loan_class)
|
72
|
+
loan_class == "LoanCreator::Bullet"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module LoanCreator
|
2
|
+
module TimeHelper
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
def leap_days_count(start_date, end_date)
|
7
|
+
start_year = start_date.year
|
8
|
+
# mostly no op but allows to skip one iteration if end date is january 1st
|
9
|
+
end_year = (end_date - 1.day).year
|
10
|
+
|
11
|
+
(start_year..end_year).sum do |year|
|
12
|
+
next 0 unless Date.gregorian_leap?(year)
|
13
|
+
|
14
|
+
current_start_date =
|
15
|
+
if start_year == year
|
16
|
+
start_date
|
17
|
+
else
|
18
|
+
Date.new(year, 1, 1)
|
19
|
+
end
|
20
|
+
|
21
|
+
current_end_date =
|
22
|
+
if end_year == year
|
23
|
+
end_date
|
24
|
+
else
|
25
|
+
Date.new(year + 1, 1, 1)
|
26
|
+
end
|
27
|
+
|
28
|
+
current_end_date - current_start_date
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def compute_realistic_periodic_interests_rate(start_date, end_date, annual_interests_rate)
|
33
|
+
total_days = end_date - start_date
|
34
|
+
leap_days = bigd(leap_days_count(start_date, end_date))
|
35
|
+
non_leap_days = bigd(total_days - leap_days)
|
36
|
+
|
37
|
+
annual_interests_rate.mult(
|
38
|
+
leap_days.div(366, BIG_DECIMAL_DIGITS) +
|
39
|
+
non_leap_days.div(365, BIG_DECIMAL_DIGITS),
|
40
|
+
BIG_DECIMAL_DIGITS
|
41
|
+
).div(100, BIG_DECIMAL_DIGITS)
|
42
|
+
end
|
43
|
+
|
44
|
+
# for terms spanning more than a year,
|
45
|
+
# we capitalize each years until the last one which behaves normally
|
46
|
+
def multi_part_interests(start_date, end_date, annual_interests_rate, amount_to_capitalize)
|
47
|
+
duration_in_days = end_date - start_date
|
48
|
+
leap_days = bigd(leap_days_count(start_date, end_date))
|
49
|
+
non_leap_days = bigd(duration_in_days - leap_days)
|
50
|
+
|
51
|
+
ratio = non_leap_days.div(365, BIG_DECIMAL_DIGITS) + leap_days.div(366, BIG_DECIMAL_DIGITS)
|
52
|
+
full_years, year_part = ratio.divmod(1)
|
53
|
+
rate = annual_interests_rate.div(100, BIG_DECIMAL_DIGITS)
|
54
|
+
|
55
|
+
total = amount_to_capitalize.mult((1 + rate)**full_years, BIG_DECIMAL_DIGITS)
|
56
|
+
.mult(1 + rate * year_part, BIG_DECIMAL_DIGITS)
|
57
|
+
|
58
|
+
total - amount_to_capitalize
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -33,7 +33,7 @@ module LoanCreator
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def compute_interests(due_date, timetable)
|
36
|
-
computed_periodic_interests_rate = periodic_interests_rate(
|
36
|
+
computed_periodic_interests_rate = periodic_interests_rate(timetable_term_dates[timetable.current_index], due_date)
|
37
37
|
amount.mult(bigd(computed_periodic_interests_rate), BIG_DECIMAL_DIGITS)
|
38
38
|
end
|
39
39
|
|
data/lib/loan_creator/version.rb
CHANGED
data/lib/loan_creator.rb
CHANGED
@@ -7,14 +7,16 @@ require 'loan_creator/version'
|
|
7
7
|
module LoanCreator
|
8
8
|
BIG_DECIMAL_DIGITS = 14
|
9
9
|
|
10
|
-
autoload :ExcelFormulas,
|
11
|
-
autoload :
|
12
|
-
autoload :
|
13
|
-
autoload :
|
14
|
-
autoload :
|
15
|
-
autoload :
|
16
|
-
autoload :
|
17
|
-
autoload :
|
18
|
-
autoload :
|
19
|
-
autoload :
|
10
|
+
autoload :ExcelFormulas, 'loan_creator/excel_formulas'
|
11
|
+
autoload :TimeHelper, 'loan_creator/time_helper'
|
12
|
+
autoload :BorrowerTimetable, 'loan_creator/borrower_timetable'
|
13
|
+
autoload :Common, 'loan_creator/common'
|
14
|
+
autoload :Standard, 'loan_creator/standard'
|
15
|
+
autoload :Linear, 'loan_creator/linear'
|
16
|
+
autoload :InFine, 'loan_creator/in_fine'
|
17
|
+
autoload :Bullet, 'loan_creator/bullet'
|
18
|
+
autoload :Timetable, 'loan_creator/timetable'
|
19
|
+
autoload :Term, 'loan_creator/term'
|
20
|
+
autoload :UncapitalizedBullet, 'loan_creator/uncapitalized_bullet'
|
21
|
+
autoload :TermDatesValidator, 'loan_creator/term_dates_validator'
|
20
22
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'csv'
|
3
|
+
require 'open-uri'
|
4
|
+
require 'pry'
|
5
|
+
require 'securerandom'
|
6
|
+
|
7
|
+
csv_url = ARGV[0]
|
8
|
+
|
9
|
+
spec_order = %i[
|
10
|
+
index
|
11
|
+
due_on
|
12
|
+
crd_beginning_of_period
|
13
|
+
crd_end_of_period
|
14
|
+
period_theoric_interests
|
15
|
+
delta_interests
|
16
|
+
accrued_delta_interests
|
17
|
+
amount_to_add
|
18
|
+
period_interests
|
19
|
+
period_capital
|
20
|
+
total_paid_capital_end_of_period
|
21
|
+
total_paid_interests_end_of_period
|
22
|
+
period_amount_to_pay
|
23
|
+
due_interests_beginning_of_period
|
24
|
+
due_interests_end_of_period
|
25
|
+
]
|
26
|
+
|
27
|
+
column_getter = {
|
28
|
+
index: proc { |r| r['t'].to_i },
|
29
|
+
due_on: proc { |r| r['date'] },
|
30
|
+
crd_beginning_of_period: proc { |r| r['crd_start'].gsub(',', '.').to_f },
|
31
|
+
crd_end_of_period: proc { |r| r['crd_end'].gsub(',', '.').to_f },
|
32
|
+
period_theoric_interests: proc { |r| r['period_theoric_interests'].gsub(',', '.').to_f },
|
33
|
+
delta_interests: proc { |r| r['delta_interests'].gsub(',', '.').to_f },
|
34
|
+
accrued_delta_interests: proc { |r| r['cumulated_delta_interests'].gsub(',', '.').to_f },
|
35
|
+
amount_to_add: proc { |r| r['amount_to_add'].gsub(',', '.').to_f },
|
36
|
+
period_interests: proc { |r| r['period_interests'].gsub(',', '.').to_f },
|
37
|
+
period_capital: proc { |r| r['period_capital'].gsub(',', '.').to_f },
|
38
|
+
total_paid_capital_end_of_period: proc { |r| r['total_capital_paid'].gsub(',', '.').to_f },
|
39
|
+
total_paid_interests_end_of_period: proc { |r| r['total_interests_paid'].gsub(',', '.').to_f },
|
40
|
+
period_amount_to_pay: proc { |r| r['period_total'].gsub(',', '.').to_f },
|
41
|
+
due_interests_beginning_of_period: proc { |r| r['due_interests_beginning_of_period'].gsub(',', '.').to_f },
|
42
|
+
due_interests_end_of_period: proc { |r| r['due_interests_end_of_period'].gsub(',', '.').to_f }
|
43
|
+
}
|
44
|
+
|
45
|
+
data = CSV.parse(URI.open(csv_url), headers: true).map(&:to_hash)
|
46
|
+
|
47
|
+
CSV.open("./spec/fixtures/new/#{SecureRandom.alphanumeric}.csv", 'w') do |csv|
|
48
|
+
data.each do |row|
|
49
|
+
csv << spec_order.map { |column| column_getter[column].call(row) }
|
50
|
+
end
|
51
|
+
end
|
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.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- thibaulth
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: exe
|
14
14
|
cert_chain: []
|
15
|
-
date: 2021-
|
15
|
+
date: 2021-11-03 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: bundler
|
@@ -177,10 +177,13 @@ files:
|
|
177
177
|
- lib/loan_creator/linear.rb
|
178
178
|
- lib/loan_creator/standard.rb
|
179
179
|
- lib/loan_creator/term.rb
|
180
|
+
- lib/loan_creator/term_dates_validator.rb
|
181
|
+
- lib/loan_creator/time_helper.rb
|
180
182
|
- lib/loan_creator/timetable.rb
|
181
183
|
- lib/loan_creator/uncapitalized_bullet.rb
|
182
184
|
- lib/loan_creator/version.rb
|
183
185
|
- loan_creator.gemspec
|
186
|
+
- scripts/convert_export_to_spec.rb
|
184
187
|
homepage: https://github.com/CapSens/loan-creator
|
185
188
|
licenses:
|
186
189
|
- MIT
|