diff --git a/blocnote/apps/financialInputs/migrations/0013_auto_20170424_2158.py b/blocnote/apps/financialInputs/migrations/0013_auto_20170424_2158.py
new file mode 100644
index 0000000000000000000000000000000000000000..781d3464cd0629f108aebe0392a0987857d9ae3b
--- /dev/null
+++ b/blocnote/apps/financialInputs/migrations/0013_auto_20170424_2158.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.6 on 2017-04-24 21:58
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('financialInputs', '0012_customerpreference'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='EstimationAlgorithm',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('building_id', models.IntegerField()),
+ ('algorithm', models.CharField(max_length=100)),
+ ],
+ ),
+ migrations.RemoveField(
+ model_name='billsoverview',
+ name='estimation_algorithm',
+ ),
+ ]
diff --git a/blocnote/apps/financialInputs/migrations/0015_auto_20170424_2250.py b/blocnote/apps/financialInputs/migrations/0015_auto_20170424_2250.py
new file mode 100644
index 0000000000000000000000000000000000000000..e350b035d62e87880c7bb1b48c93568b0297324e
--- /dev/null
+++ b/blocnote/apps/financialInputs/migrations/0015_auto_20170424_2250.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.6 on 2017-04-24 22:50
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('financialInputs', '0013_auto_20170424_2158'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='estimationalgorithm',
+ name='algorithm',
+ field=models.CharField(max_length=16),
+ ),
+ ]
diff --git a/blocnote/apps/financialInputs/models.py b/blocnote/apps/financialInputs/models.py
index 139bfb31abb126c3861ab4384d7e22ef8a989137..14e63987d192abb9720883ac08ba491f9bafbf93 100644
--- a/blocnote/apps/financialInputs/models.py
+++ b/blocnote/apps/financialInputs/models.py
@@ -42,12 +42,18 @@ class Bills(models.Model):
charge = models.DecimalField(max_digits=10, decimal_places=2)
+class EstimationAlgorithm(models.Model):
+ """Estimation algorithm used to project bills for pro forma duration."""
+
+ algorithm = models.CharField(max_length=16)
+ building_id = models.IntegerField()
+
+
class BillsOverview(models.Model):
"""Store annual charge of each utility used for bill projection."""
building_id = models.IntegerField()
year = models.DecimalField(max_digits=4, decimal_places=0)
- estimation_algorithm = models.CharField(max_length=100)
electricity = models.DecimalField(max_digits=10, decimal_places=2)
electricity_is_user_input = models.BooleanField(default=False)
water = models.DecimalField(max_digits=10, decimal_places=2)
diff --git a/blocnote/apps/financialInputs/static/financialInputs/scripts/app.js b/blocnote/apps/financialInputs/static/financialInputs/scripts/app.js
index cfc018772ee7c48ae402e85cb6aec8d297d382e2..4f042d4faf16b607d16f61ac2bdff59e5c56d2fe 100644
--- a/blocnote/apps/financialInputs/static/financialInputs/scripts/app.js
+++ b/blocnote/apps/financialInputs/static/financialInputs/scripts/app.js
@@ -31,8 +31,6 @@ function billProjectionDatesForm(form) {
'Content-Type': 'application/json',
'X-CSRFToken': Cookies.get('csrftoken')
})
- }).then(res => {
- loadBillsOverview();
});
}
return false;
@@ -95,19 +93,24 @@ function updateTable(utility, text) {
/** Generate html text for a given utility and bills data from backend. */
function getText(result, utility) {
+ units = {};
+ units['electricity'] = `kWh`;
+ units['gas'] = `mmBTU`;
+ units['oil'] = `mmBTU`;
+ units['water'] = `Gallons`;
var text = `
Date From
Date To
-
Usage
+
Usage (${units[utility]})
Bill Charge ($)
`;
- for(var i =0; i`;
- for(var j=0; j` + result[i][j] + ``;
}
text += ``;
@@ -148,39 +151,75 @@ function sendFile(id, content) {
}).then(res => {
var text = getText(res.payload.result, id);
updateTable(id, text);
- loadBillsOverview();
});
}
+function createEstimateModelForm() {
+ var estimateModelForm = ``;
+ estimateModelForm += `
+ `;
+ return estimateModelForm;
+}
+
/** Create form tag Energy Bills Overview */
-function startOverviewForm() {
- var text = ``;
+ text += `
+
+
+
Total Annual Charge
+ `;
+ for (var charge in data['total_annual_charge']) {
+ text += `
+
$${data['total_annual_charge'][charge]}
+ `;
+ }
+ text += `
+
+
+ `;
+ return text;
+}
+
+/**Create the calculate button to project bill with given data. */
+function createCalculateButton() {
+ text = `
+
+
+
+ `;
+ return text;
+}
+
+/**Create button to submit the projected and input data. */
+function createSubmitButton() {
+ text = `
+
+
+
+ `;
return text;
}
@@ -245,22 +326,22 @@ function loadBillsOverview() {
}).then(res => {
if(!res.err) {
const table = document.querySelector('#Energy-Bills-Overview');
- var text = "";
- text += startOverviewForm();
- text += estimationDropDownBox();
- text += createOverviewColumnHeaders(res.payload.instance.year);
- text += createOverviewRows(res.payload.instance);
+ var text = ``;
+ text += createEstimateModelForm();
+ if(res.payload.instance.present) {
+ text += createBillsOverviewTable(res.payload.instance);
+ }
table.innerHTML = text;
}
})
}
/**
- * Handle Submition of energy bills overview form. Get form data and create
+ * Handle Submission 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) {
+function billsOverviewFormCalculate(data) {
const formData = new FormData(data);
const result = {};
for (const [key, value] of formData.entries()) {
@@ -274,6 +355,34 @@ function billsOverviewFormSubmit(data) {
'Content-Type': 'application/json',
'X-CSRFToken': Cookies.get('csrftoken')
})
+ }).then(res => {
+ if(res.payload.instance['err']) {
+ alert(res.payload.instance['msg']);
+ return false;
+ }
+ table = document.querySelector('#Energy-Bills-Overview')
+ var text = ``;
+ text += createEstimateModelForm();
+ text += createBillsOverviewTable(res.payload.instance)
+ table.innerHTML = text;
+ });
+ return false;
+}
+
+function billsOverviewFormSubmit(form) {
+ const formData = new FormData(form);
+ const result = {};
+ for (const [key, value] of formData.entries()) {
+ result[key] = value;
+ }
+ request(`bills-overview/`, {
+ method: 'POST',
+ credentials: 'same-origin',
+ body: JSON.stringify(result),
+ headers: new Headers({
+ 'Content-Type': 'application/json',
+ 'X-CSRFToken': Cookies.get('csrftoken')
+ })
});
return false;
}
@@ -314,7 +423,7 @@ function createCustomerPreferenceTable(instance) {
var expectedPayback = instance['expected_payback'];
var expectedNetNOIDSCR = instance['expected_net_noi_dscr']
}
- var text = `
+ var text = `
Preference
diff --git a/blocnote/apps/financialInputs/views.py b/blocnote/apps/financialInputs/views.py
index 37ca0fd0e47eceb7f6cc6a147240c1adcfaae244..f99a8b55dfb0195e5a6c5bb391651f3a96535323 100644
--- a/blocnote/apps/financialInputs/views.py
+++ b/blocnote/apps/financialInputs/views.py
@@ -4,7 +4,9 @@ from django.http import JsonResponse
from django.db import connections
from django.views import View
-from .models import FinancingOverview, Bills, BillsOverview, CustomerPreference
+from bpfin.utilbills.bill_backend_call import bill_prior_proj_rough_annual
+
+from .models import FinancingOverview, Bills, BillsOverview, CustomerPreference, EstimationAlgorithm
from .forms import BlocNoteHeaderForm
@@ -289,29 +291,101 @@ class BillsTable(View):
return JsonResponse({'result': result, 'present': present})
-def get_total_charge(obj):
- """Get total utility charge.
+def get_total_charge(utility_type, analysis_date, building_id):
+ """Get annual total utility charge.
+
+ Obtain annual charge for a utility for every year from the Pro Forma start year till end year. Make calls to bpfin
+ to perform the tasks.
+
+ Args:
+ utility_type: Which utility type.
+ analysis_date: Dictionary containing the Pro Forma start date and duration.
+ building_id: id of the building.
+
+ Returns:
+ annual_bill: Dictionary with year as keys and the annual charge for that year as value.
+ """
+ bills_object = Bills.objects.filter(
+ building_id=building_id,
+ utility_type=utility_type,
+ )
+
+ if bills_object:
+ raw_bill = {}
+ raw_bill['utility_type'] = utility_type
+ raw_bill['date_from'] = []
+ raw_bill['date_to'] = []
+ raw_bill['charge'] = []
+ raw_bill['usage'] = []
+
+ for bill in bills_object:
+ raw_bill['date_from'].append(bill.date_from)
+ raw_bill['date_to'].append(bill.date_to)
+ raw_bill['usage'].append(float(bill.usage))
+ raw_bill['charge'].append(float(bill.charge))
+ annual_bill = bill_prior_proj_rough_annual(raw_bill, analysis_date)
+ else:
+ annual_bill = {}
+ objs = BillsOverview.objects.filter(
+ building_id=building_id,
+ )
+ if objs:
+ for obj in objs:
+ store_year = str(obj.year)
+ if utility_type == 'electricity':
+ annual_bill[store_year] = obj.electricity
+ elif utility_type == 'gas':
+ annual_bill[store_year] = obj.gas
+ elif utility_type == 'oil':
+ annual_bill[store_year] = obj.oil
+ elif utility_type == 'water':
+ annual_bill[store_year] = obj.water
+ else:
+ for year in range(analysis_date['proforma_duration']):
+ store_year = str(analysis_date['proforma_start'].year + year)
+ annual_bill[store_year] = 0
+ for year in annual_bill:
+ annual_bill[year] = float("{0:.2f}".format(annual_bill[year]))
+ annual_bill = {str(key): value for key, value in annual_bill.items()}
+ return annual_bill
+
+
+def get_if_user_input(building_id):
+ """Check if utility charge input was user or from bills.
- Obtain the total charge for a utility. This function will be replaced by
- finance team logic.
+ Check if the utility charge obtained from bills stored or by user input. Query bills database to check if an
+ entry has been made for this building.
Args:
- object: Model object which contains the charge value.
+ building_id: id of the building.
Returns:
- total: The sum of all charges for the utility.
+ e_user, g_user, o_user, w_user: Boolean for each utility.
"""
- total = 0
- for row in obj:
- total += row.charge
- return total
+ electricity_obj = Bills.objects.filter(
+ building_id=building_id,
+ utility_type='electricity',
+ )
+ gas_obj = Bills.objects.filter(
+ building_id=building_id,
+ utility_type='gas',
+ )
+ oil_obj = Bills.objects.filter(
+ building_id=building_id,
+ utility_type='oil',
+ )
+ water_obj = Bills.objects.filter(
+ building_id=building_id,
+ utility_type='water',
+ )
+ return not electricity_obj, not gas_obj, not oil_obj, not water_obj
class BillsOverviewView(View):
"""Generate Energy Bills Overview table.
- Generate energy bills overview table from the energy bills data. If bill not
- available, take user input for calculation purposes.
+ Generate energy bills overview table from the energy bills data. If bill
+ not available, take user input for calculation purposes.
"""
model_bills_overview = BillsOverview
@@ -321,9 +395,10 @@ class BillsOverviewView(View):
def get(self, request, building_id):
"""Handle HTTP GET request.
- Generate energy bills overview table with bills present in the
- database. If a certain utility bill is absent, allow user to input
- data.
+ Generate energy bills overview table with bills present in the database. If a certain utility bill is absent,
+ allow user to input value manually. Call bpfin functions to project bill charges from the Pro Forma start date
+ for the Pro Forma period. Store projected values as well as manually inputs. On page load, must fetch actual
+ and projected values.
Args:
request: HTTP GET request.
@@ -333,124 +408,134 @@ class BillsOverviewView(View):
JsonResponse: Returns instance, which is a dictionary containing
all the data to be filled in the table.
"""
- instance = self.get_instance(building_id)
- return JsonResponse({'instance': instance})
+ objs = self.model_bills_overview.objects.filter(building_id=building_id)
+ result = {}
+ total_annual_charge = []
+ if objs:
+ result['present'] = True
+ else:
+ result['present'] = False
+ result['electricity'] = {}
+ result['gas'] = {}
+ result['oil'] = {}
+ result['water'] = {}
+ result['electricity_user'] = True
+ result['gas_user'] = True
+ result['oil_user'] = True
+ result['water_user'] = True
+ for obj in objs:
+ store_year = str(obj.year)
+ result['electricity'][store_year] = float("{0:.2f}".format(obj.electricity))
+ result['gas'][store_year] = float("{0:.2f}".format(obj.gas))
+ result['oil'][store_year] = float("{0:.2f}".format(obj.oil))
+ result['water'][store_year] = float("{0:.2f}".format(obj.water))
+ result['electricity_user'] = obj.electricity_is_user_input
+ result['gas_user'] = obj.gas_is_user_input
+ result['oil_user'] = obj.oil_is_user_input
+ result['water_user'] = obj.water_is_user_input
+ total_annual_charge.append(obj.electricity + obj.gas + obj.oil + obj.water)
+ result['total_annual_charge'] = total_annual_charge
+
+ return JsonResponse({'instance': result})
- def get_instance(self, building_id):
- """Create dictionary instance.
+ def put(self, request, building_id):
+ """Handle HTTP PUT request.
- This dictionary is an instance of the data present in the database. It
- contains the annual utility charge(for now, this will be replaced by
- value obtained from finance logic), Pro Forma start year and flags
- indicating if a utility is present in the database. This is to tell the
- frontend if an input has to be taken or not.
+ Take annual utility charge and projection option from frontend and project bills for given Pro Forma start
+ date and duration. Pass this value as a dictionary to the frontend.
Args:
+ request: HTTP PUT request.
building_id: id of the building.
Returns:
- instance: A dictionary containing the annual utility charge and a
- flag indicating if utility bill present or not.
+ JsonResponse: Returns new instance with the updated values.
"""
- instance = {}
-
- try:
- obj = FinancingOverview.objects.get(building_id=building_id)
- date = obj.pro_forma_start_date
- year = date.year
- except:
- year = 'TBD'
-
- utility_objects = {}
- for util in self.utility:
- utility_objects[util] = self.model_bills.objects.filter(
+ put = json.loads(request.body.decode())
+ estimation_algorithm_obj = EstimationAlgorithm.objects.filter(building_id=building_id)
+ if estimation_algorithm_obj:
+ estimation_algorithm_obj.update(
building_id=building_id,
- utility_type=util
- )
-
- for util in self.utility:
- instance[util] = 0
- instance[util+'_is_user_input'] = True
-
- for util in self.utility:
- if utility_objects[util]:
- instance[util] = get_total_charge(
- utility_objects[util]
- )
- instance[util+'_is_user_input'] = False
- else:
- try:
- bills_overview_obj = self.model_bills_overview.objects.get(
- building_id=building_id
- )
- if util == 'electricity':
- instance[util] = bills_overview_obj.electricity
- elif util == 'gas':
- instance[util] = bills_overview_obj.gas
- elif util == 'oil':
- instance[util] = bills_overview_obj.oil
- elif util == 'water':
- instance[util] = bills_overview_obj.water
- except:
- instance[util] = 0
- instance['year'] = year
-
- return instance
+ algorithm=put['Estimation Model'],
+ )
+ else:
+ EstimationAlgorithm.objects.create(
+ building_id=building_id,
+ algorithm=put['Estimation Model'],
+ )
+ projected_bills = {}
+ analysis_date = {}
+ pro_forma_object = get_model_object(FinancingOverview, building_id)
+ if not pro_forma_object:
+ projected_bills['err'] = True
+ projected_bills['msg'] = 'Please fill in bill projection date, period and funds form'
+ return JsonResponse({'instance': projected_bills})
+ analysis_date['proforma_start'] = pro_forma_object.pro_forma_start_date
+ analysis_date['proforma_duration'] = int(pro_forma_object.pro_forma_duration)
+ if put['Estimation Model'] == 'Rough Estimation':
+ projected_bills['err'] = False
+ for util in self.utility:
+ projected_bills[util] = get_total_charge(util, analysis_date, building_id)
+ e_user, g_user, o_user, w_user = get_if_user_input(building_id)
+ projected_bills['electricity_user'] = e_user
+ projected_bills['gas_user'] = g_user
+ projected_bills['oil_user'] = o_user
+ projected_bills['water_user'] = w_user
+ total_annual_charge = []
+ for year in range(analysis_date['proforma_duration']):
+ total = 0
+ store_year = str(analysis_date['proforma_start'].year + year)
+ total += float("{0:.2f}".format(projected_bills['electricity'][store_year]))
+ total += float("{0:.2f}".format(projected_bills['gas'][store_year]))
+ total += float("{0:.2f}".format(projected_bills['oil'][store_year]))
+ total += float("{0:.2f}".format(projected_bills['water'][store_year]))
+ total_annual_charge.append(total)
+ projected_bills['total_annual_charge'] = total_annual_charge
+ else:
+ projected_bills['err'] = True
+ projected_bills['msg'] = 'Only Rough Estimation available at this point'
+ return JsonResponse({'instance': projected_bills})
- def put(self, request, building_id):
- """Handle HTTP PUT request.
+ def post(self, request, building_id):
+ """Handle HTTP POST request.
- Take annual utility charge and projection option from frontend and
- store in the database. This will be modified to call the finance
- projection fuction.
+ Get annual utility charge for the Pro Forma duration from Pro Forma start date and store in the database.
+ If data for this building is already present, they are deleted before storing new data.
Args:
- request: HTTP PUT request.
+ request: HTTP POST request.
building_id: id of the building.
Returns:
- JsonResponse: Returns new instance with the updated values.
+ JsonResponse: A dictionary with status OK.
"""
- put = json.loads(request.body.decode())
-
- entry = self.model_bills_overview.objects.filter(
- building_id=building_id
- )
-
- instance = self.get_instance(building_id)
-
- if entry:
- entry.update(
+ post = json.loads(request.body.decode())
+ self.model_bills_overview.objects.filter(building_id=building_id).delete()
+ analysis_date = {}
+ e_user, g_user, o_user, w_user = get_if_user_input(building_id)
+ financing_overview_obj = FinancingOverview.objects.get(building_id=building_id)
+ analysis_date['proforma_start'] = financing_overview_obj.pro_forma_start_date
+ analysis_date['proforma_duration'] = int(financing_overview_obj.pro_forma_duration)
+ for i in range(analysis_date['proforma_duration']):
+ store_year = str(analysis_date['proforma_start'].year + i)
+ e_search = 'electricity-value-' + store_year
+ g_search = 'gas-value-' + store_year
+ o_search = 'oil-value-' + store_year
+ w_search = 'water-value-' + store_year
+ self.model_bills_overview.objects.create(
building_id=building_id,
- year=instance['year'],
- electricity=put['electricity-value'],
- electricity_is_user_input=instance['electricity_is_user_input'],
- gas=put['gas-value'],
- gas_is_user_input=instance['gas_is_user_input'],
- oil=put['oil-value'],
- oil_is_user_input=instance['oil_is_user_input'],
- water=put['water-value'],
- water_is_user_input=instance['water_is_user_input'],
- estimation_algorithm=put['Estimation Model']
- )
- else:
- entry = self.model_bills_overview.objects.create(
- building_id=building_id,
- year=instance['year'],
- electricity=put['electricity-value'],
- electricity_is_user_input=instance['electricity_is_user_input'],
- gas=put['gas-value'],
- gas_is_user_input=instance['gas_is_user_input'],
- oil=put['oil-value'],
- oil_is_user_input=instance['oil_is_user_input'],
- water=put['water-value'],
- water_is_user_input=instance['water_is_user_input'],
- estimation_algorithm=put['Estimation Model']
+ year=int(store_year),
+ electricity=post[e_search],
+ gas=post[g_search],
+ oil=post[o_search],
+ water=post[w_search],
+ electricity_is_user_input=e_user,
+ gas_is_user_input=g_user,
+ oil_is_user_input=o_user,
+ water_is_user_input=w_user
)
- new_instance = self.get_instance(building_id)
-
- return JsonResponse({'status': new_instance})
+ return JsonResponse({'status': 'OK'})
class CustomerPreferenceView(View):