Created
June 14, 2017 04:25
-
-
Save bomatson/eefe4ead1ac3720a2c0c0e264ddc4573 to your computer and use it in GitHub Desktop.
This file contains 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 |
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_details
provide an actualtotal_paid
value of how much that loan actually costs over time.The
payment_schedule
map describes each payment record that is made each month, as well as how much each payment contributed to interest vs principal on the loan.