From 45d6e32149ab613310ea1b3d8e6b5f53f8765eb0 Mon Sep 17 00:00:00 2001 From: JohnKent Date: Sun, 6 Jan 2019 16:39:54 -0500 Subject: [PATCH] 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. --- 10Kloan.json | 63 ++++++++ brendamortgage.json | 56 +++++++ dadmortgage.json | 56 +++++++ greenfield_mortgage.json | 63 ++++++++ greenfield_mortgage.txt | 25 ---- mortgage_template.py | 307 ++++++++++++++++++++------------------- statement.pdf.jinja | 30 ++-- 7 files changed, 409 insertions(+), 191 deletions(-) create mode 100644 10Kloan.json create mode 100644 brendamortgage.json create mode 100644 dadmortgage.json create mode 100644 greenfield_mortgage.json delete mode 100644 greenfield_mortgage.txt diff --git a/10Kloan.json b/10Kloan.json new file mode 100644 index 0000000..b9cd72d --- /dev/null +++ b/10Kloan.json @@ -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" + } +} + diff --git a/brendamortgage.json b/brendamortgage.json new file mode 100644 index 0000000..d13476f --- /dev/null +++ b/brendamortgage.json @@ -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"] + ] +} diff --git a/dadmortgage.json b/dadmortgage.json new file mode 100644 index 0000000..9ff0acb --- /dev/null +++ b/dadmortgage.json @@ -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"] + ] +} diff --git a/greenfield_mortgage.json b/greenfield_mortgage.json new file mode 100644 index 0000000..65d2127 --- /dev/null +++ b/greenfield_mortgage.json @@ -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" + } +} diff --git a/greenfield_mortgage.txt b/greenfield_mortgage.txt deleted file mode 100644 index 91bc430..0000000 --- a/greenfield_mortgage.txt +++ /dev/null @@ -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"] - ] -} diff --git a/mortgage_template.py b/mortgage_template.py index 38e67a9..df1cb4b 100644 --- a/mortgage_template.py +++ b/mortgage_template.py @@ -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__': diff --git a/statement.pdf.jinja b/statement.pdf.jinja index b1a43cd..1e2370c 100644 --- a/statement.pdf.jinja +++ b/statement.pdf.jinja @@ -1,22 +1,22 @@ -

{{ statement.title }}

-

{{ statement.lender.name }}

+

{{ model.header.title }}

+

{{ model.lender.name }}

-

{{ statement.lender.phone }} - {{ statement.lender.address }} - -{{ statement.lender.city }} {{statement.lender.state }} {{ statement.lender.zip }}

-

Statement Date: {{ statement.date }}

+

{{ model.lender.phone }} - {{ model.lender.address }} - +{{ model.lender.city }} {{model.lender.state }} {{ model.lender.zip }}

+

Statement Date: {{ model.header.date }}

- - - - - - + + + + + +
Loan Information 
Borrower: {{ statement.borrower.name }}  Account Number: {{ statement.loan.account_number }}
{{ statement.borrower.address }}  Origination Date: {{ statement.loan.origination_date }}
{{ statement.borrower.city }}, {{statement.borrower.state }} {{ statement.borrower.zip }}Original Principal: {{ "$%.2f"|format(statement.loan.principal) }}
Rate: {{statement.loan.rate }} Term: {{statement.loan.term }} months
Next Payment Due Date: {{statement.loan.next_due_date}} Payment Due: {{ "$%.2f"|format(statement.loan.next_payment_amt) }}
Borrower: {{ model.borrower.name }}  Account Number: {{ model.parameters.account_number }}
{{ model.borrower.address }}  Origination Date: {{ model.parameters.start_date }}
{{ model.borrower.city }}, {{model.borrower.state }} {{ model.borrower.zip }}Original Principal: {{ "$%.2f"|format(model.parameters.principal) }}
Rate: {{model.parameters.interest_rate }}% Term: {{model.parameters.periods }} months
Next Payment Due Date: {{model.parameters.next_due_date}} Payment Due: {{ "$%.2f"|format(model.parameters.next_payment_amt) }}

@@ -33,7 +33,7 @@ New Balance -{% for item in past_payments %} +{% for item in model.past_payments %} {{ item.payment_number }} {{ item.bill_date }} {{ item.payment_date }} @@ -49,7 +49,7 @@ {% endfor %} -

Total interest paid to date is {{ "$%.2f"|format(total_interest_paid_to_date) }}.

+

Total interest paid to date is {{ "$%.2f"|format(model.total_interest_paid_to_date) }}.

Remaining Amortization

@@ -64,7 +64,7 @@ Principal Balance -{% for item in future_payments %} +{% for item in model.future_payments %} {{ item.payment_number }} {{ item.payment_date }} {{ item.days_of_interest }} @@ -76,7 +76,7 @@ {% endfor %} -

Balloon Payment Due: {{ "$%.2f"|format(balloon_payment) }}

+

Balloon Payment Due: {{ "$%.2f"|format(model.balloon_payment) }}

\ No newline at end of file