loan_creator 0.5.0 → 0.7.1
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 +5 -5
- data/.circleci/config.yml +45 -0
- data/.rubocop.yml +2 -2
- data/.ruby-version +1 -1
- data/CHANGELOG.md +57 -0
- data/CODE_OF_CONDUCT.md +73 -0
- data/README.md +23 -4
- data/lib/loan_creator.rb +10 -9
- data/lib/loan_creator/borrower_timetable.rb +4 -1
- data/lib/loan_creator/bullet.rb +15 -16
- data/lib/loan_creator/common.rb +72 -35
- data/lib/loan_creator/in_fine.rb +1 -1
- data/lib/loan_creator/linear.rb +1 -0
- data/lib/loan_creator/term.rb +6 -0
- data/lib/loan_creator/timetable.rb +7 -6
- data/lib/loan_creator/uncapitalized_bullet.rb +34 -0
- data/lib/loan_creator/version.rb +1 -1
- data/loan_creator.gemspec +5 -5
- metadata +16 -10
- data/.gitlab-ci.yml +0 -11
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 72a0b25211b0e4cff4c6089ed26ecde7f792eec8404ac58d459e769dcd275c87
|
|
4
|
+
data.tar.gz: ea1836c498d837e62a8cfa389fd6d0041c2a6f71861c2a062ecc780980692170
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b45dd0f8944759ee36d58fb746522a7b2727ba8182a845b8387ff871c13df2494707ab7a7e03f8cd64f6b68d7495a25b1634ff980f81af57f31ee6f870374fe9
|
|
7
|
+
data.tar.gz: b5a70c0ffc639f8afe638f47a423170eddfa0557e44936366895f14a1db9608a2657442dcfcdf2190576416bb215bb1e73776e6a6727304b7e1b4fbb500d2041
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
version: 2.1
|
|
2
|
+
orbs:
|
|
3
|
+
ruby: circleci/ruby@0.1.2
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
build:
|
|
7
|
+
docker:
|
|
8
|
+
- image: circleci/ruby:2.7-node
|
|
9
|
+
executor: ruby/default
|
|
10
|
+
steps:
|
|
11
|
+
- checkout
|
|
12
|
+
- run:
|
|
13
|
+
name: Bundle install
|
|
14
|
+
command: |
|
|
15
|
+
gem install bundler:2.1.4
|
|
16
|
+
bundle install --path vendor/bundle
|
|
17
|
+
- run:
|
|
18
|
+
name: Test
|
|
19
|
+
command: bundle exec rspec
|
|
20
|
+
- run:
|
|
21
|
+
name: Coding style
|
|
22
|
+
command: |
|
|
23
|
+
gem install rubocop
|
|
24
|
+
mkdir -p rubocop
|
|
25
|
+
rubocop --format html -o rubocop/rubocop.html || true
|
|
26
|
+
- run:
|
|
27
|
+
name: Notation
|
|
28
|
+
command: |
|
|
29
|
+
gem install sexp_processor -v 4.13.0
|
|
30
|
+
gem install rubycritic -v 4.3.2
|
|
31
|
+
rubycritic app --no-browser || true
|
|
32
|
+
- run:
|
|
33
|
+
name: "Axe d'optimisation"
|
|
34
|
+
command: |
|
|
35
|
+
gem install fasterer
|
|
36
|
+
fasterer || true
|
|
37
|
+
- run:
|
|
38
|
+
name: "Audit Securité du Gemfile"
|
|
39
|
+
command: |
|
|
40
|
+
gem install bundler-audit
|
|
41
|
+
bundle audit --update
|
|
42
|
+
- store_artifacts:
|
|
43
|
+
path: rubocop/rubocop.html
|
|
44
|
+
- store_artifacts:
|
|
45
|
+
path: tmp/rubycritic
|
data/.rubocop.yml
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
AllCops:
|
|
2
|
-
TargetRubyVersion: 2.
|
|
2
|
+
TargetRubyVersion: 2.7
|
|
3
3
|
Exclude:
|
|
4
4
|
- 'db/**/*'
|
|
5
5
|
- 'vendor/**/*'
|
|
@@ -12,7 +12,7 @@ Metrics/BlockLength:
|
|
|
12
12
|
Exclude:
|
|
13
13
|
- spec/**/*
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Layout/LineLength:
|
|
16
16
|
Max: 120
|
|
17
17
|
|
|
18
18
|
Metrics/MethodLength:
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
ruby-2.
|
|
1
|
+
ruby-2.7.1
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
v0.7.1
|
|
2
|
+
-------------------------
|
|
3
|
+
|
|
4
|
+
- fix `index` for `borrower_timetable` method that did not take into account starting index of `lender_timetables`
|
|
5
|
+
|
|
6
|
+
v0.7.0
|
|
7
|
+
-------------------------
|
|
8
|
+
|
|
9
|
+
- change `capitalized_interests` for `capitalized_interests_beginning_of_period`
|
|
10
|
+
and `capitalized_interests_end_of_period` in `LoanCreator::Term`
|
|
11
|
+
- add `capitalized_interests` in `:inital_values` for `LoanCreator::Bullet` loans
|
|
12
|
+
|
|
13
|
+
v0.6.2
|
|
14
|
+
-------------------------
|
|
15
|
+
|
|
16
|
+
- add `:initial_values` for loans initialization
|
|
17
|
+
- add and compute `capitalized_interests` for `LoanCreator::Bullet` terms
|
|
18
|
+
|
|
19
|
+
v0.6.1
|
|
20
|
+
-------------------------
|
|
21
|
+
|
|
22
|
+
- fix homepage url
|
|
23
|
+
|
|
24
|
+
v0.6.0
|
|
25
|
+
-------------------------
|
|
26
|
+
|
|
27
|
+
- add `LoanCreator::UncapitalizedBullet`
|
|
28
|
+
|
|
29
|
+
v0.5.0
|
|
30
|
+
-------------------------
|
|
31
|
+
|
|
32
|
+
- add `interests_start_date` in `LoanCreator::Common` attributes, replacing `first_term_date`
|
|
33
|
+
|
|
34
|
+
v0.3.0
|
|
35
|
+
-------------------------
|
|
36
|
+
|
|
37
|
+
- add `first_term_date` in `LoanCreator::Common` attributes
|
|
38
|
+
|
|
39
|
+
v0.2.3
|
|
40
|
+
-------------------------
|
|
41
|
+
|
|
42
|
+
- rename `starts_at` -> `starts_on`
|
|
43
|
+
|
|
44
|
+
v0.2.2
|
|
45
|
+
-------------------------
|
|
46
|
+
|
|
47
|
+
- rename `date` -> `due_on`
|
|
48
|
+
|
|
49
|
+
v0.2.1
|
|
50
|
+
-------------------------
|
|
51
|
+
|
|
52
|
+
- convert some options to their expected type by default
|
|
53
|
+
|
|
54
|
+
v0.2.0
|
|
55
|
+
-------------------------
|
|
56
|
+
|
|
57
|
+
- Huge rework : add `period`, rename `amount_in_cents` to `amount` and other breaking changes.
|
data/CODE_OF_CONDUCT.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
|
8
|
+
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
|
9
|
+
level of experience, education, socio-economic status, nationality, personal
|
|
10
|
+
appearance, race, religion, or sexual identity and orientation.
|
|
11
|
+
|
|
12
|
+
## Our Standards
|
|
13
|
+
|
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
|
15
|
+
include:
|
|
16
|
+
|
|
17
|
+
* Using welcoming and inclusive language
|
|
18
|
+
* Being respectful of differing viewpoints and experiences
|
|
19
|
+
* Gracefully accepting constructive criticism
|
|
20
|
+
* Focusing on what is best for the community
|
|
21
|
+
* Showing empathy towards other community members
|
|
22
|
+
|
|
23
|
+
Examples of unacceptable behavior by participants include:
|
|
24
|
+
|
|
25
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
|
26
|
+
advances
|
|
27
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
|
28
|
+
* Public or private harassment
|
|
29
|
+
* Publishing others' private information, such as a physical or electronic
|
|
30
|
+
address, without explicit permission
|
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
|
32
|
+
professional setting
|
|
33
|
+
|
|
34
|
+
## Our Responsibilities
|
|
35
|
+
|
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
|
38
|
+
response to any instances of unacceptable behavior.
|
|
39
|
+
|
|
40
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
|
41
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
|
42
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
|
43
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
|
44
|
+
threatening, offensive, or harmful.
|
|
45
|
+
|
|
46
|
+
## Scope
|
|
47
|
+
|
|
48
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
|
49
|
+
when an individual is representing the project or its community. Examples of
|
|
50
|
+
representing a project or community include using an official project e-mail
|
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
|
53
|
+
further defined and clarified by project maintainers.
|
|
54
|
+
|
|
55
|
+
## Enforcement
|
|
56
|
+
|
|
57
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
58
|
+
reported by contacting the project team at development@capsens.eu. All
|
|
59
|
+
complaints will be reviewed and investigated and will result in a response that
|
|
60
|
+
is deemed necessary and appropriate to the circumstances. The project team is
|
|
61
|
+
obligated to maintain confidentiality with regard to the reporter of an incident.
|
|
62
|
+
Further details of specific enforcement policies may be posted separately.
|
|
63
|
+
|
|
64
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
|
65
|
+
faith may face temporary or permanent repercussions as determined by other
|
|
66
|
+
members of the project's leadership.
|
|
67
|
+
|
|
68
|
+
## Attribution
|
|
69
|
+
|
|
70
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
|
71
|
+
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
|
72
|
+
|
|
73
|
+
[homepage]: https://www.contributor-covenant.org
|
data/README.md
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
`loan_creator` gem intends to provide a set of methods to allow automatic generation of loan timetables, for simulation, from a lender point of view and from a borrower point of view, regarding financial rounding differences. As of today, the gem makes the borrower support any rounding issue. In a later work, an option should be provided to decide who supports such issues.
|
|
4
4
|
|
|
5
|
-
Link to Loan_Creator excel simulator [Click here] (Excel)
|
|
6
|
-
|
|
7
5
|
## Installation
|
|
8
6
|
|
|
9
7
|
Add this line to your application's Gemfile:
|
|
@@ -35,6 +33,7 @@ There are four types of loans. All inherit from a `LoanCreator::Common` class.
|
|
|
35
33
|
LoanCreator::Linear
|
|
36
34
|
LoanCreator::InFine
|
|
37
35
|
LoanCreator::Bullet
|
|
36
|
+
LoanCreator::UncapitalizedBullet
|
|
38
37
|
```
|
|
39
38
|
|
|
40
39
|
Each instance of one of the previous classes has the following attributes:
|
|
@@ -47,6 +46,19 @@ Each instance of one of the previous classes has the following attributes:
|
|
|
47
46
|
:duration_in_periods
|
|
48
47
|
:deferred_in_periods (default to zero)
|
|
49
48
|
:interests_start_date (optional)
|
|
49
|
+
:initial_values (to generate a timetable from a previous term or at a given state)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Initial values must be a hash with specific keys, like so:
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
{
|
|
56
|
+
paid_capital: 0,
|
|
57
|
+
paid_interests: 11000.0,
|
|
58
|
+
accrued_delta_interests: 0,
|
|
59
|
+
starting_index: 2,
|
|
60
|
+
capitalized_interests: 0
|
|
61
|
+
}
|
|
50
62
|
```
|
|
51
63
|
|
|
52
64
|
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:
|
|
@@ -137,6 +149,9 @@ Capital share shall be repaid in full at loan's end.
|
|
|
137
149
|
Interests are capitalized, i.e. added to the borrowed capital on each term.\
|
|
138
150
|
Capital share shall be repaid in full and all interests paid at loan's end.
|
|
139
151
|
|
|
152
|
+
`UncapitalizedBullet` same as bullet, the only difference is the interests\
|
|
153
|
+
are NOT capitalized.
|
|
154
|
+
|
|
140
155
|
There is no deferred time for `InFine` and `Bullet` loans as it would be equivalent to increasing loan's duration.
|
|
141
156
|
|
|
142
157
|
### Attributes
|
|
@@ -155,10 +170,14 @@ There is no deferred time for `InFine` and `Bullet` loans as it would be equival
|
|
|
155
170
|
capital is refunded, only interest. Only relevant for `Standard` and `Linear` loans.
|
|
156
171
|
|
|
157
172
|
`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.
|
|
173
|
+
additional term with only interests for the time difference.
|
|
159
174
|
For example, with a `start_at` in january 2020 and a `interests_start_date` in october 2019, the timetable will include a
|
|
160
175
|
first term corresponding to 3 months of interests.
|
|
161
176
|
|
|
177
|
+
## Calculation
|
|
178
|
+
|
|
179
|
+
An excel simulator for standard case can be found [here](CapSens_Loan.xlsx).
|
|
180
|
+
|
|
162
181
|
## Development
|
|
163
182
|
|
|
164
183
|
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.
|
|
@@ -167,7 +186,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
|
167
186
|
|
|
168
187
|
## Contributing
|
|
169
188
|
|
|
170
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
|
189
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/CapSens/loan_creator.
|
|
171
190
|
|
|
172
191
|
|
|
173
192
|
## License
|
data/lib/loan_creator.rb
CHANGED
|
@@ -7,13 +7,14 @@ require 'loan_creator/version'
|
|
|
7
7
|
module LoanCreator
|
|
8
8
|
BIG_DECIMAL_DIGITS = 14
|
|
9
9
|
|
|
10
|
-
autoload :ExcelFormulas,
|
|
11
|
-
autoload :BorrowerTimetable,
|
|
12
|
-
autoload :Common,
|
|
13
|
-
autoload :Standard,
|
|
14
|
-
autoload :Linear,
|
|
15
|
-
autoload :InFine,
|
|
16
|
-
autoload :Bullet,
|
|
17
|
-
autoload :Timetable,
|
|
18
|
-
autoload :Term,
|
|
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'
|
|
19
20
|
end
|
|
@@ -7,6 +7,8 @@ module LoanCreator
|
|
|
7
7
|
:period_capital,
|
|
8
8
|
:total_paid_capital_end_of_period,
|
|
9
9
|
:total_paid_interests_end_of_period,
|
|
10
|
+
:capitalized_interests_beginning_of_period,
|
|
11
|
+
:capitalized_interests_end_of_period,
|
|
10
12
|
:period_amount_to_pay
|
|
11
13
|
].freeze
|
|
12
14
|
|
|
@@ -18,6 +20,7 @@ module LoanCreator
|
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
borrower_timetable = LoanCreator::Timetable.new(
|
|
23
|
+
starting_index: lenders_timetables.first.starting_index,
|
|
21
24
|
starts_on: lenders_timetables.first.starts_on,
|
|
22
25
|
period: lenders_timetables.first.period
|
|
23
26
|
)
|
|
@@ -34,7 +37,7 @@ module LoanCreator
|
|
|
34
37
|
term = BORROWER_FINANCIAL_ATTRIBUTES.each_with_object({}) do |k, h|
|
|
35
38
|
h[k] = arr.inject(bigd('0')) { |sum, tt| sum + tt.send(k) }
|
|
36
39
|
end
|
|
37
|
-
borrower_timetable << LoanCreator::Term.new(all_zero.merge(term))
|
|
40
|
+
borrower_timetable << LoanCreator::Term.new(**all_zero.merge(term))
|
|
38
41
|
end
|
|
39
42
|
borrower_timetable
|
|
40
43
|
end
|
data/lib/loan_creator/bullet.rb
CHANGED
|
@@ -7,7 +7,7 @@ module LoanCreator
|
|
|
7
7
|
reset_current_term
|
|
8
8
|
@crd_beginning_of_period = amount
|
|
9
9
|
@crd_end_of_period = amount
|
|
10
|
-
(duration_in_periods - 1).times { timetable
|
|
10
|
+
(duration_in_periods - 1).times { |period| compute_term(timetable) }
|
|
11
11
|
compute_last_term
|
|
12
12
|
timetable << current_term
|
|
13
13
|
timetable
|
|
@@ -16,25 +16,24 @@ module LoanCreator
|
|
|
16
16
|
private
|
|
17
17
|
|
|
18
18
|
def compute_last_term
|
|
19
|
-
@crd_end_of_period
|
|
20
|
-
@
|
|
21
|
-
@
|
|
22
|
-
@
|
|
23
|
-
@
|
|
24
|
-
@
|
|
19
|
+
@crd_end_of_period = bigd('0')
|
|
20
|
+
@capitalized_interests_beginning_of_period = @capitalized_interests_end_of_period
|
|
21
|
+
@period_interests = @capitalized_interests_end_of_period + compute_capitalized_interests
|
|
22
|
+
@capitalized_interests_end_of_period = 0
|
|
23
|
+
@period_capital = @crd_beginning_of_period
|
|
24
|
+
@total_paid_capital_end_of_period = @period_capital
|
|
25
|
+
@total_paid_interests_end_of_period = @period_interests
|
|
26
|
+
@period_amount_to_pay = @period_capital + @period_interests
|
|
25
27
|
end
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def total_payment
|
|
30
|
-
amount.mult(
|
|
31
|
-
(bigd(1) + periodic_interests_rate) ** bigd(duration_in_periods),
|
|
32
|
-
BIG_DECIMAL_DIGITS
|
|
33
|
-
)
|
|
29
|
+
def compute_capitalized_interests
|
|
30
|
+
(amount + @capitalized_interests_beginning_of_period).mult(periodic_interests_rate, BIG_DECIMAL_DIGITS)
|
|
34
31
|
end
|
|
35
32
|
|
|
36
|
-
def
|
|
37
|
-
|
|
33
|
+
def compute_term(timetable)
|
|
34
|
+
@capitalized_interests_beginning_of_period = @capitalized_interests_end_of_period
|
|
35
|
+
@capitalized_interests_end_of_period += compute_capitalized_interests
|
|
36
|
+
timetable << current_term
|
|
38
37
|
end
|
|
39
38
|
end
|
|
40
39
|
end
|
data/lib/loan_creator/common.rb
CHANGED
|
@@ -21,6 +21,7 @@ module LoanCreator
|
|
|
21
21
|
# attribute: default_value
|
|
22
22
|
deferred_in_periods: 0,
|
|
23
23
|
interests_start_date: nil,
|
|
24
|
+
initial_values: {}
|
|
24
25
|
}.freeze
|
|
25
26
|
|
|
26
27
|
attr_reader *REQUIRED_ATTRIBUTES
|
|
@@ -32,6 +33,8 @@ module LoanCreator
|
|
|
32
33
|
reinterpret_attributes
|
|
33
34
|
set_attributes
|
|
34
35
|
validate_attributes
|
|
36
|
+
set_initial_values
|
|
37
|
+
validate_initial_values
|
|
35
38
|
end
|
|
36
39
|
|
|
37
40
|
def periodic_interests_rate_percentage
|
|
@@ -90,53 +93,87 @@ module LoanCreator
|
|
|
90
93
|
validate(:deferred_in_periods) { |v| v.is_a?(Integer) && v >= 0 && v < duration_in_periods }
|
|
91
94
|
end
|
|
92
95
|
|
|
96
|
+
def validate_initial_values
|
|
97
|
+
return if initial_values.blank?
|
|
98
|
+
|
|
99
|
+
validate(:total_paid_capital_end_of_period) { |v| v.is_a?(BigDecimal) && v >= 0 }
|
|
100
|
+
validate(:total_paid_interests_end_of_period) { |v| v.is_a?(BigDecimal) && v >= 0 }
|
|
101
|
+
validate(:accrued_delta_interests) { |v| v.is_a?(BigDecimal) }
|
|
102
|
+
validate(:starting_index) { |v| v.is_a?(Integer) && v >= 0 }
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def set_initial_values
|
|
106
|
+
@starting_index = initial_values[:starting_index] || 1
|
|
107
|
+
|
|
108
|
+
return if initial_values.blank?
|
|
109
|
+
|
|
110
|
+
(@total_paid_capital_end_of_period = bigd(initial_values[:paid_capital]))
|
|
111
|
+
(@total_paid_interests_end_of_period = bigd(initial_values[:paid_interests]))
|
|
112
|
+
(@accrued_delta_interests = bigd(initial_values[:accrued_delta_interests]))
|
|
113
|
+
if self.is_a?(LoanCreator::Bullet)
|
|
114
|
+
(@capitalized_interests_beginning_of_period = bigd(initial_values[:capitalized_interests] || 0))
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
93
118
|
def reset_current_term
|
|
94
|
-
@
|
|
95
|
-
@
|
|
96
|
-
@
|
|
97
|
-
@
|
|
98
|
-
@
|
|
99
|
-
@
|
|
100
|
-
@
|
|
101
|
-
@
|
|
102
|
-
@
|
|
103
|
-
@
|
|
104
|
-
@
|
|
105
|
-
@
|
|
106
|
-
@
|
|
119
|
+
@accrued_delta_interests ||= bigd('0')
|
|
120
|
+
@total_paid_capital_end_of_period ||= bigd('0')
|
|
121
|
+
@total_paid_interests_end_of_period ||= bigd('0')
|
|
122
|
+
@capitalized_interests_beginning_of_period ||= bigd('0')
|
|
123
|
+
@crd_beginning_of_period = bigd('0')
|
|
124
|
+
@crd_end_of_period = bigd('0')
|
|
125
|
+
@period_theoric_interests = bigd('0')
|
|
126
|
+
@capitalized_interests_end_of_period = @capitalized_interests_beginning_of_period
|
|
127
|
+
@delta_interests = bigd('0')
|
|
128
|
+
@amount_to_add = bigd('0')
|
|
129
|
+
@period_interests = bigd('0')
|
|
130
|
+
@period_capital = bigd('0')
|
|
131
|
+
@period_amount_to_pay = bigd('0')
|
|
132
|
+
@due_on = nil
|
|
107
133
|
end
|
|
108
134
|
|
|
109
135
|
def current_term
|
|
110
136
|
LoanCreator::Term.new(
|
|
111
|
-
crd_beginning_of_period:
|
|
112
|
-
crd_end_of_period:
|
|
113
|
-
period_theoric_interests:
|
|
114
|
-
delta_interests:
|
|
115
|
-
accrued_delta_interests:
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
137
|
+
crd_beginning_of_period: @crd_beginning_of_period,
|
|
138
|
+
crd_end_of_period: @crd_end_of_period,
|
|
139
|
+
period_theoric_interests: @period_theoric_interests,
|
|
140
|
+
delta_interests: @delta_interests,
|
|
141
|
+
accrued_delta_interests: @accrued_delta_interests,
|
|
142
|
+
capitalized_interests_beginning_of_period: @capitalized_interests_beginning_of_period,
|
|
143
|
+
capitalized_interests_end_of_period: @capitalized_interests_end_of_period,
|
|
144
|
+
amount_to_add: @amount_to_add,
|
|
145
|
+
period_interests: @period_interests,
|
|
146
|
+
period_capital: @period_capital,
|
|
147
|
+
total_paid_capital_end_of_period: @total_paid_capital_end_of_period,
|
|
148
|
+
total_paid_interests_end_of_period: @total_paid_interests_end_of_period,
|
|
149
|
+
period_amount_to_pay: @period_amount_to_pay,
|
|
150
|
+
due_on: @due_on,
|
|
151
|
+
index: compute_index
|
|
124
152
|
)
|
|
125
153
|
end
|
|
126
154
|
|
|
127
155
|
def new_timetable
|
|
128
|
-
LoanCreator::Timetable.new(
|
|
156
|
+
LoanCreator::Timetable.new(
|
|
157
|
+
starts_on: starts_on,
|
|
158
|
+
period: period,
|
|
159
|
+
interests_start_date: interests_start_date,
|
|
160
|
+
starting_index: @starting_index
|
|
161
|
+
)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def compute_index
|
|
165
|
+
@index ? (@starting_index + @index - 1) : nil
|
|
129
166
|
end
|
|
130
167
|
|
|
131
168
|
def compute_term_zero
|
|
132
|
-
@crd_beginning_of_period
|
|
133
|
-
@period_theoric_interests
|
|
134
|
-
@delta_interests
|
|
135
|
-
@accrued_delta_interests
|
|
136
|
-
@period_interests
|
|
137
|
-
@total_paid_interests_end_of_period
|
|
138
|
-
@period_amount_to_pay
|
|
139
|
-
@index
|
|
169
|
+
@crd_beginning_of_period = @crd_end_of_period
|
|
170
|
+
@period_theoric_interests = term_zero_interests
|
|
171
|
+
@delta_interests = @period_theoric_interests - @period_theoric_interests.round(2)
|
|
172
|
+
@accrued_delta_interests += @delta_interests
|
|
173
|
+
@period_interests = @period_theoric_interests.round(2)
|
|
174
|
+
@total_paid_interests_end_of_period += @period_interests
|
|
175
|
+
@period_amount_to_pay = @period_interests
|
|
176
|
+
@index = 0
|
|
140
177
|
end
|
|
141
178
|
|
|
142
179
|
def term_zero_interests
|
data/lib/loan_creator/in_fine.rb
CHANGED
|
@@ -4,7 +4,7 @@ module LoanCreator
|
|
|
4
4
|
# Thus we're generating a Linear loan instead of rewriting already existing code.
|
|
5
5
|
def lender_timetable
|
|
6
6
|
options = @options.merge(deferred_in_periods: duration_in_periods - 1)
|
|
7
|
-
LoanCreator::Linear.new(options).lender_timetable
|
|
7
|
+
LoanCreator::Linear.new(**options).lender_timetable
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
10
|
end
|
data/lib/loan_creator/linear.rb
CHANGED
data/lib/loan_creator/term.rb
CHANGED
|
@@ -17,6 +17,12 @@ module LoanCreator
|
|
|
17
17
|
# Accrued interests' delta
|
|
18
18
|
:accrued_delta_interests,
|
|
19
19
|
|
|
20
|
+
# Capitalized interests at the beginning of the term (Bullet only)
|
|
21
|
+
:capitalized_interests_beginning_of_period,
|
|
22
|
+
|
|
23
|
+
# Capitalized interests at the end of the term (Bullet only)
|
|
24
|
+
:capitalized_interests_end_of_period,
|
|
25
|
+
|
|
20
26
|
# Adjustment of -0.01, 0 or +0.01 cent depending on accrued_delta_interests
|
|
21
27
|
:amount_to_add,
|
|
22
28
|
|
|
@@ -9,14 +9,15 @@ module LoanCreator
|
|
|
9
9
|
year: {years: 1}
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
attr_reader :terms, :starts_on, :period #, :interests_start_date
|
|
12
|
+
attr_reader :terms, :starts_on, :period, :starting_index #, :interests_start_date
|
|
13
13
|
|
|
14
|
-
def initialize(starts_on:, period:, interests_start_date: nil)
|
|
14
|
+
def initialize(starts_on:, period:, interests_start_date: nil, starting_index: 1)
|
|
15
15
|
raise ArgumentError.new(:period) unless PERIODS.keys.include?(period)
|
|
16
16
|
|
|
17
|
-
@terms
|
|
18
|
-
@starts_on
|
|
19
|
-
@period
|
|
17
|
+
@terms = []
|
|
18
|
+
@starts_on = (starts_on.is_a?(Date) ? starts_on : Date.parse(starts_on))
|
|
19
|
+
@period = period
|
|
20
|
+
@starting_index = starting_index
|
|
20
21
|
|
|
21
22
|
if interests_start_date
|
|
22
23
|
@interests_start_date = (interests_start_date.is_a?(Date) ? interests_start_date : Date.parse(interests_start_date))
|
|
@@ -45,7 +46,7 @@ module LoanCreator
|
|
|
45
46
|
private
|
|
46
47
|
|
|
47
48
|
def autoincrement_index
|
|
48
|
-
@current_index = @current_index.nil? ?
|
|
49
|
+
@current_index = (@current_index.nil? ? @starting_index : @current_index + 1)
|
|
49
50
|
end
|
|
50
51
|
|
|
51
52
|
def date_for(index)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module LoanCreator
|
|
2
|
+
class UncapitalizedBullet < LoanCreator::Common
|
|
3
|
+
def lender_timetable
|
|
4
|
+
raise ArgumentError.new(:deferred_in_periods) unless deferred_in_periods == 0
|
|
5
|
+
raise ArgumentError.new(:interests_start_date) unless interests_start_date.nil?
|
|
6
|
+
timetable = new_timetable
|
|
7
|
+
reset_current_term
|
|
8
|
+
@crd_beginning_of_period = amount
|
|
9
|
+
@crd_end_of_period = amount
|
|
10
|
+
(duration_in_periods - 1).times { timetable << current_term }
|
|
11
|
+
compute_last_term
|
|
12
|
+
timetable << current_term
|
|
13
|
+
timetable
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def compute_last_term
|
|
19
|
+
@crd_end_of_period = bigd('0')
|
|
20
|
+
@period_interests = total_interests
|
|
21
|
+
@period_capital = @crd_beginning_of_period
|
|
22
|
+
@total_paid_capital_end_of_period = @period_capital
|
|
23
|
+
@total_paid_interests_end_of_period = @period_interests
|
|
24
|
+
@period_amount_to_pay = @period_capital + @period_interests
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def total_interests
|
|
28
|
+
amount.mult(
|
|
29
|
+
bigd(periodic_interests_rate) * bigd(duration_in_periods),
|
|
30
|
+
BIG_DECIMAL_DIGITS
|
|
31
|
+
)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
data/lib/loan_creator/version.rb
CHANGED
data/loan_creator.gemspec
CHANGED
|
@@ -5,11 +5,11 @@ require 'loan_creator/version'
|
|
|
5
5
|
Gem::Specification.new do |spec|
|
|
6
6
|
spec.name = 'loan_creator'
|
|
7
7
|
spec.version = LoanCreator::VERSION
|
|
8
|
-
spec.authors =
|
|
9
|
-
spec.email = ['thibault@capsens.eu', 'nicolas.besnard@capsens.eu', 'younes.serraj@gmail.com']
|
|
8
|
+
spec.authors = ["thibaulth", "nicob", "younes.serraj", "Antoine Becquet", "Jerome Drevet"]
|
|
9
|
+
spec.email = ['thibault@capsens.eu', 'nicolas.besnard@capsens.eu', 'younes.serraj@gmail.com', "antoine@capsens.eu", "jerome@capsens.eu"]
|
|
10
10
|
|
|
11
11
|
spec.summary = 'Create and update timetables from input data'
|
|
12
|
-
spec.homepage = 'https://
|
|
12
|
+
spec.homepage = 'https://github.com/CapSens/loan-creator'
|
|
13
13
|
spec.license = 'MIT'
|
|
14
14
|
|
|
15
15
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
|
@@ -19,8 +19,8 @@ Gem::Specification.new do |spec|
|
|
|
19
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
20
20
|
spec.require_paths = ['lib']
|
|
21
21
|
|
|
22
|
-
spec.add_development_dependency 'bundler', '~> 1.
|
|
23
|
-
spec.add_development_dependency 'rake', '~>
|
|
22
|
+
spec.add_development_dependency 'bundler', '~> 2.1.4'
|
|
23
|
+
spec.add_development_dependency 'rake', '~> 12.0'
|
|
24
24
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
|
25
25
|
spec.add_development_dependency 'simplecov', '~> 0.16'
|
|
26
26
|
spec.add_development_dependency 'byebug', '~> 11.0'
|
metadata
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: loan_creator
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- thibaulth
|
|
8
8
|
- nicob
|
|
9
9
|
- younes.serraj
|
|
10
|
+
- Antoine Becquet
|
|
11
|
+
- Jerome Drevet
|
|
10
12
|
autorequire:
|
|
11
13
|
bindir: exe
|
|
12
14
|
cert_chain: []
|
|
13
|
-
date:
|
|
15
|
+
date: 2021-01-11 00:00:00.000000000 Z
|
|
14
16
|
dependencies:
|
|
15
17
|
- !ruby/object:Gem::Dependency
|
|
16
18
|
name: bundler
|
|
@@ -18,28 +20,28 @@ dependencies:
|
|
|
18
20
|
requirements:
|
|
19
21
|
- - "~>"
|
|
20
22
|
- !ruby/object:Gem::Version
|
|
21
|
-
version:
|
|
23
|
+
version: 2.1.4
|
|
22
24
|
type: :development
|
|
23
25
|
prerelease: false
|
|
24
26
|
version_requirements: !ruby/object:Gem::Requirement
|
|
25
27
|
requirements:
|
|
26
28
|
- - "~>"
|
|
27
29
|
- !ruby/object:Gem::Version
|
|
28
|
-
version:
|
|
30
|
+
version: 2.1.4
|
|
29
31
|
- !ruby/object:Gem::Dependency
|
|
30
32
|
name: rake
|
|
31
33
|
requirement: !ruby/object:Gem::Requirement
|
|
32
34
|
requirements:
|
|
33
35
|
- - "~>"
|
|
34
36
|
- !ruby/object:Gem::Version
|
|
35
|
-
version: '
|
|
37
|
+
version: '12.0'
|
|
36
38
|
type: :development
|
|
37
39
|
prerelease: false
|
|
38
40
|
version_requirements: !ruby/object:Gem::Requirement
|
|
39
41
|
requirements:
|
|
40
42
|
- - "~>"
|
|
41
43
|
- !ruby/object:Gem::Version
|
|
42
|
-
version: '
|
|
44
|
+
version: '12.0'
|
|
43
45
|
- !ruby/object:Gem::Dependency
|
|
44
46
|
name: rspec
|
|
45
47
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -115,17 +117,21 @@ email:
|
|
|
115
117
|
- thibault@capsens.eu
|
|
116
118
|
- nicolas.besnard@capsens.eu
|
|
117
119
|
- younes.serraj@gmail.com
|
|
120
|
+
- antoine@capsens.eu
|
|
121
|
+
- jerome@capsens.eu
|
|
118
122
|
executables: []
|
|
119
123
|
extensions: []
|
|
120
124
|
extra_rdoc_files: []
|
|
121
125
|
files:
|
|
126
|
+
- ".circleci/config.yml"
|
|
122
127
|
- ".gitignore"
|
|
123
|
-
- ".gitlab-ci.yml"
|
|
124
128
|
- ".rspec"
|
|
125
129
|
- ".rubocop.yml"
|
|
126
130
|
- ".ruby-gemset"
|
|
127
131
|
- ".ruby-version"
|
|
128
132
|
- ".travis.yml"
|
|
133
|
+
- CHANGELOG.md
|
|
134
|
+
- CODE_OF_CONDUCT.md
|
|
129
135
|
- CapSens_Loan.xlsx
|
|
130
136
|
- Gemfile
|
|
131
137
|
- LICENSE.txt
|
|
@@ -144,9 +150,10 @@ files:
|
|
|
144
150
|
- lib/loan_creator/standard.rb
|
|
145
151
|
- lib/loan_creator/term.rb
|
|
146
152
|
- lib/loan_creator/timetable.rb
|
|
153
|
+
- lib/loan_creator/uncapitalized_bullet.rb
|
|
147
154
|
- lib/loan_creator/version.rb
|
|
148
155
|
- loan_creator.gemspec
|
|
149
|
-
homepage: https://
|
|
156
|
+
homepage: https://github.com/CapSens/loan-creator
|
|
150
157
|
licenses:
|
|
151
158
|
- MIT
|
|
152
159
|
metadata: {}
|
|
@@ -165,8 +172,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
165
172
|
- !ruby/object:Gem::Version
|
|
166
173
|
version: '0'
|
|
167
174
|
requirements: []
|
|
168
|
-
|
|
169
|
-
rubygems_version: 2.5.2.3
|
|
175
|
+
rubygems_version: 3.1.2
|
|
170
176
|
signing_key:
|
|
171
177
|
specification_version: 4
|
|
172
178
|
summary: Create and update timetables from input data
|
data/.gitlab-ci.yml
DELETED