244 lines
9.1 KiB
Python
244 lines
9.1 KiB
Python
from flask import Flask, render_template, request, redirect, url_for
|
|
import json
|
|
from decimal import *
|
|
from datetime import *
|
|
from jinja2 import Environment, FileSystemLoader
|
|
from fpdf import FPDF, HTMLMixin
|
|
import smtplib
|
|
|
|
from email.MIMEMultipart import MIMEMultipart
|
|
from email.MIMEText import MIMEText
|
|
from email.MIMEBase import MIMEBase
|
|
from email import Encoders
|
|
|
|
app = Flask(__name__)
|
|
|
|
@app.route('/')
|
|
def hello():
|
|
|
|
loans = []
|
|
loans.append( addLoan("1 Greenfield Lane Mortgage", "greenfield_mortgage.json" ) )
|
|
loans.append( addLoan("2 Bear Houses LLC Loan", "9Kloan.json" ) )
|
|
loans.append( addLoan("3 Brenda Mortgage", "brendamortgage.json" ) )
|
|
loans.append( addLoan("4 Dad Mortgage", "dadmortgage.json") )
|
|
|
|
if 'loan' in request.args:
|
|
filename = request.args["loan"]
|
|
else:
|
|
return redirect('/?loan=' + loans[0]['filename'])
|
|
|
|
loan = loadLoanInformation('/Users/john/PycharmProjects/mortgage/' + filename)
|
|
amortizeLoan(loan)
|
|
|
|
return render_template('main.html', filename=filename, loans=loans, model=loan)
|
|
|
|
@app.route('/update_file')
|
|
def update_file():
|
|
return
|
|
|
|
@app.route('/send_statement', methods=['POST'])
|
|
def send_statement():
|
|
loan = request.form["loan"]
|
|
redirect( '/?loan=' + loan )
|
|
|
|
def addLoan(loanName, fileName):
|
|
x = {}
|
|
x['name'] = loanName
|
|
x['filename'] = fileName
|
|
return x
|
|
|
|
'''from old code'''
|
|
def getStatementHeader(datastore):
|
|
return datastore['header']
|
|
|
|
|
|
def getEmailInformation(datastore):
|
|
return datastore['email']
|
|
|
|
|
|
def loadLoanInformation(filename):
|
|
datastore = getDatastore(filename)
|
|
|
|
loanModel = {}
|
|
loanModel['datastore'] = datastore
|
|
loanModel['email'] = getEmailInformation(datastore)
|
|
loanModel['parameters'] = getLoanParameters(datastore)
|
|
loanModel['lender'] = getLender(datastore)
|
|
loanModel['borrower'] = getBorrower(datastore)
|
|
loanModel['header'] = getStatementHeader(datastore)
|
|
return loanModel
|
|
|
|
|
|
def getLoanParameters(datastore):
|
|
# read in the loan profile information
|
|
loan = datastore['parameters']
|
|
|
|
annual_rate = Decimal(loan['interest_rate']) / 100
|
|
daily_interest_rate = annual_rate / 360
|
|
principal = Decimal(loan["principal"]).quantize(Decimal("1.00"))
|
|
periods_per_year = Decimal(loan["periods_per_year"])
|
|
total_periods = Decimal(loan["periods"])
|
|
payment_day_of_month = int(loan['payment_day_of_month'])
|
|
|
|
if "monthly_payment" in loan:
|
|
monthly_payment = Decimal(loan["monthly_payment"]).quantize(Decimal("1.00"))
|
|
else:
|
|
# calculate expected monthly payment
|
|
periodic_rate = annual_rate / periods_per_year
|
|
discount_factor = (((1 + periodic_rate) ** total_periods) - 1) / (
|
|
periodic_rate * ((1 + periodic_rate) ** total_periods))
|
|
monthly_payment = (principal / discount_factor).quantize(Decimal("1.00"))
|
|
|
|
loan['principal'] = principal # standardizes the format
|
|
loan['annual_rate'] = annual_rate # standardizes the format
|
|
loan['daily_interest_rate'] = daily_interest_rate
|
|
loan['rate'] = '' + (annual_rate * 100).__str__() + '%'
|
|
loan['next_payment_amt'] = 0
|
|
loan['next_payment_date'] = '12/12/12'
|
|
loan['total_periods'] = total_periods
|
|
loan['monthly_payment'] = monthly_payment
|
|
datastore['parameters'] = loan
|
|
return loan
|
|
|
|
|
|
def getLender(datastore):
|
|
return datastore['lender']
|
|
|
|
|
|
def getBorrower(datastore):
|
|
return datastore['borrower']
|
|
|
|
|
|
def getDatastore(filename=None):
|
|
try:
|
|
if filename:
|
|
with open(filename, 'r') as f:
|
|
datastore = json.load(f)
|
|
|
|
except Exception as e:
|
|
print "An error occurred opening your loan file '%s'. " % filename
|
|
print "The Exception:"
|
|
print e.__repr__()
|
|
quit()
|
|
|
|
return datastore
|
|
|
|
|
|
def amortizeLoan(loan):
|
|
# loop over the payments and calculate the actual amortization
|
|
monthly_payment = loan["parameters"]["monthly_payment"]
|
|
|
|
actual_payments = loan["datastore"]["payments"]
|
|
|
|
remaining_principal = loan["parameters"]["principal"]
|
|
payment_day_of_month = int(loan["parameters"]["payment_day_of_month"])
|
|
daily_interest_rate = loan["parameters"]["daily_interest_rate"]
|
|
total_periods = loan["parameters"]["total_periods"]
|
|
interest_paid_through_date = datetime.strptime(loan["parameters"]["start_interest_date"], "%Y-%m-%d").date()
|
|
next_payment_date = datetime.strptime(loan["parameters"]["first_payment_month"], '%Y-%m-%d').date()
|
|
next_bill_date = date(year=next_payment_date.year, month=next_payment_date.month, day=payment_day_of_month)
|
|
|
|
payment_number = 1
|
|
annual_interest = 0
|
|
total_interest = 0
|
|
old_bill_date = next_bill_date
|
|
current_year = next_bill_date.year
|
|
|
|
past_payments = []
|
|
future_payments = []
|
|
|
|
for payment in actual_payments:
|
|
payment_date = datetime.strptime((payment[0]), '%Y-%m-%d').date()
|
|
payment_amount = Decimal(payment[1]).quantize(Decimal("1.00"))
|
|
days_since_last_payment = (payment_date - interest_paid_through_date).days
|
|
|
|
#check for out of order payments, generally a sign of a data entry problem, especially years
|
|
if days_since_last_payment < 0:
|
|
print "Payment Number %s appears out of order. The payment date '%s' is before the previous payment on '%s'." \
|
|
% (payment_number, payment_date, interest_paid_through_date)
|
|
quit()
|
|
|
|
new_interest = (days_since_last_payment * remaining_principal * daily_interest_rate).quantize(Decimal("0.00"))
|
|
new_principal = payment_amount - new_interest
|
|
interest_paid_through_date = payment_date
|
|
total_interest = total_interest + new_interest
|
|
annual_interest = annual_interest + new_interest
|
|
remaining_principal = remaining_principal - new_principal
|
|
|
|
|
|
# create the payment record for the template to render
|
|
payment_record = {}
|
|
payment_record['year']=next_bill_date.year
|
|
payment_record['month']=next_bill_date.month
|
|
payment_record['payment_number'] = payment_number
|
|
payment_record['bill_date'] = next_bill_date
|
|
payment_record['payment_date'] = payment_date
|
|
payment_record['days_of_interest'] = days_since_last_payment
|
|
payment_record['payment_amount'] = payment_amount
|
|
payment_record['principal_payment'] = payment_amount - new_interest
|
|
payment_record['interest_payment'] = new_interest
|
|
payment_record['new_balance'] = remaining_principal
|
|
payment_record['interest_to_date'] = total_interest
|
|
payment_record['annual_interest_to_date'] = annual_interest
|
|
past_payments.append(payment_record)
|
|
|
|
payment_number = payment_number + 1
|
|
old_bill_date = next_bill_date
|
|
|
|
if old_bill_date.month < 12:
|
|
next_bill_date = date(year=old_bill_date.year, month=old_bill_date.month + 1, day=payment_day_of_month)
|
|
else:
|
|
annual_interest = Decimal("0.00")
|
|
next_bill_date = date(year=old_bill_date.year + 1, month=1, day = payment_day_of_month)
|
|
|
|
loan["total_interest_paid_to_date"] = total_interest
|
|
loan["parameters"]["next_due_date"] = next_bill_date
|
|
|
|
if (remaining_principal < monthly_payment):
|
|
loan["parameters"]["next_payment_amt"] = remaining_principal
|
|
else:
|
|
loan["parameters"]["next_payment_amt"] = monthly_payment
|
|
|
|
# loop over remaining scheduled payments and present estimated amortization
|
|
while (payment_number <= total_periods) and (remaining_principal > 0):
|
|
days_since_last_payment = (next_bill_date - interest_paid_through_date).days
|
|
new_interest = (days_since_last_payment * remaining_principal * daily_interest_rate).quantize(Decimal("0.00"))
|
|
|
|
# make sure the last payment isn't too much
|
|
if new_interest + remaining_principal < monthly_payment:
|
|
monthly_payment = new_interest + remaining_principal
|
|
|
|
new_principal = monthly_payment - new_interest
|
|
|
|
remaining_principal = remaining_principal - new_principal
|
|
|
|
interest_paid_through_date = next_bill_date
|
|
|
|
# complete the future payment amortization record
|
|
future_payment_record = {}
|
|
future_payment_record['payment_number'] = payment_number
|
|
future_payment_record['payment_date'] = next_bill_date
|
|
future_payment_record['days_of_interest'] = days_since_last_payment
|
|
future_payment_record['payment_amount'] = monthly_payment
|
|
future_payment_record['principal_payment'] = new_principal
|
|
future_payment_record['interest_payment'] = new_interest
|
|
future_payment_record['new_balance'] = remaining_principal
|
|
future_payments.append(future_payment_record)
|
|
|
|
payment_number = payment_number + 1
|
|
old_bill_date = next_bill_date
|
|
if old_bill_date.month < 12:
|
|
next_bill_date = date(year=old_bill_date.year, month=old_bill_date.month + 1, day=payment_day_of_month)
|
|
else:
|
|
next_bill_date = date(year=old_bill_date.year + 1, month=1, day=payment_day_of_month)
|
|
|
|
|
|
loan["balloon_payment"] = remaining_principal
|
|
loan["past_payments"] = past_payments
|
|
loan["future_payments"] = future_payments
|
|
return
|
|
|
|
|
|
if __name__ == '__main__':
|
|
app.debug = True
|
|
app.run() |