From 9199a93dac82352ed05a434f6cc7cb40434c92f5 Mon Sep 17 00:00:00 2001 From: Adarsh Murthy Date: Wed, 19 Apr 2017 17:59:20 -0400 Subject: [PATCH 1/4] Create route GET/PUT for customer preference table and display table on frontend. --- .gitignore | 1 + .../migrations/0012_customerpreference.py | 25 +++++++ blocnote/apps/financialInputs/models.py | 9 +++ .../static/financialInputs/scripts/app.js | 73 +++++++++++++++++++ .../financialInputs/customerPreference.html | 6 ++ .../templates/financialInputs/index.html | 3 + blocnote/apps/financialInputs/urls.py | 1 + blocnote/apps/financialInputs/views.py | 40 +++++++++- 8 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 blocnote/apps/financialInputs/migrations/0012_customerpreference.py create mode 100644 blocnote/apps/financialInputs/templates/financialInputs/customerPreference.html diff --git a/.gitignore b/.gitignore index 32b1e5a..171d778 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ node_modules # misc .idea .vscode/ +static/ diff --git a/blocnote/apps/financialInputs/migrations/0012_customerpreference.py b/blocnote/apps/financialInputs/migrations/0012_customerpreference.py new file mode 100644 index 0000000..2b643cf --- /dev/null +++ b/blocnote/apps/financialInputs/migrations/0012_customerpreference.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.6 on 2017-04-19 20:58 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('financialInputs', '0011_auto_20170418_0232'), + ] + + operations = [ + migrations.CreateModel( + name='CustomerPreference', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('building_id', models.IntegerField()), + ('downpayment', models.DecimalField(decimal_places=2, max_digits=10)), + ('expected_payback', models.DecimalField(decimal_places=0, max_digits=3)), + ('expected_net_noi_dscr', models.DecimalField(decimal_places=2, max_digits=5)), + ], + ), + ] diff --git a/blocnote/apps/financialInputs/models.py b/blocnote/apps/financialInputs/models.py index b10647c..139bfb3 100644 --- a/blocnote/apps/financialInputs/models.py +++ b/blocnote/apps/financialInputs/models.py @@ -56,3 +56,12 @@ class BillsOverview(models.Model): oil_is_user_input = models.BooleanField(default=False) gas = models.DecimalField(max_digits=10, decimal_places=2) gas_is_user_input = models.BooleanField(default=False) + + +class CustomerPreference(models.Model): + """Store customer preferences on payment.""" + + building_id = models.IntegerField() + downpayment = models.DecimalField(max_digits=10, decimal_places=2) + expected_payback = models.DecimalField(max_digits=3, decimal_places=0) + expected_net_noi_dscr = models.DecimalField(max_digits=5, decimal_places=2) diff --git a/blocnote/apps/financialInputs/static/financialInputs/scripts/app.js b/blocnote/apps/financialInputs/static/financialInputs/scripts/app.js index 9f076c4..96c887e 100644 --- a/blocnote/apps/financialInputs/static/financialInputs/scripts/app.js +++ b/blocnote/apps/financialInputs/static/financialInputs/scripts/app.js @@ -3,6 +3,7 @@ for (var utility_index in utilities) { loadInitialBillsTable(utilities[utility_index]); } loadBillsOverview(); +getCustomerPreferenceTable(); function billProjectionDatesForm(form) { /* @@ -272,3 +273,75 @@ function billsOverviewFormSubmit(data) { }); return false; } + +function customerPreferenceForm(form) { + /* Handle customer preference form submission */ + formData = new FormData(form); + const result = {}; + for (const [key, value] of formData.entries()) { + result[key] = value; + } + request('customer-preference/', { + method: 'put', + credentials: 'same-origin', + body: JSON.stringify(result), + headers: new Headers({ + 'Content-Type': 'application/json', + 'X-CSRFToken': Cookies.get('csrftoken') + }) + }).then(res => { + console.log(res); + }); + return false; +} + +function createCustomerPreferenceTable(instance) { + const customerPreferenceForm = document.querySelector('#Customer-Preference'); + if (instance.status) { + var downpayment = instance['downpayment']; + var expectedPayback = instance['expected_payback']; + var expectedNetNOIDSCR = instance['expected_net_noi_dscr'] + } + else { + var downpayment = 0; + var expectedPayback = 999; + var expectedNetNOIDSCR = 1.15 + } + var text = ` + + + + + + + + + + + + + + + + + + + + +
PreferenceValue
Affordable Downpayment
Expected PaybackMonths
Expected Net NOI DSCR
+ ` + customerPreferenceForm.innerHTML = text; +} + +function getCustomerPreferenceTable() { + request(`customer-preference/`, { + method: 'get', + credentials: 'same-origin', + headers: { + 'Content-Type': 'application/json' + }, + }).then(res => { + console.log(res); + createCustomerPreferenceTable(res.payload.instance); + }); +} diff --git a/blocnote/apps/financialInputs/templates/financialInputs/customerPreference.html b/blocnote/apps/financialInputs/templates/financialInputs/customerPreference.html new file mode 100644 index 0000000..ec52556 --- /dev/null +++ b/blocnote/apps/financialInputs/templates/financialInputs/customerPreference.html @@ -0,0 +1,6 @@ +

+ Customer Preference +

+
+
+ diff --git a/blocnote/apps/financialInputs/templates/financialInputs/index.html b/blocnote/apps/financialInputs/templates/financialInputs/index.html index f615ef0..25a35b7 100644 --- a/blocnote/apps/financialInputs/templates/financialInputs/index.html +++ b/blocnote/apps/financialInputs/templates/financialInputs/index.html @@ -22,6 +22,9 @@
{% include "financialInputs/billsOverview.html" %}
+
+ {% include "financialInputs/customerPreference.html" %} +
{% endblock %} {% block scripts %} diff --git a/blocnote/apps/financialInputs/urls.py b/blocnote/apps/financialInputs/urls.py index 7f66bed..72b7fbd 100644 --- a/blocnote/apps/financialInputs/urls.py +++ b/blocnote/apps/financialInputs/urls.py @@ -7,4 +7,5 @@ urlpatterns = [ url(r'^finance-overview/$', views.BlocNoteHeader.as_view(), name='header'), url(r'^bills/$', views.BillsTable.as_view(), name='bills'), url(r'^bills-overview/$', views.BillsOverviewView.as_view(), name='bills_overview'), + url(r'^customer-preference/$', views.CustomerPreferenceView.as_view(), name='customer_preference'), ] diff --git a/blocnote/apps/financialInputs/views.py b/blocnote/apps/financialInputs/views.py index 0488f73..646d8c7 100644 --- a/blocnote/apps/financialInputs/views.py +++ b/blocnote/apps/financialInputs/views.py @@ -4,7 +4,7 @@ from django.http import JsonResponse from django.db import connections from django.views import View -from .models import FinancingOverview, Bills, BillsOverview +from .models import FinancingOverview, Bills, BillsOverview, CustomerPreference from .forms import BlocNoteHeaderForm @@ -451,3 +451,41 @@ class BillsOverviewView(View): new_instance = self.get_instance(building_id) return JsonResponse({'status': new_instance}) + + +class CustomerPreferenceView(View): + + model = CustomerPreference + + def put(self, request, building_id): + put = json.loads(request.body.decode()) + print(put) + obj = self.model.objects.filter(building_id=building_id) + if(obj): + obj.update( + building_id=building_id, + downpayment=put['Affordable-Downpayment'], + expected_payback=put['Expected-Payback'], + expected_net_noi_dscr=put['Expected-NOI-DSCR'] + ) + else: + self.model.objects.create( + building_id=building_id, + downpayment=put['Affordable-Downpayment'], + expected_payback=put['Expected-Payback'], + expected_net_noi_dscr=put['Expected-NOI-DSCR'] + ) + return JsonResponse({'status': 1}) + + def get(self, request, building_id): + obj = get_model_object(self.model, building_id) + instance = {} + if obj: + instance['downpayment'] = obj.downpayment + instance['expected_payback'] = obj.expected_payback + instance['expected_net_noi_dscr'] = obj.expected_net_noi_dscr + instance['status'] = True + else: + instance['status'] = False + return JsonResponse({'instance': instance}) + -- GitLab From f47bf21d0572bdc027deca37c7396a4cc634fc6e Mon Sep 17 00:00:00 2001 From: Adarsh Murthy Date: Wed, 19 Apr 2017 18:57:37 -0400 Subject: [PATCH 2/4] Add comments to views, models and app.js for the customer preference funtions and classes. --- .../static/financialInputs/scripts/app.js | 102 ++++++++++-------- blocnote/apps/financialInputs/views.py | 34 +++++- 2 files changed, 87 insertions(+), 49 deletions(-) diff --git a/blocnote/apps/financialInputs/static/financialInputs/scripts/app.js b/blocnote/apps/financialInputs/static/financialInputs/scripts/app.js index 96c887e..5aaa430 100644 --- a/blocnote/apps/financialInputs/static/financialInputs/scripts/app.js +++ b/blocnote/apps/financialInputs/static/financialInputs/scripts/app.js @@ -5,14 +5,14 @@ for (var utility_index in utilities) { loadBillsOverview(); getCustomerPreferenceTable(); +/** + * Handle submition of the header form. Validate commissioning date is greater + * than construction start date. Create result dictionary containing the form + * data and convert into JSON to send to the backend. Upon success, load the + * Bills overview table as the Pro Forma year changes the start year of the + * Bills overview table. + */ function billProjectionDatesForm(form) { - /* - * Handle submition of the header form. Validate commissioning date is greater - * than construction start date. Create result dictionary containing the form - * data and convert into JSON to send to the backend. Upon success, load the - * Bills overview table as the Pro Forma year changes the start year of the - * Bills overview table. - */ const formData = new FormData(form); var validDate = validateDate(formData); if (!validDate) { @@ -38,8 +38,8 @@ function billProjectionDatesForm(form) { return false; } +/** Validate that commissioning date is after the construction start date. */ function validateDate(data) { - /* Validate that commissioning date is after the construction start date. */ var startDateYear = data.get('anticipated_construction_start_date_year'); var startDateMonth = data.get('anticipated_construction_start_date_month'); var startDateDay = data.get('anticipated_construction_start_date_day'); @@ -62,12 +62,12 @@ function validateDate(data) { return true; } +/** + * Load initial bills table given a utility. Send GET request to obtain + * bill information and call updateTable function to update the bills table + * with the data obtained from backend. + */ function loadInitialBillsTable(utility) { - /* - * Load initial bills table given a utility. Send GET request to obtain - * bill information and call updateTable function to update the bills table - * with the data obtained from backend. - */ const table = document.querySelector('#'+utility); request(`bills/?utility_type=${utility}`, { @@ -84,17 +84,17 @@ function loadInitialBillsTable(utility) { }) } - +/** + * Update the Bills table with the data. Function queries to get the table + * component and then updates the component with the text. + */ function updateTable(utility, text) { - /* Update the Bills table with the data. Function queries to get the table - * component and then updates the component with the text. - */ table = document.querySelector('#'+utility); table.innerHTML = text; } +/** Generate html text for a given utility and bills data from backend. */ function getText(result, utility) { - /* Generate html text for a given utility and bills data from backend. */ var text = ` @@ -116,11 +116,12 @@ function getText(result, utility) { return text; } +/** + * Upload an energy bill. Get the id of the component to identify the + * utility type. Use reader to read as text and call the sendFile function + * to send the contents to the backend. + */ function uploadFile(data) { - /* Upload an energy bill. Get the id of the component to identify the - * utility type. Use reader to read as text and call the sendFile function - * to send the contents to the backend. - */ const id = document.getElementsByClassName("show")[0].getAttribute("id"); csvFile = data.files[0]; var reader = new FileReader(); @@ -134,8 +135,8 @@ function uploadFile(data) { return false; } +/** HTTP PUT request to upload the contents of the utility bills file */ function sendFile(id, content) { - /* HTTP PUT request to upload the contents of the utility bills file */ request(`bills/`, { method: 'put', credentials: 'same-origin', @@ -151,23 +152,22 @@ function sendFile(id, content) { }); } +/** Create form tag Energy Bills Overview */ function startOverviewForm() { - /* Create form tag Energy Bills Overview */ var text = ``; return text; } +/** Create dropdown box to select estimation algorithm */ function estimationDropDownBox() { - /* Create dropdown box to select estimation algorithm */ var text = ``; return text; } - +/** Create table and column headings */ function createOverviewColumnHeaders(year) { - /* Create table and column headings */ var text = `
@@ -178,9 +178,8 @@ function createOverviewColumnHeaders(year) { `; return text; } - +/** Display if user input is needed or not */ function createFlag(state) { - /* Display if user input is needed or not */ if(state) { text = `Need User Input`; } @@ -190,11 +189,12 @@ function createFlag(state) { return text; } +/** + * Create input field. Add attribute readonly if value is grabbed from + * database. If value is not from database, make it a user input. Name + * the input along with utility type to uniquely identify it. + */ function createInput(id, state, value) { - /* Create input field. Add attribute readonly if value is grabbed from - * database. If value is not from database, make it a user input. Name - * the input along with utility type to uniquely identify it. - */ var text = ``; var is_readonly = ``; if (!state) { @@ -204,10 +204,12 @@ function createInput(id, state, value) { return text; } +/** + * Add rows to the energy bills table. Currently adds only one entry in + * each column. Will be modified to display entries for 20 years. + */ function createOverviewRows(data) { - /* Add rows to the energy bills table. Currently adds only one entry in - * each column. Will be modified to display entries for 20 years. - */ + var user_input = ''; var text = ``; for (var utility in utilities) { @@ -229,10 +231,11 @@ function createOverviewRows(data) { return text; } +/** + * Make HTTP GET request to get the bills overview information. Call all + * the relevant functions to create the energy overview table. + */ function loadBillsOverview() { - /* Make HTTP GET request to get the bills overview information. Call all - * the relevant functions to create the energy overview table. - */ request(`bills-overview/`, { method: 'get', credentials: 'same-origin', @@ -252,11 +255,12 @@ function loadBillsOverview() { }) } +/** + * Handle Submition of energy bills overview form. Get form data and create + * a dictionary result with the formdata. Send result to backend. This will + * be modified to receive all projected rows for ~20 years. + */ function billsOverviewFormSubmit(data) { - /* Handle Submition of energy bills overview form. Get form data and create - * a dictionary result with the formdata. Send result to backend. This will - * be modified to receive all projected rows for ~20 years. - */ const formData = new FormData(data); const result = {}; for (const [key, value] of formData.entries()) { @@ -274,6 +278,9 @@ function billsOverviewFormSubmit(data) { return false; } +/** + * Handle customer preference form submit. Make a HTTP PUT request. + */ function customerPreferenceForm(form) { /* Handle customer preference form submission */ formData = new FormData(form); @@ -289,12 +296,13 @@ function customerPreferenceForm(form) { 'Content-Type': 'application/json', 'X-CSRFToken': Cookies.get('csrftoken') }) - }).then(res => { - console.log(res); }); return false; } +/** + * Create the customer preference table. Display values if previously filled else display defaults. + */ function createCustomerPreferenceTable(instance) { const customerPreferenceForm = document.querySelector('#Customer-Preference'); if (instance.status) { @@ -333,6 +341,9 @@ function createCustomerPreferenceTable(instance) { customerPreferenceForm.innerHTML = text; } +/** + * Make HTTP GET request to obtain customer preference table data if present. + */ function getCustomerPreferenceTable() { request(`customer-preference/`, { method: 'get', @@ -341,7 +352,6 @@ function getCustomerPreferenceTable() { 'Content-Type': 'application/json' }, }).then(res => { - console.log(res); createCustomerPreferenceTable(res.payload.instance); }); } diff --git a/blocnote/apps/financialInputs/views.py b/blocnote/apps/financialInputs/views.py index 646d8c7..37ca0fd 100644 --- a/blocnote/apps/financialInputs/views.py +++ b/blocnote/apps/financialInputs/views.py @@ -454,14 +454,26 @@ class BillsOverviewView(View): class CustomerPreferenceView(View): + """Create and update customer preference table.""" model = CustomerPreference def put(self, request, building_id): + """Create/Update customer preference table. + + Create a customer preference table if not present for this building + else update existing table with form data received from frontend. + + Args: + request: HTTP PUT request. + building_id: id of the building. + + Returns: + JsonResponse: Return a status that says ok. + """ put = json.loads(request.body.decode()) - print(put) obj = self.model.objects.filter(building_id=building_id) - if(obj): + if obj: obj.update( building_id=building_id, downpayment=put['Affordable-Downpayment'], @@ -475,9 +487,25 @@ class CustomerPreferenceView(View): expected_payback=put['Expected-Payback'], expected_net_noi_dscr=put['Expected-NOI-DSCR'] ) - return JsonResponse({'status': 1}) + return JsonResponse({'status': 'ok'}) def get(self, request, building_id): + """Fetch customer preference table. + + Check database if the customer preference table exists for this + building. If it does, return that data as a dictionary, else return + status saying false. + + Args: + request: HTTP GET request. + building_id: id of the building. + + Returns: + JsonResponse: Return instance as a JSON. Instance is a dictionary + that contains a status which is true of the table is + present, else says false. If table is present, + instance also contains the table values. + """ obj = get_model_object(self.model, building_id) instance = {} if obj: -- GitLab From 350d0d9cfedc4b3fcd45c655cf3cb7e69a9ef9d1 Mon Sep 17 00:00:00 2001 From: Adarsh Murthy Date: Thu, 20 Apr 2017 09:42:07 -0400 Subject: [PATCH 3/4] Make methods get and put all caps in request. Reorder customer preference table creation function to have fewer lines of code as per Conrad's suggestion. --- .../static/financialInputs/scripts/app.js | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/blocnote/apps/financialInputs/static/financialInputs/scripts/app.js b/blocnote/apps/financialInputs/static/financialInputs/scripts/app.js index 5aaa430..4efc7be 100644 --- a/blocnote/apps/financialInputs/static/financialInputs/scripts/app.js +++ b/blocnote/apps/financialInputs/static/financialInputs/scripts/app.js @@ -24,7 +24,7 @@ function billProjectionDatesForm(form) { result[key] = value; } request('finance-overview/', { - method: 'put', + method: 'PUT', credentials: 'same-origin', body: JSON.stringify(result), headers: new Headers({ @@ -71,7 +71,7 @@ function loadInitialBillsTable(utility) { const table = document.querySelector('#'+utility); request(`bills/?utility_type=${utility}`, { - method: 'get', + method: 'GET', credentials: 'same-origin', headers: { 'Content-Type': 'application/json' @@ -138,7 +138,7 @@ function uploadFile(data) { /** HTTP PUT request to upload the contents of the utility bills file */ function sendFile(id, content) { request(`bills/`, { - method: 'put', + method: 'PUT', credentials: 'same-origin', body: JSON.stringify(content), headers: new Headers({ @@ -237,7 +237,7 @@ function createOverviewRows(data) { */ function loadBillsOverview() { request(`bills-overview/`, { - method: 'get', + method: 'GET', credentials: 'same-origin', headers: { 'Content-Type': 'application/json' @@ -267,7 +267,7 @@ function billsOverviewFormSubmit(data) { result[key] = value; } request(`bills-overview/`, { - method: 'put', + method: 'PUT', credentials: 'same-origin', body: JSON.stringify(result), headers: new Headers({ @@ -305,16 +305,15 @@ function customerPreferenceForm(form) { */ function createCustomerPreferenceTable(instance) { const customerPreferenceForm = document.querySelector('#Customer-Preference'); + var downpayment = 0; + var expectedPayback = 999; + var expectedNetNOIDSCR = 1.15 + if (instance.status) { var downpayment = instance['downpayment']; var expectedPayback = instance['expected_payback']; var expectedNetNOIDSCR = instance['expected_net_noi_dscr'] } - else { - var downpayment = 0; - var expectedPayback = 999; - var expectedNetNOIDSCR = 1.15 - } var text = `
@@ -346,7 +345,7 @@ function createCustomerPreferenceTable(instance) { */ function getCustomerPreferenceTable() { request(`customer-preference/`, { - method: 'get', + method: 'GET', credentials: 'same-origin', headers: { 'Content-Type': 'application/json' -- GitLab From 8b67e3a857b47e3dffdcee207cc5bf32fdcf7674 Mon Sep 17 00:00:00 2001 From: Adarsh Murthy Date: Thu, 20 Apr 2017 09:45:40 -0400 Subject: [PATCH 4/4] Make customer preference table submit request put all caps. --- .../apps/financialInputs/static/financialInputs/scripts/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blocnote/apps/financialInputs/static/financialInputs/scripts/app.js b/blocnote/apps/financialInputs/static/financialInputs/scripts/app.js index 4efc7be..cfc0187 100644 --- a/blocnote/apps/financialInputs/static/financialInputs/scripts/app.js +++ b/blocnote/apps/financialInputs/static/financialInputs/scripts/app.js @@ -289,7 +289,7 @@ function customerPreferenceForm(form) { result[key] = value; } request('customer-preference/', { - method: 'put', + method: 'PUT', credentials: 'same-origin', body: JSON.stringify(result), headers: new Headers({ -- GitLab