From 466d2dce8b68288440a13779da7b58daa0bbedeb Mon Sep 17 00:00:00 2001 From: john Date: Mon, 3 Oct 2022 00:02:12 -0400 Subject: [PATCH] :G: Enter commit message. Lines beginning with 'HG:' are removed. --- .hgignore | 6 +- testloan.json => 0_Test_Loan.loan | 34 +- 10Kloan.json | 69 --- dadmortgage.json => 1_Dad_Mortgage.loan | 156 ++++- brendamortgage.json => 2_Brenda_Mortgage.loan | 156 ++++- 9Kloan.json => 3_839_Harbor_Bend_2022.loan | 71 +-- ... => _Archive_Greenfield_Lane_Mortgage.loan | 86 ++- _Archive_Greenfield_Lane_Refinance-1.loan | 128 +++++ _Archive_Old_Harbor_Bend_Mortgage.loan | 50 ++ _Archive_Wayneland_Mortgage.loan | 137 +++++ mortgage.py | 130 ----- mortgage/calculate_interest_heloc.py | 68 +++ mortgage/mortgage_template.py | 345 ----------- mortgage/templates/main.html | 20 +- .../payment_received_email.html.jinja | 23 + mortgage/templates/statement.text.jinja | 75 +-- mortgage/web.py | 254 +++++--- mortgage/web_ng.py | 544 ++++++++++++++++++ pyvenv.cfg | 3 + requirements.txt | 4 +- 20 files changed, 1630 insertions(+), 729 deletions(-) rename testloan.json => 0_Test_Loan.loan (76%) delete mode 100644 10Kloan.json rename dadmortgage.json => 1_Dad_Mortgage.loan (54%) rename brendamortgage.json => 2_Brenda_Mortgage.loan (54%) rename 9Kloan.json => 3_839_Harbor_Bend_2022.loan (52%) rename greenfield_mortgage.json => _Archive_Greenfield_Lane_Mortgage.loan (72%) create mode 100644 _Archive_Greenfield_Lane_Refinance-1.loan create mode 100644 _Archive_Old_Harbor_Bend_Mortgage.loan create mode 100644 _Archive_Wayneland_Mortgage.loan delete mode 100644 mortgage.py create mode 100644 mortgage/calculate_interest_heloc.py delete mode 100644 mortgage/mortgage_template.py create mode 100644 mortgage/templates/payment_received_email.html.jinja create mode 100644 mortgage/web_ng.py create mode 100644 pyvenv.cfg diff --git a/.hgignore b/.hgignore index 1545b02..40b7757 100644 --- a/.hgignore +++ b/.hgignore @@ -1,3 +1,5 @@ -./venv/ -.hgignore .Python +.DS_Store +./bin/ +./lib/ +./.idea/ diff --git a/testloan.json b/0_Test_Loan.loan similarity index 76% rename from testloan.json rename to 0_Test_Loan.loan index 0be860b..e8faba3 100644 --- a/testloan.json +++ b/0_Test_Loan.loan @@ -23,7 +23,7 @@ "date": "Today", "title": "Installment Loan Test Statement" }, - "payments": [ + "payments": [ [ "2019-07-15", "475.00" @@ -52,6 +52,36 @@ "2020-01-15", "0", "50" + ], + [ + "2020-09-27", + "278.15", + "20" + ], + [ + "2020-09-29", + "296.12", + "25" + ], + [ + "2020-10-16", + "133", + "0.00" + ], + [ + "2020-10-16", + "133", + "0.00" + ], + [ + "2020-10-16", + "133", + "0.00" + ], + [ + "2021-05-03", + "1", + "1" ] ], "borrower": { @@ -67,6 +97,6 @@ "subject": "Your test loan statement...", "body": "Your test loan statement is attached.", "server": "smtp.gmail.com", - "password": "pvyrbcnzrjoizprn" + "password": "builcuouzobxroow" } } \ No newline at end of file diff --git a/10Kloan.json b/10Kloan.json deleted file mode 100644 index 3bac0b5..0000000 --- a/10Kloan.json +++ /dev/null @@ -1,69 +0,0 @@ -{ -"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"], - ["2019-01-15", "0.00"], - ["2019-02-13", "589.00"], - ["2019-03-15", "0"], - ["2019-04-15", "0"], - ["2019-05-15", "589.00"], - ["2019-06-21", "2985.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/dadmortgage.json b/1_Dad_Mortgage.loan similarity index 54% rename from dadmortgage.json rename to 1_Dad_Mortgage.loan index 919852a..c0faec1 100644 --- a/dadmortgage.json +++ b/1_Dad_Mortgage.loan @@ -22,7 +22,7 @@ "send_text": "true", "template": "./template.txt", "send_pdf": "true", - "password": "pvyrbcnzrjoizprn", + "password": "builcuouzobxroow", "subject": "Your loan statement..." }, "lender": { @@ -129,14 +129,164 @@ [ "2020-06-01", "278.15" + ], + [ + "2020-07-01", + "278.15" + ], + [ + "2020-08-01", + "278.15" + ], + [ + "2020-09-01", + "278.15" + ], + [ + "2020-10-01", + "278.15" + ], + [ + "2020-11-01", + "278.15", + "0.00" + ], + [ + "2020-12-01", + "278.15", + "0.00" + ], + [ + "2021-01-01", + "278.15", + "0" + ], + [ + "2021-02-01", + "278.15", + "0" + ], + [ + "2021-03-01", + "278.15", + "0.00" + ], + [ + "2021-04-01", + "278.15", + "0.00" + ], + [ + "2021-04-30", + "278.15", + "0" + ], + [ + "2021-06-01", + "278.15", + "0.00" + ], + [ + "2021-07-01", + "278.15", + "0" + ], + [ + "2021-07-31", + "278.15", + "0" + ], + [ + "2021-09-01", + "278.15", + "0.00", + "False" + ], + [ + "2021-10-01", + "278.15", + "0.00", + "False" + ], + [ + "2021-11-01", + "278.15", + "0", + "False" + ], + [ + "2021-12-01", + "278.15", + "0.00", + "False" + ], + [ + "2022-01-01", + "278.15", + "0.00", + "False" + ], + [ + "2022-02-01", + "278.15", + "0.00", + "False" + ], + [ + "2022-03-01", + "278.15", + "0.00", + "False" + ], + [ + "2022-04-01", + "278.15", + "0.00", + "False" + ], + [ + "2022-05-01", + "278.15", + "0.00", + "False" + ], + [ + "2022-06-01", + "278.15", + "0.00", + "False" + ], + [ + "2022-07-01", + "278.15", + "0.00", + "False" + ], + [ + "2022-08-01", + "278.15", + "0.00", + "False" + ], + [ + "2022-09-01", + "278.15", + "0.00", + "False" + ], + [ + "2022-10-01", + "278.15", + "0.00", + "False" ] ], "borrower": { "city": "Washington", "state": "DC", "name": "Grandma Tina's Properties, LLC", - "zip": "20008", - "address": "3100 Connecticut Ave NW Apt 144" + "zip": "20001", + "address": "1720 New Jersey Ave NW Unit 401" }, "txtTemplate": "statement.txt.jinja" } \ No newline at end of file diff --git a/brendamortgage.json b/2_Brenda_Mortgage.loan similarity index 54% rename from brendamortgage.json rename to 2_Brenda_Mortgage.loan index 12e74ba..848a549 100644 --- a/brendamortgage.json +++ b/2_Brenda_Mortgage.loan @@ -22,7 +22,7 @@ "send_text": "true", "template": "./template.txt", "send_pdf": "true", - "password": "pvyrbcnzrjoizprn", + "password": "builcuouzobxroow", "subject": "Your loan statement..." }, "lender": { @@ -129,14 +129,164 @@ [ "2020-06-01", "278.15" + ], + [ + "2020-07-01", + "278.15" + ], + [ + "2020-08-01", + "278.15" + ], + [ + "2020-09-01", + "278.15" + ], + [ + "2020-10-01", + "278.15" + ], + [ + "2020-11-01", + "278.15", + "0.00" + ], + [ + "2020-12-01", + "278.15", + "0.00" + ], + [ + "2021-01-01", + "278.15", + "0" + ], + [ + "2021-02-01", + "278.15", + "0" + ], + [ + "2021-03-01", + "278.15", + "0.00" + ], + [ + "2021-04-01", + "278.15", + "0.00" + ], + [ + "2021-04-30", + "278.15", + "0" + ], + [ + "2021-06-01", + "278.15", + "0.00" + ], + [ + "2021-07-01", + "278.15", + "0" + ], + [ + "2021-07-31", + "278.15", + "0" + ], + [ + "2021-09-01", + "278.15", + "0.00", + "False" + ], + [ + "2021-10-01", + "278.15", + "0.00", + "False" + ], + [ + "2021-11-01", + "278.15", + "0", + "False" + ], + [ + "2021-12-01", + "278.15", + "0.00", + "False" + ], + [ + "2022-01-01", + "278.15", + "0.00", + "False" + ], + [ + "2022-02-01", + "278.15", + "0", + "False" + ], + [ + "2022-03-01", + "278.15", + "0.00", + "False" + ], + [ + "2022-04-01", + "278.15", + "0.00", + "False" + ], + [ + "2022-05-01", + "278.15", + "0.00", + "False" + ], + [ + "2022-06-01", + "278.15", + "0.00", + "False" + ], + [ + "2022-07-01", + "278.15", + "0.00", + "False" + ], + [ + "2022-08-01", + "278.15", + "0.00", + "False" + ], + [ + "2022-09-01", + "278.15", + "0.00", + "False" + ], + [ + "2022-10-01", + "278.15", + "0.00", + "False" ] ], "borrower": { "city": "Washington", "state": "DC", "name": "Grandma Tina's Properties, LLC", - "zip": "20008", - "address": "3100 Connecticut Ave NW Apt 144" + "zip": "20001", + "address": "1720 New Jersey Ave NW Unit 401" }, "txtTemplate": "statement.txt.jinja" } \ No newline at end of file diff --git a/9Kloan.json b/3_839_Harbor_Bend_2022.loan similarity index 52% rename from 9Kloan.json rename to 3_839_Harbor_Bend_2022.loan index a01c4b4..3d41c1f 100644 --- a/9Kloan.json +++ b/3_839_Harbor_Bend_2022.loan @@ -1,16 +1,16 @@ { "htmlTemplate": "statement.pdf.jinja", "parameters": { - "monthly_payment": 475.0, - "interest_rate": 6.5, - "start_interest_date": "2019-06-17", + "monthly_payment": 842.93, + "interest_rate": 5.75, + "start_interest_date": "2022-08-12", "payment_day_of_month": "15", - "first_payment_month": "2019-07-15", - "account_number": "100002", - "periods": 20, - "start_date": "2019-06-15", + "first_payment_month": "2022-09-15", + "account_number": "22-0001", + "periods": 180, + "start_date": "2022-08-12", "periods_per_year": 12, - "principal": 9000.0 + "principal": 101508.04 }, "format": "html", "email": { @@ -22,66 +22,33 @@ "send_text": "true", "template": "./template.txt", "send_pdf": "true", - "password": "pvyrbcnzrjoizprn", + "password": "builcuouzobxroow", "subject": "Your loan statement..." }, "lender": { "city": "Washington", "name": "Rivanna Graphite Investments, LLC", - "zip": "20008", + "zip": "20001", "phone": "703.343.0782", "state": "DC", - "address": "3100 Connecticut Ave NW Apt 144" + "address": "1720 New Jersey Ave NW Unit 401" }, "header": { "date": "Today", - "title": "Installment Loan Statement" + "title": "Mortgage Loan Statement - Harbor Bend Loan 1" }, "payments": [ [ - "2019-07-15", - "475.00" - ], - [ - "2019-08-14", - "475.00" - ], - [ - "2019-09-17", - "475" - ], - [ - "2019-10-15", - "0" - ], - [ - "2019-11-15", - "0" - ], - [ - "2019-12-5", - "475" - ], - [ - "2020-01-15", + "2022-08-15", + "803", "0", - "0" + "False" ], [ - "2020-02-17", - "0" - ], - [ - "2020-03-03", - "475" - ], - [ - "2020-04-15", - "0" - ], - [ - "2020-05-19", - "475" + "2022-09-09", + "803", + "0.00", + "False" ] ], "borrower": { diff --git a/greenfield_mortgage.json b/_Archive_Greenfield_Lane_Mortgage.loan similarity index 72% rename from greenfield_mortgage.json rename to _Archive_Greenfield_Lane_Mortgage.loan index 1ea4eee..22fe53d 100644 --- a/greenfield_mortgage.json +++ b/_Archive_Greenfield_Lane_Mortgage.loan @@ -22,16 +22,16 @@ "send_text": "true", "template": "./template.txt", "send_pdf": "true", - "password": "pvyrbcnzrjoizprn", + "password": "builcuouzobxroow", "subject": "Your loan statement..." }, "lender": { "city": "Washington", "name": "Rivanna Graphite Investments, LLC", - "zip": "20008", + "zip": "20001", "phone": "703.343.0782", "state": "DC", - "address": "3100 Connecticut Ave NW Apt 144" + "address": "1720 New Jersey Ave NW Unit 401" }, "header": { "date": "Today", @@ -162,6 +162,86 @@ [ "2020-06-16", "803.00" + ], + [ + "2020-07-15", + "803" + ], + [ + "2020-08-13", + "803" + ], + [ + "2020-09-17", + "803" + ], + [ + "2020-10-15", + "803", + "0.00" + ], + [ + "2020-11-16", + "803.00", + "0" + ], + [ + "2020-12-15", + "803.00", + "0.00" + ], + [ + "2021-01-13", + "803.00", + "0" + ], + [ + "2021-02-16", + "803.00", + "0" + ], + [ + "2021-03-22", + "0", + "32.12" + ], + [ + "2021-04-14", + "803.00", + "0.00" + ], + [ + "2021-05-18", + "803.00", + "0" + ], + [ + "2021-06-15", + "803.00", + "0" + ], + [ + "2021-07-31", + "0", + "32.12" + ], + [ + "2021-08-18", + "803", + "0.00", + "False" + ], + [ + "2021-09-24", + "803", + "0.00", + "False" + ], + [ + "2021-09-25", + "0", + "0.00", + "False" ] ], "borrower": { diff --git a/_Archive_Greenfield_Lane_Refinance-1.loan b/_Archive_Greenfield_Lane_Refinance-1.loan new file mode 100644 index 0000000..5ab8f08 --- /dev/null +++ b/_Archive_Greenfield_Lane_Refinance-1.loan @@ -0,0 +1,128 @@ +{ + "htmlTemplate": "statement.pdf.jinja", + "parameters": { + "monthly_payment": 831.0, + "interest_rate": 5.5, + "start_interest_date": "2021-10-13", + "payment_day_of_month": "15", + "first_payment_month": "2021-11-15", + "account_number": "21-0004", + "periods": 180, + "start_date": "2021-10-13", + "periods_per_year": 12, + "principal": 101123.26 + }, + "format": "html", + "email": { + "body": "Your loan statement is attached.", + "to_address": "grady@gradystreet.com", + "from_address": "jkent3rd@gmail.com", + "text": "Please see your most recent account statement.", + "server": "smtp.gmail.com", + "send_text": "true", + "template": "./template.txt", + "send_pdf": "true", + "password": "builcuouzobxroow", + "subject": "Your loan statement..." + }, + "lender": { + "city": "Washington", + "name": "Rivanna Graphite Investments, LLC", + "zip": "20001", + "phone": "703.343.0782", + "state": "DC", + "address": "1720 New Jersey Ave NW Unit 401" + }, + "header": { + "date": "Today", + "title": "Mortgage Loan Statement - 195 Greenfield Lane, Pearl MS" + }, + "payments": [ + [ + "2021-10-14", + "803", + "0.00", + "False" + ], + [ + "2021-10-14", + "28", + "0.00", + "False" + ], + [ + "2021-10-18", + "28", + "0.00", + "False" + ], + [ + "2021-11-16", + "803.00", + "0.00", + "False" + ], + [ + "2021-11-19", + "28", + "0.00", + "False" + ], + [ + "2022-02-10", + "831", + "0.00", + "False" + ], + [ + "2022-04-04", + "1000", + "55.00", + "False" + ], + [ + "2022-05-15", + "0", + "0.00", + "False" + ], + [ + "2022-06-15", + "0", + "0.00", + "False" + ], + [ + "2022-07-15", + "0", + "0.00", + "False" + ], + [ + "2022-07-26", + "803", + "0.00", + "False" + ], + [ + "2022-08-12", + "0", + "0.00", + "False" + ], + [ + "2022-08-12", + "101508.04", + "0.00", + "False" + ] + ], + "borrower": { + "city": "Alexandria", + "state": "VA", + "name": "Bear Houses, LLC", + "zip": "22312", + "address": "301 N Beauregard St Apt 203" + }, + "txtTemplate": "statement.txt.jinja" +} \ No newline at end of file diff --git a/_Archive_Old_Harbor_Bend_Mortgage.loan b/_Archive_Old_Harbor_Bend_Mortgage.loan new file mode 100644 index 0000000..c89078d --- /dev/null +++ b/_Archive_Old_Harbor_Bend_Mortgage.loan @@ -0,0 +1,50 @@ +{ + "htmlTemplate": "statement.pdf.jinja", + "parameters": { + "monthly_payment": 848, + "interest_rate": 5.75, + "start_interest_date": "2022-08-12", + "payment_day_of_month": "15", + "first_payment_month": "2022-09-15", + "account_number": "22-0001", + "periods": 180, + "start_date": "2022-08-12", + "periods_per_year": 12, + "principal": 101508.04 + }, + "format": "html", + "email": { + "body": "Your loan statement is attached.", + "to_address": "grady@gradystreet.com", + "from_address": "jkent3rd@gmail.com", + "text": "Please see your most recent account statement.", + "server": "smtp.gmail.com", + "send_text": "true", + "template": "./template.txt", + "send_pdf": "true", + "password": "builcuouzobxroow", + "subject": "Your loan statement..." + }, + "lender": { + "city": "Washington", + "name": "Rivanna Graphite Investments, LLC", + "zip": "20001", + "phone": "703.343.0782", + "state": "DC", + "address": "1720 New Jersey Ave NW Unit 401" + }, + "header": { + "date": "Today", + "title": "Mortgage Loan Statement - Harbor Bend Loan 1" + }, + "payments": [ + ], + "borrower": { + "city": "Alexandria", + "state": "VA", + "name": "Bear Houses, LLC", + "zip": "22312", + "address": "301 N Beauregard St Apt 203" + }, + "txtTemplate": "statement.txt.jinja" +} \ No newline at end of file diff --git a/_Archive_Wayneland_Mortgage.loan b/_Archive_Wayneland_Mortgage.loan new file mode 100644 index 0000000..f7cde9e --- /dev/null +++ b/_Archive_Wayneland_Mortgage.loan @@ -0,0 +1,137 @@ +{ + "htmlTemplate": "statement.pdf.jinja", + "parameters": { + "monthly_payment": 175.55, + "interest_rate": 4.5, + "start_interest_date": "2020-07-15", + "payment_day_of_month": "15", + "first_payment_month": "2020-08-15", + "account_number": "100003", + "periods": 60, + "start_date": "2020-07-15", + "periods_per_year": 12, + "principal": 16884 + }, + "format": "html", + "email": { + "body": "Your loan statement is attached.", + "to_address": "grady@gradystreet.com", + "from_address": "jkent3rd@gmail.com", + "text": "Please see your most recent account statement.", + "server": "smtp.gmail.com", + "send_text": "true", + "template": "./template.txt", + "send_pdf": "true", + "password": "builcuouzobxroow", + "subject": "Your loan statement..." + }, + "lender": { + "city": "Washington", + "name": "Rivanna Graphite Investments, LLC", + "zip": "20008", + "phone": "703.343.0782", + "state": "DC", + "address": "3100 Connecticut Ave NW Apt 144" + }, + "header": { + "date": "Today", + "title": "Mortgage Loan Statement - 5025 Wayneland Drive Apt D11 Jackson MS 39211" + }, + "payments": [ + [ + "2020-08-27", + "175.55" + ], + [ + "2020-09-30", + "175.55" + ], + [ + "2020-10-19", + "175.55", + "0.00" + ], + [ + "2020-12-01", + "0", + "17.55" + ], + [ + "2020-12-29", + "0", + "17.55" + ], + [ + "2021-01-20", + "175.55", + "0" + ], + [ + "2021-02-15", + "0.00", + "17.55" + ], + [ + "2021-03-12", + "175.55", + "0.00" + ], + [ + "2021-04-15", + "0", + "17.55" + ], + [ + "2021-05-17", + "0", + "17.55" + ], + [ + "2021-06-30", + "0", + "0.00" + ], + [ + "2021-07-29", + "175.55", + "17.55" + ], + [ + "2021-08-09", + "175.55", + "0" + ], + [ + "2021-08-10", + "175.55", + "0", + "extra" + ], + [ + "2021-09-03", + "175.55", + "0.00", + "False" + ], + [ + "2021-09-17", + "175.55", + "0.00", + "False" + ], + [ + "2021-09-18", + "0", + "0.00", + "False" + ] + ], + "borrower": { + "city": "Alexandria", + "state": "VA", + "name": "Bear Houses, LLC", + "zip": "22312", + "address": "301 N Beauregard St Apt 203" + }, + "txtTemplate": "statement.txt.jinja" +} \ No newline at end of file diff --git a/mortgage.py b/mortgage.py deleted file mode 100644 index 18a582e..0000000 --- a/mortgage.py +++ /dev/null @@ -1,130 +0,0 @@ -import json -from decimal import * -from datetime import * - -# 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 = "./dadmortgage.txt" -#filename = "./brendamortgage.txt" -#filename = "./greenfield_mortgage.txt" - -if filename: - with open(filename, 'r') as f: - datastore = json.load(f) - -#read in the loan profile information -annual_rate = Decimal(datastore['interest rate'])/100 -daily_interest_rate = annual_rate/360 -principal = Decimal(datastore["principal"]).quantize(Decimal("1.00")) -periods_per_year = Decimal(datastore["periods per year"]) -total_periods = Decimal(datastore["periods"]) -payment_day_of_month = int(datastore['payment day of month']) - -if "monthly_payment" in datastore: - monthly_payment = Decimal(datastore["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")) - - - -print "Principal: ", principal -print "Interest Rate: ", annual_rate -print "Payments Per Year: ", periods_per_year -print "Loan Term: ", total_periods -print "Monthly Payment", monthly_payment -print "Payments due day: ", payment_day_of_month - -print - -#loop over the payments and calculate the actual amortization -actual_payments = datastore["payments"] - -remaining_principal = principal -annual_interest = 0 -total_interest = 0 - -interest_paid_through_date = datetime.strptime(datastore["start_interest_date"], "%Y-%m-%d").date() -next_payment_date = datetime.strptime(datastore["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 - -print "Payment History:" -print "\tBill\t\t\tPayment\tDays of\tPayment\t\tRemaining\t\tPrincipal\tInterest\t\t\tNew" -print "#\tDate\t\t\tDate\tInterst\tAmount\t\tPrincipal\t\tPayment\t\tPayment\t\t\tBalance" -for payment in actual_payments: - payment_date = datetime.strptime((payment[0]), '%Y-%m-%d').date() - payment_amount = Decimal(payment[1]).quantize(Decimal("1.00")) - #print next_bill_date, "\t", next_payment_date, "\t", - days_since_last_payment = (payment_date-interest_paid_through_date).days - #print days_since_last_payment - new_interest = (days_since_last_payment * remaining_principal * daily_interest_rate).quantize(Decimal("0.00")) -# new_principal = monthly_payment - new_interest - new_principal = payment_amount - new_interest - - print payment_number, " ", next_bill_date, "\t\t", payment_date, "\t", days_since_last_payment, "\t", payment_amount, "\t\t\t", remaining_principal, "\t\t", new_principal,\ - "\t\t", 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 - print "\t\t\t", remaining_principal - 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) - print "Total interest paid to date for", old_bill_date.year, " is", annual_interest - else: - next_bill_date = date(year=old_bill_date.year+1, month = 1, day=payment_day_of_month) - print "Total interest for ", old_bill_date.year, " was ", annual_interest - annual_interest = 0 - -print "Total interest paid to date on this loan is", total_interest - -#loop over remaining scheduled payments and present estimated amortization -print "\nEstimated future amortization" - -while (payment_number <= total_periods) and (remaining_principal > 0): - print payment_number, "\t", - payment_number = payment_number+1 - - print next_bill_date, - - days_since_last_payment = (next_bill_date-interest_paid_through_date).days - print days_since_last_payment, "\t", - 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 - - print monthly_payment, "\t\t\t", remaining_principal, "\t\t", new_principal,\ - "\t\t", new_interest, - - remaining_principal = remaining_principal - new_principal - print "\t", remaining_principal - - interest_paid_through_date = next_bill_date - 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) - -if remaining_principal > 0: - print 'Balloon payment due:', remaining_principal diff --git a/mortgage/calculate_interest_heloc.py b/mortgage/calculate_interest_heloc.py new file mode 100644 index 0000000..70e3961 --- /dev/null +++ b/mortgage/calculate_interest_heloc.py @@ -0,0 +1,68 @@ +'''''''take in the csv file of transactions''' +import datetime +from decimal import * +import csv +from calendar import monthrange + +def main(): + getcontext().prec=10 + open_balance = Decimal("-24521.81") + interest_rate = Decimal("8.00")/Decimal("100.00")/Decimal("365.00") + year = 2021 + + start_date = datetime.date(year, 1, 1) + end_date = datetime.date(year, 12, 31)+datetime.timedelta(1) + days_in_year = (end_date - start_date).days + print ("Days in year: %d" % days_in_year) + + balances = [Decimal('0.00')] * days_in_year + interest_invoices = [Decimal('0.00')] * 12 + + with open("/Users/john/Downloads/query_result.csv") as f: + reader = csv.DictReader(f) + for row in reader: + print(row) + year = row['year'] + month = row['month'] + day = row['day'] + amount = row['position (USD)'] + + date_val = datetime.date(int(year), int(month), int(day)) + day_of_year = date_val.toordinal() - datetime.date(date_val.year, 1, 1).toordinal() + 1 + print("Record created for day of year %d" % day_of_year) + print("%s - %s - %s: %s " % (year, month, day, amount)) + balances[day_of_year] = balances[day_of_year] + Decimal(amount) + + current_balance = open_balance + day_being_processed = 1 + accumlated_interest = Decimal('0.000000') + + while (day_being_processed <= days_in_year): + print("Day of year: %d" % day_being_processed) + #calculate the day's balance + current_balance = current_balance + balances[day_being_processed-1] + balances[day_being_processed-1] = current_balance + + #accummulate the day's interest + todays_interest = current_balance * interest_rate + accumlated_interest = accumlated_interest + todays_interest + + #check if this is the last day of the month, if it is do the transition stuff + current_month = datetime.date.fromordinal(start_date.toordinal()+day_being_processed-1).month + next_month = datetime.date.fromordinal(start_date.toordinal()+day_being_processed).month + print("Current Month: %d Next_month: %d" % (current_month, next_month )) + if (current_month != next_month): + interest_invoices[current_month-1] = accumlated_interest.quantize(Decimal('.01')) + current_balance = current_balance + accumlated_interest + accumlated_interest = Decimal('0.00') + + + day_being_processed = day_being_processed + 1 + + i=0 + while (i<12): + print ("%d: %s" %(i+1, interest_invoices[i]) ) + i = i +1 + +if __name__ == '__main__': + main() diff --git a/mortgage/mortgage_template.py b/mortgage/mortgage_template.py deleted file mode 100644 index dfa8260..0000000 --- a/mortgage/mortgage_template.py +++ /dev/null @@ -1,345 +0,0 @@ -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 - - -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 - - -def transformTemplate(template_fileName, loanModel): - # template_filename = "statement.text.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 generateEmailWithAttachments(from_address, to_address, subject, body, pdfAttachment, htmlAttachment, 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 - - 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(loan): - templateKey = loan["datastore"]["format"] + "Template" - if templateKey in loan: - template = loan[templateKey] - else: - template = 'statement.pdf.jinja' - - return template - -def main(): - test_flag = True - # 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 - test_flag = False - test_address = 'jkent3rd@yahoo.com' - - #filename = "./testloan.json" - filename = "./9Kloan.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 - emailParameters = loan["email"] - msg = generateEmail(emailParameters["from_address"], emailParameters["to_address"], emailParameters["subject"], - emailParameters["body"], pdfAttachment, report) - if test_flag == False: - sendEmail(msg, emailParameters["from_address"], emailParameters["to_address"], emailParameters['password']) - else: - sendEmail(msg, emailParameters["from_address"], test_address, emailParameters['password']) - -if __name__ == '__main__': - main() diff --git a/mortgage/templates/main.html b/mortgage/templates/main.html index 1b0c7db..29e8664 100644 --- a/mortgage/templates/main.html +++ b/mortgage/templates/main.html @@ -1,7 +1,6 @@ -