Updated all of the payment files to reflect new format. Updated the PDF generation template. Updated the email sending code. Fixed a few off by one errors when the last payment also is the last payment of the year.

This commit is contained in:
JohnKent
2019-01-06 16:39:54 -05:00
parent e274b96672
commit 45d6e32149
7 changed files with 409 additions and 191 deletions

63
10Kloan.json Normal file
View File

@@ -0,0 +1,63 @@
{
"htmlTemplate": "statement.pdf.jinja",
"txtTemplate": "statement.txt.jinja",
"format": "html",
"email": {
"from_address": "jkent3rd@gmail.com",
"to_address": "grady@gradystreet.com",
"server": "smtp.gmail.com",
"password": "pvyrbcnzrjoizprn",
"template": "./template.txt",
"send_pdf": "true",
"send_text": "true",
"subject": "Your loan statement...",
"body": "Your loan statement is attached.",
"text": "Please see your most recent account statement."
},
"parameters": {
"account_number": "100100",
"principal": 10020.00,
"interest_rate": 6.5,
"periods_per_year": 12,
"periods": 18,
"start_date": "2017-12-05",
"start_interest_date": "2017-12-05",
"first_payment_month": "2018-01-15",
"monthly_payment": 589.00,
"payment_day_of_month": "15"
},
"payments": [
["2018-01-16", "589.00"],
["2018-03-30", "589.00"],
["2018-04-06", "589.00"],
["2018-04-12", "589.00"],
["2018-05-28", "589.00"],
["2018-06-12", "589.00"],
["2018-07-13", "589.00"],
["2018-08-14", "589.00"],
["2018-09-26", "589.00"],
["2018-10-15", "0"],
["2018-11-29", "589.00"],
["2018-12-31", "589.00"]
],
"borrower": {
"name": "Bear Houses, LLC",
"address": "301 N Beauregard St Apt 203",
"city": "Alexandria",
"state": "VA",
"zip": "22312"
},
"lender": {
"name": "John Kent",
"phone": "703.343.0782",
"address": "743 Madison St NW",
"city": "Washington",
"state": "DC",
"zip": "20011"
},
"header": {
"title": "Installment Loan Statement",
"date": "Today"
}
}

56
brendamortgage.json Normal file
View File

@@ -0,0 +1,56 @@
{
"htmlTemplate": "statement.pdf.jinja",
"txtTemplate": "statement.txt.jinja",
"format": "html",
"email": {
"from_address": "jkent3rd@gmail.com",
"to_address": "bck@virginia.edu",
"server": "smtp.gmail.com",
"password": "pvyrbcnzrjoizprn",
"template": "./template.txt",
"send_pdf": "true",
"send_text": "true",
"subject": "Your loan statement...",
"body": "Your loan statement is attached.",
"text": "Please see your most recent account statement."
},
"parameters": {
"account_number": "100001",
"principal": 35000.00,
"interest_rate": 5.0,
"periods_per_year": 12,
"periods": 180,
"start_date": "2018-06-25",
"start_interest_date": "2018-07-01",
"first_payment_month": "2018-08-01",
"monthly_payment": 278.15,
"payment_day_of_month": "01"
},
"borrower": {
"name": "Grandma Tina's Properties, LLC",
"address": "743 Madison St NW",
"city": "Washington",
"state": "DC",
"zip": "20011"
},
"lender": {
"name": "John Kent",
"phone": "434-510-7272",
"address": "109 Shores Rd",
"city": "Palmyra",
"state": "VA",
"zip": "22963"
},
"header": {
"title": "Mortgage Loan Statement - 185 James River Rd, Scottsville VA",
"date": "Today"
},
"payments": [
["2018-08-01", "278.15"],
["2018-09-01", "278.15"],
["2018-10-01", "278.15"],
["2018-11-01", "278.15"],
["2018-12-01", "278.15"],
["2019-01-01", "278.15"]
]
}

56
dadmortgage.json Normal file
View File

@@ -0,0 +1,56 @@
{
"htmlTemplate": "statement.pdf.jinja",
"txtTemplate": "statement.txt.jinja",
"format": "html",
"email": {
"from_address": "jkent3rd@gmail.com",
"to_address": "johnkent49@gmail.com",
"server": "smtp.gmail.com",
"password": "pvyrbcnzrjoizprn",
"template": "./template.txt",
"send_pdf": "true",
"send_text": "true",
"subject": "Your loan statement...",
"body": "Your loan statement is attached.",
"text": "Please see your most recent account statement."
},
"parameters": {
"account_number": "100001",
"principal": 35000.00,
"interest_rate": 5.0,
"periods_per_year": 12,
"periods": 180,
"start_date": "2018-06-25",
"start_interest_date": "2018-07-01",
"first_payment_month": "2018-08-01",
"monthly_payment": 278.15,
"payment_day_of_month": "01"
},
"borrower": {
"name": "Grandma Tina's Properties, LLC",
"address": "743 Madison St NW",
"city": "Washington",
"state": "DC",
"zip": "20011"
},
"lender": {
"name": "John Kent",
"phone": "434-510-7272",
"address": "109 Shores Rd",
"city": "Palmyra",
"state": "VA",
"zip": "22963"
},
"header": {
"title": "Mortgage Loan Statement - 185 James River Rd, Scottsville VA",
"date": "Today"
},
"payments": [
["2018-08-01", "278.15"],
["2018-09-01", "278.15"],
["2018-10-01", "278.15"],
["2018-11-01", "278.15"],
["2018-12-01", "278.15"],
["2019-01-01", "278.15"]
]
}

63
greenfield_mortgage.json Normal file
View File

@@ -0,0 +1,63 @@
{
"htmlTemplate": "statement.pdf.jinja",
"txtTemplate": "statement.txt.jinja",
"format": "html",
"email": {
"from_address": "jkent3rd@gmail.com",
"to_address": "grady@gradystreet.com",
"server": "smtp.gmail.com",
"password": "pvyrbcnzrjoizprn",
"template": "./template.txt",
"send_pdf": "true",
"send_text": "true",
"subject": "Your loan statement...",
"body": "Your loan statement is attached.",
"text": "Please see your most recent account statement."
},
"parameters": {
"account_number": "100001",
"principal": 97750.00,
"interest_rate": 5.5,
"periods_per_year": 12,
"periods": 182,
"start_date": "2017-11-07",
"start_interest_date": "2017-11-11",
"first_payment_month": "2017-12-15",
"monthly_payment": 803.00,
"payment_day_of_month": "15"
},
"payments": [
["2017-12-11", "803.00"],
["2018-01-23", "803.00"],
["2018-03-23", "803.00"],
["2018-04-18", "803.00"],
["2018-04-26", "803.00"],
["2018-05-15", "0.00"],
["2018-06-15", "0.00"],
["2018-07-12", "803.00"],
["2018-08-07", "803.00"],
["2018-09-06", "803.00"],
["2018-10-11", "803.00"],
["2018-11-13", "803.00"],
["2018-12-13", "803.00"]
],
"borrower": {
"name": "Bear Houses, LLC",
"address": "301 N Beauregard St Apt 203",
"city": "Alexandria",
"state": "VA",
"zip": "22312"
},
"lender": {
"name": "Rivanna Graphite Investments, LLC",
"phone": "703.343.0782",
"address": "743 Madison St NW",
"city": "Washington",
"state": "DC",
"zip": "20011"
},
"header": {
"title": "Mortgage Loan Statement - 195 Greenfield Lane, Pearl MS",
"date": "Today"
}
}

View File

@@ -1,25 +0,0 @@
{
"principal": 97750.00,
"interest rate": 5.5,
"periods per year": 12,
"periods": 182,
"start date": "2017-11-07",
"start_interest_date": "2017-11-11",
"first payment month": "2017-12-15",
"monthly_payment": 803.00,
"payment day of month": "15",
"payments": [
["2017-12-11", "803.00"],
["2018-01-23", "803.00"],
["2018-03-23", "803.00"],
["2018-04-18", "803.00"],
["2018-04-26", "803.00"],
["2018-05-15", "0.00"],
["2018-06-15", "0.00"],
["2018-07-12", "803.00"],
["2018-08-07", "803.00"],
["2018-09-06", "803.00"],
["2018-10-11", "803.00"],
["2018-11-13", "803.00"]
]
}

View File

@@ -4,45 +4,47 @@ 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
def getPaymentHistory(datastore, loan, asOfDate):
pass
def getStatementHeader(datastore):
return datastore['header']
def getAmortization(datastore, loan, paymentHistory):
pass
def getEmailInformation(datastore):
return datastore['email']
def loadLoanInformation(filename):
datastore = getDatastore(filename)
loanModel = {}
loanModel['loan'] = getLoan(datastore)
loanModel = {}
loanModel['datastore'] = datastore
loanModel['email'] = getEmailInformation(datastore)
loanModel['parameters'] = getLoanParameters(datastore)
loanModel['lender'] = getLender(datastore)
loanModel['borrower'] = getBorrower(datastore)
loanModel['paymentHistory'] = getPaymentHistory(datastore, loan, asOfDate)
loanModel['futureAmortization'] = getAmortization(datastore, loan, loanModel.paymentHistory)
loanModel['header'] = getStatementHeader(datastore)
return loanModel
def getLoan(datastore):
def getLoanParameters(datastore):
# read in the loan profile information
loan = {}
loan = datastore['parameters']
annual_rate = Decimal(datastore['loan.interest rate']) / 100
annual_rate = Decimal(loan['interest_rate']) / 100
daily_interest_rate = annual_rate / 360
principal = Decimal(datastore["loan.principal"]).quantize(Decimal("1.00"))
periods_per_year = Decimal(datastore["loan.periods per year"])
total_periods = Decimal(datastore["loan.periods"])
payment_day_of_month = int(datastore['loan.payment day of month'])
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 datastore:
monthly_payment = Decimal(datastore["monthly_payment"]).quantize(Decimal("1.00"))
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
@@ -50,38 +52,24 @@ def getLoan(datastore):
periodic_rate * ((1 + periodic_rate) ** total_periods))
monthly_payment = (principal / discount_factor).quantize(Decimal("1.00"))
loan['loan.account_number'] = '123456789'
loan['principal'] = principal
loan['term'] = total_periods
loan['annual_rate'] = annual_rate
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):
lender = {}
# to be replaced with real loading code
lender['name'] = 'Rivanna Graphite Investments, LLC'
lender['phone'] = '703.343.0782'
lender['address'] = '743 Madison St NW'
lender['city'] = 'Washington'
lender['state'] = 'DC'
lender['zip'] = '20011'
return getLender
return datastore['lender']
def getBorrower(datastore):
borrower = {}
# to be replaced with real loading code
borrower['name'] = 'Bear Houses, LLC'
borrower['address'] = '123 Any Street'
borrower['city'] = 'Alltown'
borrower['state'] = 'VA'
borrower['zip'] = '11111'
return borrower
return datastore['borrower']
def getDatastore(filename=None):
@@ -91,7 +79,7 @@ def getDatastore(filename=None):
datastore = json.load(f)
except Exception as e:
print "An error occurred opening your loan file '#s'. " % filename
print "An error occurred opening your loan file '%s'. " % filename
print "The Exception:"
print e.__repr__()
quit()
@@ -99,109 +87,29 @@ def getDatastore(filename=None):
return datastore
def calculateLoanAmortization(loanModel):
return loanModel
def transformTemplate(template_fileName, loanModel):
# template_filename = "statement.txt.jinja"
# setup jinja for creating the statement
env = Environment(loader=FileSystemLoader('.'))
template = env.get_template(template_fileName)
report = template.render(original_principal_balance=loanModel.principal, future_payments=loanModel.future_payments,
past_payments=loanModel.past_payments, balloon_payment=loanModel.remaining_principal,
total_interest_paid_to_date=loanModel.total_interest, statement=loanModel.statement)
return report
def generatePDFStatement():
template_filename = "statement.pdf.jinja"
pass
def generateHTMLStatement():
pass
def generateTextStatement():
pass
def generateEmail(from_address, to_address, subject, body, attachment):
msg = MIMEMultipart()
msg['Subject'] = subject
msg['From'] = from_address
msg['To'] = to_address
msg.attach(MIMEText(body))
part = MIMEBase('application', "octet-stream")
part.set_payload(attachment)
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="statement.pdf"')
msg.attach(part)
return msg
def main():
# this program reads the json file describing a mortgage and calculate the actual and projected amortization
# the first payment in the file should be the interest paid at closing
# the interest at closing covers interest that would be incurred from the date of closing until the first day
# that will be covered by the first loan payment
# i.e., the first loan payment is expected a month and a half after closing, the first two weeks interest is due
# at closing. The first payment will incur interest from one month before the bill is due.
from_address = 'jkent3rd@gmail.com'
passwd = "pvyrbcnzrjoizprn"
subject = "Mortgage or Loan Statement"
to_address = 'jkent3rd@gmail.com'
body = 'This email contains a PDF of your mortgage statement.'
# read in the file
# filename = "./10Kloan.txt"
# filename = "./10Kloan.test.txt"
# filename = "./dadmortgage.txt"
# filename = "./brendamortgage.txt"
filename = "./greenfield_mortgage.txt"
template_filename = "statement.pdf.jinja"
loanInformation = loadLoanInformation(filename)
loanModel = calculateLoanAmortization(loanInformation)
# read in the statement information
statement, lender, borrower, loan = {}, {}, {}, {}
lender = loanModel.lender
borrower = loanModel.borrower
past_payments = loanModel.past_payments
future_payments = loanModel.future_payments
statement['title'] = "Mortgage Statement - 185 James River Rd"
statement['date'] = "Today"
statement['lender'] = lender
statement['borrower'] = borrower
statement['loan'] = loan
def amortizeLoan(loan):
# loop over the payments and calculate the actual amortization
actual_payments = loanModel["payments"]
monthly_payment = loan["parameters"]["monthly_payment"]
remaining_principal = loanModel.principal
payment_day_of_month = loanInformation.payment_day_of_month
daily_interest_rate = loanInformation.daily_interest_rate
total_periods = loanInformation.total_periods
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
interest_paid_through_date = datetime.strptime(loanModel["start_interest_date"], "%Y-%m-%d").date()
next_payment_date = datetime.strptime(loanModel["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)
old_bill_date = next_bill_date
payment_number = 1
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"))
@@ -232,6 +140,16 @@ def main():
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["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):
@@ -254,7 +172,7 @@ def main():
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_interest
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)
@@ -266,8 +184,68 @@ def main():
else:
next_bill_date = date(year=old_bill_date.year + 1, month=1, day=payment_day_of_month)
report = transformTemplate('', loanModel)
loan["balloon_payment"] = remaining_principal
loan["past_payments"] = past_payments
loan["future_payments"] = future_payments
return
def transformTemplate(template_fileName, loanModel):
# template_filename = "statement.txt.jinja"
# setup jinja for creating the statement
env = Environment(loader=FileSystemLoader('.'))
template = env.get_template(template_fileName)
print loanModel
report = template.render(model=loanModel)
return report
def generatePDFAttachment():
template_filename = "statement.pdf.jinja"
pass
def generateEmail(from_address, to_address, subject, body, pdfAttachment, txtAttachment):
msg = MIMEMultipart()
msg['Subject'] = subject
msg['From'] = from_address
msg['To'] = to_address
msg.attach(MIMEText(body))
if (pdfAttachment != None):
part = MIMEBase("application", "octet-stream")
part.set_payload(pdfAttachment)
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="statement.pdf"')
msg.attach(part)
if (txtAttachment != None):
part = MIMEBase("text", "html")
part.set_payload(txtAttachment)
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="statement.html"')
msg.attach(part)
return msg
def sendEmail(msg, from_address, to_address, passwd):
try:
server = smtplib.SMTP('smtp.gmail.com', 587)
server.ehlo()
server.starttls()
server.login(from_address, passwd)
server.sendmail(from_address, to_address, msg.as_string())
server.close()
except:
print "Couldn't send email."
def createPDF(report):
# create pdf
class MyFPDF(FPDF, HTMLMixin):
pass
@@ -277,22 +255,49 @@ def main():
pdf.add_page()
pdf.write_html(report)
# pdf.output(name='test.pdf', dest='F')
attachment = pdf.output(dest='S')
return pdf.output(dest='S')
def selectTemplate(loan):
templateKey = loan["datastore"]["format"] + "Template"
if templateKey in loan:
template = loan[templateKey]
else:
template = 'statement.pdf.jinja'
return template
def main():
# this program reads the json file describing a mortgage and calculate the actual and projected amortization
# the first payment in the file should be the interest paid at closing
# the interest at closing covers interest that would be incurred from the date of closing until the first day
# that will be covered by the first loan payment
# i.e., the first loan payment is expected a month and a half after closing, the first two weeks interest is due
# at closing. The first payment will incur interest from one month before the bill is due.
# read in the file
# filename = "./10Kloan.txt"
#filename = "./10Kloan.json"
# filename = "./dadmortgage.json"
# filename = "./brendamortgage.json"
filename = "./greenfield_mortgage.json"
template_filename = "statement.pdf.jinja"
loan = loadLoanInformation(filename)
amortizeLoan(loan)
report = transformTemplate(selectTemplate(loan), loan)
if loan["email"]["send_pdf"] == "true":
pdfAttachment = createPDF(report)
# send email
try:
server = smtplib.SMTP('smtp.gmail.com', 587)
server.ehlo()
server.starttls()
server.login(from_address, passwd)
email = generateEmail(from_address, to_address, subject, body, attachment)
server.sendmail(from_address, to_address, email.as_string())
server.close()
except:
print "Couldn't send email, dumping statement to file."
pdf.output(name='test.pdf', dest='F')
quit()
emailParameters = loan["email"]
msg = generateEmail(emailParameters["from_address"], emailParameters["to_address"], emailParameters["subject"],
emailParameters["body"], pdfAttachment, report)
sendEmail(msg, emailParameters["from_address"], emailParameters["to_address"], emailParameters['password'])
if __name__ == '__main__':

View File

@@ -1,22 +1,22 @@
<html>
<body>
<font face='arial' size='14'><p align='center'>{{ statement.title }}</p></font>
<font face='arial' size='10'><p align='center'>{{ statement.lender.name }}</p></font>
<font face='arial' size='14'><p align='center'>{{ model.header.title }}</p></font>
<font face='arial' size='10'><p align='center'>{{ model.lender.name }}</p></font>
<font face='arial' size='8'>
<p align='center'>{{ statement.lender.phone }} - {{ statement.lender.address }} -
{{ statement.lender.city }} {{statement.lender.state }} {{ statement.lender.zip }}</p>
<p align='right'>Statement Date: {{ statement.date }}</p>
<p align='center'>{{ model.lender.phone }} - {{ model.lender.address }} -
{{ model.lender.city }} {{model.lender.state }} {{ model.lender.zip }}</p>
<p align='right'>Statement Date: {{ model.header.date }}</p>
<p/>
<table>
<thead><tr><th width='45%' align='left'>Loan Information</th><th width='45%'>&nbsp;</th></tr></thead>
<tbody>
<tr><td>Borrower: {{ statement.borrower.name }}&nbsp;</td> <td>Account Number: {{ statement.loan.account_number }}</td></tr>
<tr><td>{{ statement.borrower.address }}&nbsp;</td> <td>Origination Date: {{ statement.loan.origination_date }}</td></tr>
<tr><td>{{ statement.borrower.city }}, {{statement.borrower.state }} {{ statement.borrower.zip }}</td>
<td>Original Principal: {{ "$%.2f"|format(statement.loan.principal) }}</td></tr>
<tr><td>Rate: {{statement.loan.rate }} </td> <td>Term: {{statement.loan.term }} months </td></tr>
<tr><td>Next Payment Due Date: {{statement.loan.next_due_date}} </td> <td>Payment Due: {{ "$%.2f"|format(statement.loan.next_payment_amt) }} </td></tr>
<tr><td>Borrower: {{ model.borrower.name }}&nbsp;</td> <td>Account Number: {{ model.parameters.account_number }}</td></tr>
<tr><td>{{ model.borrower.address }}&nbsp;</td> <td>Origination Date: {{ model.parameters.start_date }}</td></tr>
<tr><td>{{ model.borrower.city }}, {{model.borrower.state }} {{ model.borrower.zip }}</td>
<td>Original Principal: {{ "$%.2f"|format(model.parameters.principal) }}</td></tr>
<tr><td>Rate: {{model.parameters.interest_rate }}% </td> <td>Term: {{model.parameters.periods }} months </td></tr>
<tr><td>Next Payment Due Date: {{model.parameters.next_due_date}} </td> <td>Payment Due: {{ "$%.2f"|format(model.parameters.next_payment_amt) }} </td></tr>
</tbody>
</table>
<p/>
@@ -33,7 +33,7 @@
<th width='20%' align='right'>New Balance</th>
</tr></thead>
<tbody>
{% for item in past_payments %}
{% for item in model.past_payments %}
<tr><td align='center'> {{ item.payment_number }} </td>
<td align='center'> {{ item.bill_date }} </td>
<td align='center'> {{ item.payment_date }} </td>
@@ -49,7 +49,7 @@
{% endfor %}
</tbody>
</table>
<p>Total interest paid to date is {{ "$%.2f"|format(total_interest_paid_to_date) }}.</p>
<p>Total interest paid to date is {{ "$%.2f"|format(model.total_interest_paid_to_date) }}.</p>
<p/> <p/>
<p class='section_header'><font face='arial' size='14'>Remaining Amortization</font></p>
@@ -64,7 +64,7 @@
<th width='20%' align='right'>Principal Balance</th>
</tr></thead>
<tbody>
{% for item in future_payments %}
{% for item in model.future_payments %}
<tr><td align='center'> {{ item.payment_number }} </td>
<td align='center'> {{ item.payment_date }} </td>
<td align='center'> {{ item.days_of_interest }} </td>
@@ -76,7 +76,7 @@
{% endfor %}
</tbody>
</table>
<p>Balloon Payment Due: {{ "$%.2f"|format(balloon_payment) }} </p>
<p>Balloon Payment Due: {{ "$%.2f"|format(model.balloon_payment) }} </p>
</font>
</body>
</html>