From e9fefb1a1abd51871a984ae7994dc36243995475 Mon Sep 17 00:00:00 2001 From: JohnKent Date: Mon, 8 Jul 2019 00:27:38 -0400 Subject: [PATCH] Web version updated to allow sending emails. --- templates/add.html | 18 +++ templates/email.html | 19 +++ templates/main.html | 35 ++--- templates/statement.html.jinja | 84 +++++++++++ .../statement.pdf.jinja | 6 +- .../statement.text.jinja | 0 web.py | 134 +++++++++++++++++- 7 files changed, 273 insertions(+), 23 deletions(-) create mode 100644 templates/add.html create mode 100644 templates/email.html create mode 100644 templates/statement.html.jinja rename statement.pdf.jinja => templates/statement.pdf.jinja (99%) rename statement.txt.jinja => templates/statement.text.jinja (100%) diff --git a/templates/add.html b/templates/add.html new file mode 100644 index 0000000..7e68337 --- /dev/null +++ b/templates/add.html @@ -0,0 +1,18 @@ + + + + + + + + Loan Management + + + + + +Return to Main Screen. + + \ No newline at end of file diff --git a/templates/email.html b/templates/email.html new file mode 100644 index 0000000..530e273 --- /dev/null +++ b/templates/email.html @@ -0,0 +1,19 @@ + + + + + + + + Loan Management + + + + +

The email has been sent.

+Return to Main Screen. + + + \ No newline at end of file diff --git a/templates/main.html b/templates/main.html index 674a873..b311656 100644 --- a/templates/main.html +++ b/templates/main.html @@ -10,7 +10,7 @@ Loan Management -

Web Mortgage Manager

+
@@ -131,21 +131,24 @@
-
Loan:
- - - - - - - - +
Generate and Send Statement
Send From:{{model.email.from_address}}
Send To:{{model.email.to_address}}
Topic:
Message Body:
Send Statement As:
Include Future Amortization
+ + + + + + + + + +
Generate and Send Statement
Send From: {{model.email.from_address}}
Send To: {{model.email.to_address}}
Subject:
Message:
Send Statement As:
+ HTML + PDF + Plain Text +
Include Future Amortization
+ Yes + No +
diff --git a/templates/statement.html.jinja b/templates/statement.html.jinja new file mode 100644 index 0000000..48e124c --- /dev/null +++ b/templates/statement.html.jinja @@ -0,0 +1,84 @@ + + +

{{ model.header.title }}

+

{{ model.lender.name }}

+ +

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

+

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

+ +

+ + + + + + + + + + +
Loan Information 
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) }}
+

+

Payment History

+ + + + + + + + + + + +{% for item in model.past_payments %} + + + + + + + + + + {% if item.month == 12 or loop.last %} + + {% endif %} +{% endfor %} + + +
# + Due DateDate PaidDays InterestPayment AmtPrincipal PmtInterest PmtNew Balance
{{ item.payment_number }} {{ item.bill_date }} {{ item.payment_date }} {{ item.days_of_interest }} {{ "$%.2f"|format(item.payment_amount) }} {{ "$%.2f"|format(item.principal_payment) }} {{ "$%.2f"|format(item.interest_payment) }} {{ "$%.2f"|format(item.new_balance) }}
Total interest paid in {{item.year}} is {{ "$%.2f"|format(item.annual_interest_to_date) }}.
Total interest paid to date is {{ "$%.2f"|format(model.total_interest_paid_to_date) }}.
+

+ +

Remaining Amortization

+ + + + + + + + + + + + + +{% for item in model.future_payments %} + + + + + + + + +{% endfor %} + +
#Due DateDays InterestPayment AmtPrincipal PmtInterest PmtPrincipal Balance
{{ item.payment_number }} {{ item.payment_date }} {{ item.days_of_interest }} {{ "$%.2f"|format(item.payment_amount) }} {{ "$%.2f"|format(item.principal_payment) }} {{ "$%.2f"|format(item.interest_payment) }} {{ "$%.2f"|format(item.new_balance) }}
+

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

+
+ + \ No newline at end of file diff --git a/statement.pdf.jinja b/templates/statement.pdf.jinja similarity index 99% rename from statement.pdf.jinja rename to templates/statement.pdf.jinja index acd59c5..48e124c 100644 --- a/statement.pdf.jinja +++ b/templates/statement.pdf.jinja @@ -54,7 +54,8 @@

Remaining Amortization

- + + @@ -62,7 +63,8 @@ - + + {% for item in model.future_payments %} diff --git a/statement.txt.jinja b/templates/statement.text.jinja similarity index 100% rename from statement.txt.jinja rename to templates/statement.text.jinja diff --git a/web.py b/web.py index 672499d..d1a2361 100644 --- a/web.py +++ b/web.py @@ -2,9 +2,13 @@ from flask import Flask, render_template, request, redirect, url_for import json from decimal import * from datetime import * -from jinja2 import Environment, FileSystemLoader +import jinja2 from fpdf import FPDF, HTMLMixin import smtplib +import os + +loader=jinja2.FileSystemLoader([os.path.join(os.path.dirname(__file__),"templates")]) +environment = jinja2.Environment(loader=loader) from email.MIMEMultipart import MIMEMultipart from email.MIMEText import MIMEText @@ -21,6 +25,7 @@ def hello(): 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") ) + loans.append( addLoan("5 Test Loan", "testloan.json")) if 'loan' in request.args: filename = request.args["loan"] @@ -34,12 +39,49 @@ def hello(): @app.route('/update_file') def update_file(): - return + loanFile = request.form['loan'] + return redirect( '/?loan=' + loan ) @app.route('/send_statement', methods=['POST']) def send_statement(): - loan = request.form["loan"] - redirect( '/?loan=' + loan ) + loanFile = request.form["loan"] + subject = request.form["subject"] + message = request.form["message"] + style = request.form["style"] + + loan = loadLoanInformation('/Users/john/PycharmProjects/mortgage/' + loanFile) + amortizeLoan(loan) + + reportCreated = False + textReport = pdfReport = htmlReport = None + + if 'text' in request.form: + textReport = transformTemplate(selectTemplate('text'), loan) + reportCreated = True + + if 'pdf' in request.form: + pdfInterimReport = transformTemplate(selectTemplate('pdf'), loan) + pdfReport = createPDF(pdfInterimReport) + if style == 'embed': + style = 'attach' + reportCreated = True + + if ('html' in request.form) or (reportCreated is False): + htmlReport = transformTemplate(selectTemplate('html'), loan) + + + # send email + emailParameters = loan["email"] + + msg = generateEmail( emailParameters["from_address"], + emailParameters["to_address"], + subject, + message, pdfReport, htmlReport, textReport) + + sendEmail(msg, emailParameters["from_address"], emailParameters["to_address"], emailParameters['password']) + + + return render_template('email.html', filename=loanFile) def addLoan(loanName, fileName): x = {} @@ -47,7 +89,10 @@ def addLoan(loanName, fileName): x['filename'] = fileName return x -'''from old code''' +################### +# from old code # +################### + def getStatementHeader(datastore): return datastore['header'] @@ -238,6 +283,85 @@ def amortizeLoan(loan): loan["future_payments"] = future_payments return +def transformTemplate(template_fileName, loanModel): + # template_filename = "statement.text.jinja" + # setup jinja for creating the statement + template = environment.get_template(template_fileName) + + print loanModel + report = template.render(model=loanModel) + return report + + +def generateEmail(from_address, to_address, subject, body, pdf, html, txt): + msg = MIMEMultipart() + msg['Subject'] = subject + msg['From'] = from_address + msg['To'] = to_address + + msg.attach(MIMEText(body)) + + if (pdf != None): + part = MIMEBase("application", "octet-stream") + part.set_payload(pdf) + Encoders.encode_base64(part) + part.add_header('Content-Disposition', 'attachment; filename="statement.pdf"') + msg.attach(part) + + if (html != None): + part = MIMEBase("text", "html") + part.set_payload(html) + Encoders.encode_base64(part) + part.add_header('Content-Disposition', 'attachment; filename="statement.html"') + msg.attach(part) + + if (txt != None): + part = MIMEBase("text", "plain") + part.set_payload(txt) + Encoders.encode_base64(part) + part.add_header('Content-Disposition', 'attachment; filename="statement.txt"') + 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 + + pdf = MyFPDF() + pdf.set_font(family='Arial', size=12) + pdf.add_page() + pdf.write_html(report) + # pdf.output(name='test.pdf', dest='F') + return pdf.output(dest='S') + + +def selectTemplate(format): + if format == 'html': + return 'statement.html.jinja' + + if format == 'pdf': + return 'statement.pdf.jinja' + + if format == 'text': + return 'statement.text.jinja' + + return 'statement.html.jinja' if __name__ == '__main__': app.debug = True
# Due Date Days InterestPrincipal Pmt Interest Pmt Principal Balance
{{ item.payment_number }}