Class: Amortizy::Disclosure
- Inherits:
-
Object
- Object
- Amortizy::Disclosure
- Defined in:
- lib/amortizy/disclosure.rb
Constant Summary collapse
- APR_MAX_ITERATIONS =
100- APR_CONVERGENCE_TOLERANCE =
1e-8- APR_REG_Z_TOLERANCE =
1/8 of 1 percentage point
0.00125
Instance Method Summary collapse
-
#amount_financed ⇒ Object
— Amount Financed (§900(a)(1)(B)) — Principal + financed amounts - prepaid finance charges (origination fee).
-
#apr ⇒ Object
— APR (§940) — Actuarial method per Appendix J, Regulation Z (12 CFR Part 1026).
-
#average_monthly_cost ⇒ Object
— Average Monthly Cost (§910(a)(12)) — Only for non-monthly payment frequencies.
-
#finance_charge ⇒ Object
— Finance Charge (§943) — Total dollar cost of the financing.
-
#initialize(schedule, third_party_payments: 0, prepayment_penalty_max: 0, additional_prepayment_fees: []) ⇒ Disclosure
constructor
A new instance of Disclosure.
-
#payment_amount ⇒ Object
— Payment Amount —.
-
#payment_frequency ⇒ Object
— Payment Frequency —.
-
#prepayment ⇒ Object
— Prepayment (§910(a)(8-10)) —.
-
#recipient_funds ⇒ Object
— Recipient Funds (§900(a)(26)) — Net amount given directly to the borrower.
-
#term_days ⇒ Object
— Term (§901(a)(4)) —.
- #term_display ⇒ Object
-
#to_h ⇒ Object
— Output Methods —.
- #to_labeled_h ⇒ Object
-
#total_payment_amount ⇒ Object
— Total Payment Amount (§910(a)(5)) —.
Constructor Details
#initialize(schedule, third_party_payments: 0, prepayment_penalty_max: 0, additional_prepayment_fees: []) ⇒ Disclosure
Returns a new instance of Disclosure.
31 32 33 34 35 36 37 38 39 |
# File 'lib/amortizy/disclosure.rb', line 31 def initialize(schedule, third_party_payments: 0, prepayment_penalty_max: 0, additional_prepayment_fees: []) raise ArgumentError, 'First argument must be an Amortizy::AmortizationSchedule' unless schedule.is_a?(Amortizy::AmortizationSchedule) @schedule = schedule @third_party_payments = third_party_payments.to_f @prepayment_penalty_max = prepayment_penalty_max.to_f @additional_prepayment_fees = additional_prepayment_fees end |
Instance Method Details
#amount_financed ⇒ Object
— Amount Financed (§900(a)(1)(B)) — Principal + financed amounts - prepaid finance charges (origination fee).
53 54 55 56 57 58 59 |
# File 'lib/amortizy/disclosure.rb', line 53 def amount_financed @amount_financed ||= begin base = principal - origination_fee base += additional_fee if fee_treatment == :add_to_principal base end end |
#apr ⇒ Object
— APR (§940) — Actuarial method per Appendix J, Regulation Z (12 CFR Part 1026). Rounded to nearest 10 basis points per §901(a)(5).
119 120 121 122 123 124 |
# File 'lib/amortizy/disclosure.rb', line 119 def apr @apr ||= begin raw_apr = calculate_apr round_to_ten_basis_points(raw_apr) end end |
#average_monthly_cost ⇒ Object
— Average Monthly Cost (§910(a)(12)) — Only for non-monthly payment frequencies.
108 109 110 111 112 113 |
# File 'lib/amortizy/disclosure.rb', line 108 def average_monthly_cost return nil if @schedule.frequency == :monthly return nil if term_days <= 0 total_payment_amount / (term_days / 30.4) end |
#finance_charge ⇒ Object
— Finance Charge (§943) — Total dollar cost of the financing. Derived from the Reg Z identity:
Finance Charge = Total Payment Amount - Amount Financed
This ensures the three core disclosure values are always consistent.
46 47 48 |
# File 'lib/amortizy/disclosure.rb', line 46 def finance_charge @finance_charge ||= total_payment_amount - amount_financed end |
#payment_amount ⇒ Object
— Payment Amount —
69 70 71 |
# File 'lib/amortizy/disclosure.rb', line 69 def payment_amount @schedule.payment_amount end |
#payment_frequency ⇒ Object
— Payment Frequency —
75 76 77 |
# File 'lib/amortizy/disclosure.rb', line 75 def payment_frequency @schedule.frequency end |
#prepayment ⇒ Object
— Prepayment (§910(a)(8-10)) —
128 129 130 131 132 133 134 135 |
# File 'lib/amortizy/disclosure.rb', line 128 def prepayment @prepayment ||= { has_non_interest_charges: @prepayment_penalty_max.positive?, max_non_interest_finance_charge: @prepayment_penalty_max.positive? ? @prepayment_penalty_max : nil, has_additional_fees: @additional_prepayment_fees.any?, additional_fees: @additional_prepayment_fees } end |
#recipient_funds ⇒ Object
— Recipient Funds (§900(a)(26)) — Net amount given directly to the borrower.
82 83 84 |
# File 'lib/amortizy/disclosure.rb', line 82 def recipient_funds amount_financed - @third_party_payments end |
#term_days ⇒ Object
— Term (§901(a)(4)) —
88 89 90 |
# File 'lib/amortizy/disclosure.rb', line 88 def term_days @term_days ||= (@schedule.end_date - disbursement_date).to_i end |
#term_display ⇒ Object
92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/amortizy/disclosure.rb', line 92 def term_display if term_days <= 365 "#{term_days} days" else years = term_days / 365 remaining_days = term_days % 365 months = (remaining_days / 30.4).round(2) year_label = years == 1 ? 'year' : 'years' month_label = (months - 1.0).abs < 0.005 ? 'month' : 'months' format('%d %s, %.2f %s', years, year_label, months, month_label) end end |
#to_h ⇒ Object
— Output Methods —
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/amortizy/disclosure.rb', line 139 def to_h { amount_financed: amount_financed.round(2), apr: apr, finance_charge: finance_charge.round(2), total_payment_amount: total_payment_amount.round(2), payment_amount: payment_amount.round(2), payment_frequency: payment_frequency, term_days: term_days, term_display: term_display, average_monthly_cost: average_monthly_cost&.round(2), recipient_funds: recipient_funds.round(2), prepayment: prepayment } end |
#to_labeled_h ⇒ Object
155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/amortizy/disclosure.rb', line 155 def to_labeled_h { amount_financed: { label: 'Funding Provided', value: amount_financed.round(2) }, apr: { label: 'Annual Percentage Rate (APR)', value: apr }, finance_charge: { label: 'Finance Charge', value: finance_charge.round(2) }, total_payment_amount: { label: 'Total Payment Amount', value: total_payment_amount.round(2) }, payment_amount: { label: 'Payment', value: payment_amount.round(2) }, payment_frequency: { label: 'Payment Frequency', value: payment_frequency }, term_days: { label: 'Term', value: term_display }, average_monthly_cost: { label: 'Average Monthly Cost', value: average_monthly_cost&.round(2) }, recipient_funds: { label: 'Recipient Funds', value: recipient_funds.round(2) }, prepayment: prepayment } end |
#total_payment_amount ⇒ Object
— Total Payment Amount (§910(a)(5)) —
63 64 65 |
# File 'lib/amortizy/disclosure.rb', line 63 def total_payment_amount @schedule.total_paid end |