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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f175586a927e2dd609903b79ed629c1ab5bc3aecde02b1cc5809629d33c5b852
4
- data.tar.gz: fd695b7fba80c64efa7b5c0cefc9a1092ed6c74aa4ac070da3cb25771740e3bf
3
+ metadata.gz: 3f7d2dcd74aa8a01bb25577eaf1c6ea05daba9eef071d76119d7ad00773fe0f7
4
+ data.tar.gz: ed40fe1ff5610cbef9bc5c5c92f31095a0eaa6ad745a8f194861e65d5b8e316b
5
5
  SHA512:
6
- metadata.gz: 6de1a02fc201dd985c0c255ee7b96989d477723607015647f9608228174f9bfdd4aa7f667ea9d74425a251b4912dae0430e1edd84623b7a8c1953e28ce1797f9
7
- data.tar.gz: b3b3e8d4a1d007b1f8481238df1d021b5f597d2a46b887495f4099320dcd20711ccc2fb9e2ed2fa34775a99c33826c9de2d4a5b7ede12d7eb8e978d45df017f1
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 tha specifies whether or not to use the real number of days in each month when calculating the periodic interests rate. Note that leap years are taken into account. Default: `false`.
184
- The default behaviour is to use the `period` in relation to the number of months in a year (ie: 12)
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
 
@@ -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(@due_on, timetable)
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(due_date, timetable)
36
- computed_periodic_interests_rate = periodic_interests_rate(due_date, relative_to_date: timetable_term_dates[timetable.next_index - 1])
37
- (amount + @due_interests_beginning_of_period).mult(computed_periodic_interests_rate, BIG_DECIMAL_DIGITS)
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(@due_on, timetable)
50
+ @due_interests_end_of_period += compute_capitalized_interests(timetable)
43
51
  end
44
52
  end
45
53
  end
@@ -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(date = nil, relative_to_date: nil)
53
+ def periodic_interests_rate(start_date, end_date)
42
54
  if realistic_durations?
43
- compute_realistic_periodic_interests_rate_percentage_for(date, relative_to_date: relative_to_date).div(100, BIG_DECIMAL_DIGITS)
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
- REQUIRED_ATTRIBUTES.each { |k| raise ArgumentError.new(k) unless @options.fetch(k, nil) }
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
- REQUIRED_ATTRIBUTES.each { |k| instance_variable_set(:"@#{k}", @options.fetch(k)) }
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 compute_realistic_periodic_interests_rate_percentage_for(date, relative_to_date:)
217
- realistic_days = 365
218
- realistic_days += 1 if date.leap?
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
- annual_interests_rate.div(bigd(realistic_days) / bigd(realistic_days_in_period), BIG_DECIMAL_DIGITS)
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 realistic_durations?
225
- !!@realistic_durations
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
- (@crd_beginning_of_period + @due_interests_beginning_of_period).mult(interests_rate, BIG_DECIMAL_DIGITS)
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
@@ -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
- @period_theoric_interests = period_theoric_interests(computed_periodic_interests_rate)
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(@due_on, relative_to_date: timetable_term_dates[timetable.next_index - 1])
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
@@ -40,5 +40,9 @@ module LoanCreator
40
40
  def next_index
41
41
  @current_index.nil? ? @starting_index : @current_index + 1
42
42
  end
43
+
44
+ def current_index
45
+ @current_index.nil? ? @starting_index - 1 : @current_index
46
+ end
43
47
  end
44
48
  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(due_date, relative_to_date: timetable_term_dates[timetable.next_index - 1])
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
 
@@ -1,3 +1,3 @@
1
1
  module LoanCreator
2
- VERSION = '0.8.2'.freeze
2
+ VERSION = '0.11.0'.freeze
3
3
  end
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, 'loan_creator/excel_formulas'
11
- autoload :BorrowerTimetable, 'loan_creator/borrower_timetable'
12
- autoload :Common, 'loan_creator/common'
13
- autoload :Standard, 'loan_creator/standard'
14
- autoload :Linear, 'loan_creator/linear'
15
- autoload :InFine, 'loan_creator/in_fine'
16
- autoload :Bullet, 'loan_creator/bullet'
17
- autoload :Timetable, 'loan_creator/timetable'
18
- autoload :Term, 'loan_creator/term'
19
- autoload :UncapitalizedBullet, 'loan_creator/uncapitalized_bullet'
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.8.2
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-05-05 00:00:00.000000000 Z
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