diff --git a/blocnote/apps/preliminaryFinance/static/preliminaryFinance/scripts/app.js b/blocnote/apps/preliminaryFinance/static/preliminaryFinance/scripts/app.js
index 74ea41d226185d3ec1a58fbcbff140663999aa80..0f957c11673c1ecab955abd2890c778576010939 100644
--- a/blocnote/apps/preliminaryFinance/static/preliminaryFinance/scripts/app.js
+++ b/blocnote/apps/preliminaryFinance/static/preliminaryFinance/scripts/app.js
@@ -1,8 +1,3 @@
-costEstimationTableHead();
-costEstimationTableBody();
-savingEstimationTableHead();
-savingEstimationTableBody();
-
/**
* Return the Scenario name.
*/
@@ -11,6 +6,17 @@ function getScenarioName() {
return docs.value;
}
+/**
+ * setScenarioName() Set the name of the scenario on the tab.
+ *
+ * @param {...} scenarioName - The name of the scenario.
+ *
+ */
+function setScenarioName(scenarioName) {
+ let docs = document.querySelector('a.nav-link.active input');
+ docs.value = scenarioName;
+}
+
/**
* Add column headings to the Cost Estimation table.
*/
@@ -28,14 +34,14 @@ function costEstimationTableHead() {
/**
* Load the Cost Estimation table body.
*/
-function costEstimationTableBody() {
+function costEstimationTableBody(item, cost) {
const body = document.querySelector('#cost-estimation-table tbody');
const rowCount = body.rows.length;
const row = body.insertRow(rowCount);
let cell = row.insertCell(0);
- cell.innerHTML = '';
+ cell.innerHTML = ``;
cell = row.insertCell(1);
- cell.innerHTML = '$';
+ cell.innerHTML = ``;
cell = row.insertCell(2);
cell.innerHTML = '';
return false;
@@ -76,7 +82,7 @@ function savingEstimationTableHead() {
/**
* Load Savings Estimation Table body.
*/
-function savingEstimationTableBody() {
+function savingEstimationTableBody(utilities) {
const body = document.querySelector('#saving-estimation-table tbody');
let rowCount = body.rows.length;
let row = body.insertRow(rowCount);
@@ -84,18 +90,18 @@ function savingEstimationTableBody() {
cell.innerHTML = 'Electricity';
cell = row.insertCell(1);
cell.innerHTML = `
- %
+ %
`;
cell = row.insertCell(2);
cell.innerHTML = `
`;
cell = row.insertCell(3);
cell.innerHTML = `
`;
@@ -105,18 +111,18 @@ function savingEstimationTableBody() {
cell.innerHTML = 'Gas';
cell = row.insertCell(1);
cell.innerHTML = `
- %
+ %
`;
cell = row.insertCell(2);
cell.innerHTML = `
`;
cell = row.insertCell(3);
cell.innerHTML = `
`;
@@ -126,18 +132,18 @@ function savingEstimationTableBody() {
cell.innerHTML = 'Oil';
cell = row.insertCell(1);
cell.innerHTML = `
- %
+ %
`;
cell = row.insertCell(2);
cell.innerHTML = `
`;
cell = row.insertCell(3);
cell.innerHTML = `
`;
@@ -147,18 +153,18 @@ function savingEstimationTableBody() {
cell.innerHTML = 'Water';
cell = row.insertCell(1);
cell.innerHTML = `
- %
+ %
`;
cell = row.insertCell(2);
cell.innerHTML = `
`;
cell = row.insertCell(3);
cell.innerHTML = `
`;
return false;
@@ -195,7 +201,7 @@ function submitScenario() {
}
record = {
- 'utility_type': savingEstimationBody.rows[rowIndex].cells[0].innerHTML,
+ 'utility_type': savingEstimationBody.rows[rowIndex].cells[0].innerHTML.toLowerCase(),
'estimated_savings': savingEstimationBody.rows[rowIndex].cells[1].children[0].value,
'used_before_retrofit': beforeRetrofit,
'used_after_retrofit': afterRetrofit,
@@ -231,8 +237,10 @@ function submitScenario() {
'X-CSRFToken': Cookies.get('csrftoken')
})
}).then(res => {
- loadProjectEconomicsTable(res);
- loadGraph(res);
+ if (!res.err) {
+ loadProjectEconomicsTable(res.payload.economics_overview);
+ loadGraph(res);
+ }
});
return false;
}
@@ -241,10 +249,9 @@ function submitScenario() {
* Take the response as argument and display the project economics table. This is the summary of the priliminary
* analysis that gives vital information about the financial health of the building.
*/
-function loadProjectEconomicsTable(res) {
+function loadProjectEconomicsTable(economicsOverview) {
const title = document.querySelector('#project-economics-title');
title.innerHTML = 'Project Economics';
- const economicsOverview = res.payload.economics_overview;
const body = document.querySelector('#project-economics-table tbody');
addPERow(body, economicsOverview);
}
@@ -312,3 +319,66 @@ function loadGraph(res) {
new Chart(ctx, config);
}
+/**
+ * getScenario() Do a GET request to the backend. If scenario previously stored, populate the cost and savings table
+ * as well as fill project economics and generate the savings schedule graph. If not, display new cost and savings form
+ * to be filled.
+ *
+ */
+function getScenario() {
+ request('scenario/', {
+ method: 'GET',
+ credentials: 'same-origin',
+ headers: new Headers({
+ 'Content-Type': 'application/json',
+ 'X-CSRFToken': Cookies.get('csrftoken')
+ })
+ }).then((res) => {
+ if (!res.err) {
+ if (Object.keys(res.payload.economics_overview).length > 0 ) {
+ loadProjectEconomicsTable(res.payload.economics_overview);
+ loadGraph(res);
+ }
+ costEstimationTableHead();
+ if (Object.keys(res.payload.costs).length > 0) {
+ res.payload.costs.forEach((costItem) => {
+ costEstimationTableBody(costItem.cost_item, costItem.cost);
+ });
+ } else {
+ costEstimationTableBody('', '');
+ }
+ savingEstimationTableHead();
+ let savings = {};
+ if (Object.keys(res.payload.savings).length > 0) {
+ savings = res.payload.savings;
+ } else {
+ savings = {
+ 'electricity': {
+ 'estimated_savings': '',
+ 'used_before_retrofit': '',
+ 'used_after_retrofit': '',
+ },
+ 'gas': {
+ 'estimated_savings': '',
+ 'used_before_retrofit': '',
+ 'used_after_retrofit': '',
+ },
+ 'oil': {
+ 'estimated_savings': '',
+ 'used_before_retrofit': '',
+ 'used_after_retrofit': '',
+ },
+ 'water': {
+ 'estimated_savings': '',
+ 'used_before_retrofit': '',
+ 'used_after_retrofit': '',
+ },
+ };
+ }
+ savingEstimationTableBody(savings);
+ setScenarioName(res.payload.name);
+ }
+ });
+}
+
+getScenario();
diff --git a/blocnote/apps/preliminaryFinance/views.py b/blocnote/apps/preliminaryFinance/views.py
index d5c7800f0b372977294a46674e11bbaec778e836..9fb1a1457062b60c1604516781a0cc0f4e68fabc 100644
--- a/blocnote/apps/preliminaryFinance/views.py
+++ b/blocnote/apps/preliminaryFinance/views.py
@@ -82,6 +82,7 @@ class Scenarios(View):
record['scenario_id'] = scenario_obj[0].id
SavingsEstimation.objects.create(**record)
+
def put(self, request, building_id):
"""Handle HTTP PUT request.
@@ -92,83 +93,12 @@ class Scenarios(View):
Returns: Dictionary with data to display the graph.
"""
put = json.loads(request.body.decode())
-
- # Fetch all relevant data from database.
- financing_overview = get_financing_overview(building_id)
- analysis_date = {
- 'proforma_start': financing_overview['pro_forma_start_date'],
- 'proforma_duration': financing_overview['pro_forma_duration']
- }
- commission_date = financing_overview['anticipated_commissioning_date']
- utilities = ['electricity', 'gas', 'oil', 'water']
- prior_month_bill = {}
- for utility in utilities:
- bill = get_utility_bill(building_id, utility)
- if bill:
- prior_month_bill[utility] = bill
- growth_rate = get_growth_rate(building_id)
- raw_income_statement = get_income_statement(building_id)
- cash_balance_input_dict = get_cash_balance(building_id)
- liability_dictionary = get_liabilities(building_id)
- loan_options = get_loan_options(building_id)
- customer_preference = get_customer_preference(building_id)
- annual_bills = get_annual_bills(building_id)
-
- # Extract data from the PUT request body.
- # Calculate the total cost of items.
- costs = []
- cost_list = put['cost']
- for record in cost_list:
- costs.append(float(record['cost']))
- total_cost = sum(costs)
- savings_percent = get_savings_percent(put['savings'])
-
- # The following 2 variables are hard coded for now. They will be updated at a later point.
- full_saving_dict = {
- 'electricity': None,
- 'gas': None,
- 'oil': None,
- 'water': None,
- }
- req_dscr = {
- 'req_noi_dscr': 1.15,
- 'req_cash_dscr': 1.15,
- 'req_saving_dscr': 1.10
- }
-
- # prelim_scenario returns the project economics which are a set of values determining the financial health
- # of the building and graph dictionary which contains total expense, loan repayment and total net savings.
- # The graph_dict will be plotted as a stacked bar graph in the frontend to visually see if savings can cover
- # loan repayment and if there will be any savings left are loan repayment.
- graph_dict, project_economics_overview = prelim_scenario(
- prior_month_bill,
- annual_bills,
- raw_income_statement,
- growth_rate,
- liability_dictionary,
- cash_balance_input_dict,
- loan_options,
- analysis_date,
- commission_date,
- total_cost,
- savings_percent,
- full_saving_dict,
- req_dscr,
- customer_preference,
+ project_economics_overview, energy_expense_list, total_loan_list, net_savings_list, year_list = prelim_analysis(
+ put['cost'],
+ put['savings'],
+ building_id
)
- energy_expense = graph_dict['energy_expenses']
- total_loan = graph_dict['total_loan']
- net_savings = graph_dict['net_savings']
- energy_expense_list = []
- total_loan_list = []
- net_savings_list = []
- year_list = []
- for year in sorted(energy_expense):
- year_list.append(year)
- energy_expense_list.append(energy_expense[year])
- total_loan_list.append(total_loan[year])
- net_savings_list.append(net_savings[year])
economics_overview = {
'Estimated Cost': float("{0:.2f}".format(project_economics_overview['estimated_cost'])),
'Overall Saving': float("{0:.2f}".format(project_economics_overview['overall_saving'])),
@@ -191,7 +121,7 @@ class Scenarios(View):
'min_cash_dscr': project_economics_overview['min_cash_dscr'],
'self_finance_amount': 0, # TODO: Hard-coded for now. Will be implemented soon.
}
- self.save_scenario(scenario_details, cost_list, put['savings'])
+ self.save_scenario(scenario_details, put['cost'], put['savings'])
return JsonResponse({
'year_list': year_list,
'energy_expense_list': energy_expense_list,
@@ -199,3 +129,161 @@ class Scenarios(View):
'net_savings_list': net_savings_list,
'economics_overview': economics_overview,
})
+
+ def get(self, request, building_id):
+ """HTTP GET request.
+
+ Fetch the scenario, cost and savings information from the database and send to the frontend for viewing. This
+ will be updated in the future to fetch all scenarios from the database and send to the frontend.
+
+ Args:
+ request: HTTP GET request.
+ building_id (integer): id of the building.
+
+ Returns:
+ scenario_details (dictionary): Dictionary containing all the scenario details.
+ cost_estimation (dictionary): Dictionary with key as item name and value as the cost estimation.
+ savings (dictionary): Dictionary with utility type and savings in decimal.
+ """
+ project_economics_fields = {
+ 'estimated_cost': 'Estimated Cost',
+ 'overall_savings': 'Overall Savings',
+ 'first_year_savings': 'First Year Savings',
+ 'simple_payback': 'Simple Payback',
+ 'self_finance_amount': 'Self Finance Amount',
+ 'min_savings_dscr': 'Minimum Savings DSCR',
+ 'min_net_operating_income_dscr': 'Minimum Net Operating Income DSCR',
+ 'min_cash_dscr': 'Minimum Cash DSCR',
+ }
+ savings_fields = [
+ 'estimated_savings',
+ 'used_before_retrofit',
+ 'used_after_retrofit',
+ ]
+ scenario_obj = Scenario.objects.filter(building_id=building_id)
+ project_economics = {}
+ costs = []
+ savings = {}
+ savings_list = []
+ scenario_name = ''
+ energy_expense_list = []
+ total_loan_list = []
+ net_savings_list = []
+ year_list = []
+ if scenario_obj:
+ scenario_name = scenario_obj[0].name
+ scenario_id = scenario_obj[0].id
+ for field in project_economics_fields:
+ name = project_economics_fields[field]
+ project_economics[name] = float(scenario_obj[0].__dict__[field])
+ cost_obj = CostEstimation.objects.filter(scenario_id=scenario_id)
+ for cost in cost_obj:
+ cost_estimate = {
+ 'cost_item': cost.__dict__['item'],
+ 'cost': float(cost.__dict__['cost']),
+ }
+ costs.append(cost_estimate)
+
+ savings_obj = SavingsEstimation.objects.filter(scenario_id=scenario_id)
+ for obj in savings_obj:
+ saving = {}
+ for field in savings_fields:
+ saving[field] = obj.__dict__[field]
+ saving['estimated_savings'] = float(saving['estimated_savings']) * 100
+ savings[obj.__dict__['utility_type']] = saving
+ saving['utility_type'] = obj.__dict__['utility_type']
+ savings_list.append(saving)
+ project_economics_overview, energy_expense_list, total_loan_list, net_savings_list, year_list = prelim_analysis(
+ costs,
+ savings_list,
+ building_id
+ )
+ return JsonResponse({
+ 'name': scenario_name,
+ 'economics_overview': project_economics,
+ 'costs': costs,
+ 'savings': savings,
+ 'energy_expense_list': energy_expense_list,
+ 'total_loan_list': total_loan_list,
+ 'net_savings_list': net_savings_list,
+ 'year_list': year_list,
+ })
+
+
+def prelim_analysis(cost, saving, building_id):
+ # Fetch all relevant data from database.
+ financing_overview = get_financing_overview(building_id)
+ analysis_date = {
+ 'proforma_start': financing_overview['pro_forma_start_date'],
+ 'proforma_duration': financing_overview['pro_forma_duration']
+ }
+ commission_date = financing_overview['anticipated_commissioning_date']
+ utilities = ['electricity', 'gas', 'oil', 'water']
+ prior_month_bill = {}
+ for utility in utilities:
+ bill = get_utility_bill(building_id, utility)
+ if bill:
+ prior_month_bill[utility] = bill
+ growth_rate = get_growth_rate(building_id)
+ raw_income_statement = get_income_statement(building_id)
+ cash_balance_input_dict = get_cash_balance(building_id)
+ liability_dictionary = get_liabilities(building_id)
+ loan_options = get_loan_options(building_id)
+ customer_preference = get_customer_preference(building_id)
+ annual_bills = get_annual_bills(building_id)
+
+ # Extract data from the PUT request body.
+ # Calculate the total cost of items.
+ costs = []
+ cost_list = cost
+ for record in cost_list:
+ costs.append(float(record['cost']))
+ total_cost = sum(costs)
+ savings_percent = get_savings_percent(saving)
+
+ # The following 2 variables are hard coded for now. They will be updated at a later point.
+ full_saving_dict = {
+ 'electricity': None,
+ 'gas': None,
+ 'oil': None,
+ 'water': None,
+ }
+ req_dscr = {
+ 'req_noi_dscr': 1.15,
+ 'req_cash_dscr': 1.15,
+ 'req_saving_dscr': 1.10
+ }
+
+ # prelim_scenario returns the project economics which are a set of values determining the financial health
+ # of the building and graph dictionary which contains total expense, loan repayment and total net savings.
+ # The graph_dict will be plotted as a stacked bar graph in the frontend to visually see if savings can cover
+ # loan repayment and if there will be any savings left are loan repayment.
+ graph_dict, project_economics_overview = prelim_scenario(
+ prior_month_bill,
+ annual_bills,
+ raw_income_statement,
+ growth_rate,
+ liability_dictionary,
+ cash_balance_input_dict,
+ loan_options,
+ analysis_date,
+ commission_date,
+ total_cost,
+ savings_percent,
+ full_saving_dict,
+ req_dscr,
+ customer_preference,
+ )
+ energy_expense = graph_dict['energy_expenses']
+ total_loan = graph_dict['total_loan']
+ net_savings = graph_dict['net_savings']
+ energy_expense_list = []
+ total_loan_list = []
+ net_savings_list = []
+ year_list = []
+ for year in sorted(energy_expense):
+ year_list.append(year)
+ energy_expense_list.append(energy_expense[year])
+ total_loan_list.append(total_loan[year])
+ net_savings_list.append(net_savings[year])
+ return project_economics_overview, energy_expense_list, total_loan_list, net_savings_list, year_list