Created
June 14, 2017 04:25
-
-
Save bomatson/eefe4ead1ac3720a2c0c0e264ddc4573 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| defmodule LoanSchedule do | |
| def perform(apr, monthly_payment, balance) do | |
| schedule = calculate(apr, monthly_payment, balance, 0, %{}) | |
| total_payments = Map.keys(schedule) |> Enum.max | |
| total_paid = Map.values(schedule) |> Enum.reduce(0, fn(loan, acc) -> loan[:monthly_payment] + acc end) | |
| [ | |
| payment_schedule: schedule, | |
| loan_details: %{ | |
| apr: apr, | |
| monthly_payment: monthly_payment, | |
| initial_balance: balance, | |
| total_payments: total_payments, | |
| total_paid: total_paid | |
| } | |
| ] | |
| end | |
| def calculate(apr, monthly_payment, balance, payments, schedule_map) when balance < monthly_payment do | |
| IO.puts "We are there! Last payment of: #{balance}" | |
| IO.puts "We've made #{payments + 1} payments" | |
| monthly_interest_payment = ((apr / 12) * balance) | |
| current_payment_period = payments + 1 | |
| final_payment = balance + monthly_interest_payment | |
| total_paid = (payments * monthly_payment) + final_payment | |
| current_period = [ | |
| current_balance: 0, | |
| total_paid: total_paid, | |
| principal_payment: balance, | |
| interest_payment: monthly_interest_payment, | |
| current_payment_period: current_payment_period, | |
| monthly_payment: final_payment | |
| ] | |
| Map.put(schedule_map, current_payment_period, current_period) | |
| end | |
| def calculate(apr, monthly_payment, balance, payments, schedule_map) do | |
| %{interest: interest_payment, principal: principal_payment} = current_payments(apr, balance, monthly_payment) | |
| if principal_payment < 0 do | |
| raise "You can't pay this loan. Your minimum payment must be higher than #{interest_payment}" | |
| end | |
| if principal_payment == 0 do | |
| raise "You are paying just below the minimum payment" | |
| end | |
| current_payment_period = payments + 1 | |
| next_month_balance = balance - principal_payment | |
| total_paid = current_payment_period * monthly_payment | |
| current_period = [ | |
| apr: apr, | |
| current_balance: next_month_balance, | |
| total_paid: total_paid, | |
| principal_payment: principal_payment, | |
| interest_payment: interest_payment, | |
| current_payment_period: current_payment_period, | |
| monthly_payment: monthly_payment | |
| ] | |
| new_payment_schedule = Map.put(schedule_map, current_payment_period, current_period) | |
| calculate(apr, monthly_payment, next_month_balance, current_payment_period, new_payment_schedule) | |
| end | |
| def current_payments(apr, balance, monthly_payment) do | |
| monthly_interest_payment = ((apr / 12) * balance) | |
| monthly_principal_payment = monthly_payment - monthly_interest_payment | |
| %{ | |
| interest: monthly_interest_payment, | |
| principal: monthly_principal_payment | |
| } | |
| end | |
| end |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
An example use case, with a $10,000 loan, monthly payments of $1,000 and 5% APR:
Here, the
loan_detailsprovide an actualtotal_paidvalue of how much that loan actually costs over time.The
payment_schedulemap describes each payment record that is made each month, as well as how much each payment contributed to interest vs principal on the loan.