diff --git a/.gitignore b/.gitignore index 4db2aa842187c3a007a4438a4de4a89579760a9a..0597f96a51d3664e616f11f90750a853eba575eb 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,5 @@ node_modules .idea .vscode/ /static -.coverage +*.coverage +*.swp diff --git a/blocnote/apps/financialInputs/forms.py b/blocnote/apps/financialInputs/forms.py index bca424db326cd75f84eee2d40b93206690ad012c..ce532fc9d92b616b208f37d3c80da30493b1a4d9 100644 --- a/blocnote/apps/financialInputs/forms.py +++ b/blocnote/apps/financialInputs/forms.py @@ -1,10 +1,10 @@ """Forms to render and validate for financial-inputs endpoint.""" from django.forms import ModelForm -from blocnote.apps.financialInputs.models import FinancingOverview +from blocnote.apps.financialInputs.models import FinancingOverview, CustomerPreference class ProformaInputsForm(ModelForm): - """Define the form to input/display proforma information.""" + """Define the form to validate proforma information.""" class Meta: """Choose the model and the relevant fields for the form.""" @@ -19,3 +19,17 @@ class ProformaInputsForm(ModelForm): 'anticipated_commissioning_date', 'anticipated_construction_period', ] + + +class CustomerPreferenceForm(ModelForm): + """Define the form to validate customer preference form.""" + + class Meta: + """Choose the model and the relevant fields for the form.""" + + model = CustomerPreference + fields = [ + 'downpayment', + 'expected_payback', + 'expected_net_noi_dscr', + ] diff --git a/blocnote/apps/financialInputs/old_views.py b/blocnote/apps/financialInputs/old_views.py index c2a86ae9b4c89b96919e5e2bafec6427ff9c9607..9298d3ddc512ebb25733d95ffd9a6d3d67c2e149 100644 --- a/blocnote/apps/financialInputs/old_views.py +++ b/blocnote/apps/financialInputs/old_views.py @@ -7,12 +7,13 @@ from django.http import JsonResponse from django.db import connections from django.views import View -from bpfin.back_end_call.back_end_inputs import monthly_bill -from bpfin.back_end_call.back_end_inputs import form_prior_income_table as prior_income_statement_table +from bpfin.back_end_call.back_end_inputs import monthly_bill, form_prior_income_table as prior_income_statement_table -from .models import Fund, FinancingOverview, Bills, BillsOverview, CustomerPreference, EstimationAlgorithm -from .models import Liabilities, CashBalance, IncomeStatement, LoanOptions, DefaultLoan, Lender, GrowthRate +from .models import ( + FinancingOverview, Bills, BillsOverview, EstimationAlgorithm, Liabilities, CashBalance, IncomeStatement, + LoanOptions, DefaultLoan, Lender, GrowthRate +) def get_analysis_date(building_id): @@ -504,69 +505,6 @@ class BillsOverviewView(View): return JsonResponse({}) -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()) - 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({}) - - 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: - instance['downpayment'] = obj.downpayment - instance['expected_payback'] = obj.expected_payback - instance['expected_net_noi_dscr'] = obj.expected_net_noi_dscr - return JsonResponse({'instance': instance}) - return JsonResponse({}) - - class LiabilitiesTable(View): """Store and load Mortgage and Liability information for a building id.""" diff --git a/blocnote/apps/financialInputs/static/financialInputs/scripts/app.js b/blocnote/apps/financialInputs/static/financialInputs/scripts/app.js index c679f63f565bd025f39d56d915e6b73df1e40458..416d0b5c4ec60e827876cb18f74e08f7ef81c529 100644 --- a/blocnote/apps/financialInputs/static/financialInputs/scripts/app.js +++ b/blocnote/apps/financialInputs/static/financialInputs/scripts/app.js @@ -10,7 +10,7 @@ for (var utility_index in utilities) { } loadBillsOverview(); getIncomeStatementTable(); -getCustomerPreferenceTable(); + getLiabilitiesTable(); getCashBalanceForm(); getLoanOptionsTable(); @@ -417,95 +417,6 @@ function billsOverviewFormSubmit(form) { return false; } -// Watch customer preference to display/erase error/success mesaages. -var customerPreference = document.querySelector('#Customer-Preference'); -customerPreference.onchange = function() { - document.querySelector('#customer-preference-warning-message').innerHTML = ''; -} - -/** - * Handle customer preference form submit. Make a HTTP PUT request. - */ -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 => { - if (!res.payload.err) { - document.querySelector('#customer-preference-warning-message').innerHTML = ` - Saved - `; - } - }); - return false; -} - -/** - * Create the customer preference table. Display values if previously filled else display defaults. - */ -function createCustomerPreferenceTable(instance) { - const customerPreferenceForm = document.querySelector('#Customer-Preference'); - var downpayment = 0; - var expectedPayback = 999; - var expectedNetNOIDSCR = 1.15 - - if (instance) { - var downpayment = instance['downpayment']; - var expectedPayback = instance['expected_payback']; - var expectedNetNOIDSCR = instance['expected_net_noi_dscr'] - } - var text = ` - - - - - - - - - - - - - - - - - - - - - -
PreferenceValue
Affordable Downpayment
Expected PaybackMonths
Expected Net NOI DSCR
- - `; - customerPreferenceForm.innerHTML = text; -} - -/**Make HTTP GET request to obtain customer preference table data if present. */ -function getCustomerPreferenceTable() { - request(`customer-preference/`, { - method: 'GET', - credentials: 'same-origin', - headers: { - 'Content-Type': 'application/json' - }, - }).then(res => { - createCustomerPreferenceTable(res.payload.instance); - }); -} - /** * Load the Mortgage and Liabilities table. * This function loads the mortgage and liabilities table with the given inputList. If inputList is empty, it loads a diff --git a/blocnote/apps/financialInputs/static/financialInputs/scripts/customerPreference.js b/blocnote/apps/financialInputs/static/financialInputs/scripts/customerPreference.js new file mode 100644 index 0000000000000000000000000000000000000000..d4011be5f8ef6138508be8dba8f92527603f88ac --- /dev/null +++ b/blocnote/apps/financialInputs/static/financialInputs/scripts/customerPreference.js @@ -0,0 +1,132 @@ +'use strict'; + +getCustomerPreferenceTable(); + +// Watch customer preference to display/erase error/success mesaages. +const customerPreference = document.querySelector('#Customer-Preference'); +customerPreference.onchange = function () { + document.querySelector('#customer-preference-warning-message').innerHTML = ''; + let table = document.querySelector('#customer-preference-table'); + table.querySelector('#downpayment-error').innerHTML = ''; + table.querySelector('#expected_payback-error').innerHTML = ''; + table.querySelector('#expected_net_noi_dscr-error').innerHTML = ''; +}; + +/** + * Handle customer preference form submit. Make a HTTP PUT request. If there was an error, display them else show + * saved. + * + * @param {any} form : form with the inputs filled in form html. + * @returns : false so that the document does not reload. + */ +function customerPreferenceForm(form) { + /* Handle customer preference form submission */ + const formData = new FormData(form); + let 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 => { + if (!res.err) { + document.querySelector('#customer-preference-warning-message').innerHTML = ` + Saved + `; + } + else { + res.err.responseBody.then((errorDict) => { + Object.keys(errorDict).forEach(function (key) { + document.querySelector('#' + key + '-error').innerHTML = ` + ${errorDict[key][0]} + `; + }); + }); + } + }); + return false; +} + +/** + * Create the customer preference table. Display values if previously filled else display defaults. + * + * @param {any} instance : Data received from the backend. This can be empty. + */ +function createCustomerPreferenceTable(instance) { + let customerPreferenceForm = document.querySelector('#Customer-Preference'); + let downpayment = 0; + let expectedPayback = 999; + let expectedNetNOIDSCR = 1.15; + + if (instance) { + downpayment = instance['downpayment']; + expectedPayback = instance['expected_payback']; + expectedNetNOIDSCR = instance['expected_net_noi_dscr']; + } + customerPreferenceForm.innerHTML = ` + + + + + + + + + + + + + + + + + + + + + +
PreferenceValue
Affordable Downpayment + +
+
+
Expected Payback + Months +
+
+
Expected Net NOI DSCR + +
+
+
+ + `; +} + +/** + * Make HTTP GET request to obtain customer preference table data if present. + * + */ +function getCustomerPreferenceTable() { + request('customer-preference/', { + method: 'GET', + credentials: 'same-origin', + headers: { + 'Content-Type': 'application/json' + }, + }).then(res => { + if (!res.err) { + createCustomerPreferenceTable(res.payload.instance); + } + else { + document.querySelector('#customer-preference-warning-message').innerHTML = ` + There was an error loading the table. + `; + } + }); +} diff --git a/blocnote/apps/financialInputs/templates/financialInputs/index.html b/blocnote/apps/financialInputs/templates/financialInputs/index.html index 064a91370da324dd5c9e636745eb7de9fa07962e..edf4892314b507a29bad191a75285fa18b4fe616 100644 --- a/blocnote/apps/financialInputs/templates/financialInputs/index.html +++ b/blocnote/apps/financialInputs/templates/financialInputs/index.html @@ -56,4 +56,5 @@ + {% endblock %} diff --git a/blocnote/apps/financialInputs/urls.py b/blocnote/apps/financialInputs/urls.py index cf298f6e6286245998e7498c284ea2ab9b44427f..f27b683542619dea2052549774b359ac0e0995c4 100644 --- a/blocnote/apps/financialInputs/urls.py +++ b/blocnote/apps/financialInputs/urls.py @@ -2,6 +2,7 @@ from django.conf.urls import url from . import old_views from .views import proforma_input +from .views import customer_preference app_name = 'financial-inputs' urlpatterns = [ @@ -9,7 +10,7 @@ urlpatterns = [ url(r'^finance-overview/$', proforma_input.ProformaInputs.as_view(), name='header_new'), url(r'^bills/$', old_views.BillsTable.as_view(), name='bills'), url(r'^bills-overview/$', old_views.BillsOverviewView.as_view(), name='bills_overview'), - url(r'^customer-preference/$', old_views.CustomerPreferenceView.as_view(), name='customer_preference'), + url(r'^customer-preference/$', customer_preference.CustomerPreferenceView.as_view(), name='customer_preference'), url(r'^liabilities/$', old_views.LiabilitiesTable.as_view(), name='liabilities'), url(r'^cash-balance/$', old_views.CashBalanceView.as_view(), name='cash_balance'), url(r'^income-statement/$', old_views.IncomeStatementTable.as_view(), name='income_statement'), diff --git a/blocnote/apps/financialInputs/views/customer_preference.py b/blocnote/apps/financialInputs/views/customer_preference.py new file mode 100644 index 0000000000000000000000000000000000000000..b1a6bb572b19771adefa05b93eeda9e3adff2b3c --- /dev/null +++ b/blocnote/apps/financialInputs/views/customer_preference.py @@ -0,0 +1,69 @@ +"""Define the views for Customer Preference table.""" +import json +from django.views import View +from django.http import JsonResponse +from blocnote.apps.financialInputs.models import CustomerPreference +from blocnote.apps.financialInputs.forms import CustomerPreferenceForm + + +class CustomerPreferenceView(View): + """Create and update customer preference table.""" + + customer_preference_model = CustomerPreference + customer_preference_form = CustomerPreferenceForm + + 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 if success else return status 400 with errors if form is + invalid. + """ + put = json.loads(request.body.decode()) + form = self.customer_preference_form(put) + if form.is_valid(): + put['building_id'] = building_id + self.customer_preference_model.objects.update_or_create( + building_id=building_id, + defaults=put + ) + else: + error_dict = {} + for field, error in form.errors.items(): + error_dict[field] = error + return JsonResponse(error_dict, status=400) + return JsonResponse({}) + + 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 empty. + + Args: + request: HTTP GET request. + building_id: id of the building. + + Returns: + instance: Dictionary with all data if record present for the building else returns empty. + """ + fields = [ + 'downpayment', + 'expected_payback', + 'expected_net_noi_dscr', + ] + obj = self.customer_preference_model.objects.filter(building_id=building_id) + instance = {} + if obj: + obj = obj[0] + for field in fields: + instance[field] = obj.__dict__[field] + return JsonResponse({'instance': instance}) + return JsonResponse({})