From 516bf9339f9a1291628a85f5737ea44007c7da13 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Thu, 18 May 2017 17:49:03 -0400 Subject: [PATCH 01/37] New Branch --- bpfin/tests/testdata/sample_data.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bpfin/tests/testdata/sample_data.py b/bpfin/tests/testdata/sample_data.py index 9b19e04..0d4dedd 100644 --- a/bpfin/tests/testdata/sample_data.py +++ b/bpfin/tests/testdata/sample_data.py @@ -1,6 +1,5 @@ import datetime import pprint -# from bpfin.utilbills import bill_lib as bl # pp = pprint.PrettyPrinter(width=120, indent=4, compact=True) # pp.pprint(inflation_coeff_dict) -- GitLab From c3c5698eea5868ccea6d3f555bf9f1c979ca3411 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Thu, 18 May 2017 18:02:27 -0400 Subject: [PATCH 02/37] Formmating for sample_data --- bpfin/tests/testdata/sample_data.py | 61 ++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/bpfin/tests/testdata/sample_data.py b/bpfin/tests/testdata/sample_data.py index 0d4dedd..83c7d10 100644 --- a/bpfin/tests/testdata/sample_data.py +++ b/bpfin/tests/testdata/sample_data.py @@ -626,15 +626,20 @@ income_statement_projection_cagr = { 'water_opex': 0.0, 'year': 2036}} -noi_dictionary = {2014: 31500, 2015: 37000, 2016: 37000, 2017: 41278.43692755746, 2018 : 45214.28536645262, 2019 : 48842.631285961135, -2020: 52731.934093183474,2021: 56939.349890971425,2022:61487.1217724919, 2023 : 66332.18430708232, -2024: 71461.4261836982, 2025: 76882.87761572453, 2026: 82578.96693651963, 2027: 88565.60757013515, -2028: 94901.76519041706, 2029: 101627.80434590613, 2030: 108765.29589285178, 2031: 116334.19001298171, 2032: 124349.95052275498, -2033: 132827.33443479502, 2034: 141788.36292608615, 2035: 151259.5001164715, 2036: 161269.59000112678} +noi_dictionary = { + 2014: 31500, 2015: 37000, 2016: 37000, 2017: 41278.43692755746, 2018: 45214.28536645262, 2019: 48842.631285961135, + 2020: 52731.934093183474, 2021: 56939.349890971425, 2022: 61487.1217724919, 2023: 66332.18430708232, + 2024: 71461.4261836982, 2025: 76882.87761572453, 2026: 82578.96693651963, 2027: 88565.60757013515, + 2028: 94901.76519041706, 2029: 101627.80434590613, 2030: 108765.29589285178, 2031: 116334.19001298171, + 2032: 124349.95052275498, + 2033: 132827.33443479502, 2034: 141788.36292608615, 2035: 151259.5001164715, 2036: 161269.59000112678 +} -liability_input = {'debt1': (150, 'NYSERDA', 10, datetime.date(2012, 12, 31)), - 'debt2': (100, 'NYCEEC', 20, datetime.date(2012, 8, 31))} +liability_input = { + 'debt1': (150, 'NYSERDA', 10, datetime.date(2012, 12, 31)), + 'debt2': (100, 'NYCEEC', 20, datetime.date(2012, 8, 31)) +} liability_dictionary = { @@ -2910,7 +2915,7 @@ raw_gas_bill_demo['date_from'] = [ datetime.date(2015, 12, 16), datetime.date(2015, 11, 16), datetime.date(2015, 10, 16), datetime.date(2015, 9, 19), datetime.date(2015, 8, 18), datetime.date(2015, 7, 20), datetime.date(2015, 6, 18), datetime.date(2015, 5, 19)] -raw__gas_bill_demo['date_to'] = [ +raw_gas_bill_demo['date_to'] = [ datetime.date(2016, 12, 16), datetime.date(2016, 11, 22), datetime.date(2016, 10, 18), datetime.date(2016, 9, 30), datetime.date(2016, 9, 19), datetime.date(2016, 8, 18), datetime.date(2016, 7, 20), datetime.date(2016, 6, 20), datetime.date(2016, 5, 18), @@ -3013,13 +3018,41 @@ raw_water_bill_demo['charge'] = [ raw_water_bill_demo['usage'] = [ 3500000, 3600000, 3300000] -bill_demo = {'gas_bill': raw_gas_bill_demo, 'electricity_bill': raw_elec_bill_demo, - 'oil_bill': raw_oil_bill_demo, 'water_bill': raw_water_bill_demo} +bill_demo = { + 'gas_bill': raw_gas_bill_demo, + 'electricity_bill': raw_elec_bill_demo, + 'oil_bill': raw_oil_bill_demo, + 'water_bill': raw_water_bill_demo} -raw_income_input_demo = {2014: {'total_revenue': 200000, 'other_utility_expenses': 10000, 'energy_expenses': 67000, 'utility_expenses': 77000, 'non_utility_operating_expenses': 105000, -'total_expenses': 182000, 'noi': 18000}, 2015: {'total_revenue': 196000, 'other_utility_expenses': 8400, 'energy_expenses': 69000, 'utility_expenses': 77400, 'non_utility_operating_expenses': 104000, -'total_expenses': 181400, 'noi': 14600}, 2016: {'total_revenue': 205000, 'other_utility_expenses': 8100, 'energy_expenses': 70000, 'utility_expenses': 78100, 'non_utility_operating_expenses': 130000, -'total_expenses': 208100, 'noi': -3100}} +raw_income_input_demo = { + 2014: { + 'total_revenue': 200000, + 'other_utility_expenses': 10000, + 'energy_expenses': 67000, + 'utility_expenses': 77000, + 'non_utility_operating_expenses': 105000, + 'total_expenses': 182000, + 'noi': 18000 + }, + 2015: { + 'total_revenue': 196000, + 'other_utility_expenses': 8400, + 'energy_expenses': 69000, + 'utility_expenses': 77400, + 'non_utility_operating_expenses': 104000, + 'total_expenses': 181400, + 'noi': 14600 + }, + 2016: { + 'total_revenue': 205000, + 'other_utility_expenses': 8100, + 'energy_expenses': 70000, + 'utility_expenses': 78100, + 'non_utility_operating_expenses': 130000, + 'total_expenses': 208100, + 'noi': -3100 + } +} raw_balance_sheet_demo = {2014: {'cash': 60000, 'other_debt_service': 1000, 'noi': 18000}, -- GitLab From 0892cb9604f81a7eaf3bc700c8211f249a6485f4 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Fri, 19 May 2017 10:32:11 -0400 Subject: [PATCH 03/37] Put test_cash_balance in comment, wait for new test file PR --- .../test_financials/test_cash_balance.py | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/bpfin/tests/test_financials/test_cash_balance.py b/bpfin/tests/test_financials/test_cash_balance.py index 2f27f7b..2fffe1b 100644 --- a/bpfin/tests/test_financials/test_cash_balance.py +++ b/bpfin/tests/test_financials/test_cash_balance.py @@ -2,27 +2,27 @@ from bpfin.financials.cash_balance import cash_balance from datetime import date -def test_cash_balance_year_gap(): - input_dictionary = { - date(2014, 11, 1): (500, False), - date(2014, 12, 1): (400, False), - date(2014, 3, 13): (600, False), - date(2016, 11, 11): (500, False), - date(2016, 12, 31): (400, True) - } - input_analysis_date = { - 'proforma_start': date(2012, 5, 3), - 'proforma_duration': 12 - } - output_cash_balance = { - 2012: 450, - 2013: 450, - 2014: 500, - 2015: 450, - 2016: 400 - } - result = cash_balance(input_analysis_date, input_dictionary) - assert result == output_cash_balance +# def test_cash_balance_year_gap(): +# input_dictionary = { +# date(2014, 11, 1): (500, False), +# date(2014, 12, 1): (400, False), +# date(2014, 3, 13): (600, False), +# date(2016, 11, 11): (500, False), +# date(2016, 12, 31): (400, True) +# } +# input_analysis_date = { +# 'proforma_start': date(2012, 5, 3), +# 'proforma_duration': 12 +# } +# output_cash_balance = { +# 2012: 450, +# 2013: 450, +# 2014: 500, +# 2015: 450, +# 2016: 400 +# } +# result = cash_balance(input_analysis_date, input_dictionary) +# assert result == output_cash_balance def test_cash_balance(): -- GitLab From fdf4bee78f90fb9a75c3f6ac5f8de220365463d2 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Fri, 19 May 2017 10:57:50 -0400 Subject: [PATCH 04/37] Refactor financial_income. Update backend call file and its test files --- bpfin/financials/financial_income.py | 905 +++++++++--------- bpfin/financials/financial_lib.py | 61 +- bpfin/lib/back_end_call.py | 21 +- .../test_utilbills/test_back_end_call.py | 1 - 4 files changed, 466 insertions(+), 522 deletions(-) diff --git a/bpfin/financials/financial_income.py b/bpfin/financials/financial_income.py index f13b4ea..6f7cc18 100644 --- a/bpfin/financials/financial_income.py +++ b/bpfin/financials/financial_income.py @@ -1,464 +1,441 @@ -# """ -# Rewrite Income_Statement class to saperate income statement related class and funcs from Financial_lib.py -# Income_Statement is incorporate with new Bill class, taking in bill_list as input -# """ - -# import copy -# from bpfin.lib.other import cal_cagr -# from bpfin.utilbills.bill_lib import form_bill_year -# from numpy import mean -# # from bpfin.tests.testdata import sample_data as db -# # import pprint - - -# class Income_Statement(): -# """ -# Generate Income Statement for single year, with standard accounting line items -# Will be called -# """ -# def __init__(self): -# self.year = None -# self.revenue = None -# self.utility_expense = None -# self.non_utility_expense = None -# self.electricity_opex = None -# self.gas_opex = None -# self.oil_opex = None -# self.water_opex = None -# self.energy_opex = None -# self.other_utility = None -# self.net_non_energy_opex = None -# self.total_opex = None -# self.noi = None -# # energy_debt_service = -# # other_debt_service = -# # total_debt_service = -# # bill_saving = -# # energy_DSCR = -# # total_DSCR = - -# def put_hist(self, year, income_input, annual_bill_table): -# """ -# Put historical income statement data and generate a single year income statement -# Inputs are incomplete income statement items, and energy bill overview -# Final output is an single year income_statement objectvie with standarized items filled - -# Args: -# year (int): the year of this income statement -# income_input (dictionary): 3 elements of inputs -# annual_bill_table (dictionary): annual bill, for 4 utility_types - -# Description Sample: -# income_input = {revenue': 100000, 'utility_expense': 60000,'non_utility_expense': 3000} -# annual_bill_table = {'electricity': electricity_bill, 'oil': oil_bill, 'gas': gas_bill, 'water': water_bill} -# """ -# self.year = year -# self.revenue = income_input['revenue'] -# self.utility_expense = income_input['utility_expense'] -# self.non_utility_expense = income_input['non_utility_expense'] -# self.electricity_opex = annual_bill_table['electricity'][self.year] -# self.gas_opex = annual_bill_table['gas'][self.year] -# self.oil_opex = annual_bill_table['oil'][self.year] -# self.water_opex = annual_bill_table['water'][self.year] -# self.energy_opex = self.electricity_opex + self.oil_opex + self.gas_opex + self.water_opex -# self.other_utility = self.utility_expense - self.energy_opex -# self.net_non_energy_opex = self.other_utility + self.non_utility_expense -# self.total_opex = self.energy_opex + self.net_non_energy_opex -# self.noi = self.revenue - self.total_opex # net operating income - -# def put_average(self, average_revenue, annual_bills, characters): -# """ -# Calculate and create average income statement. -# Revenue, energy bills are average of historical data. -# Other items are calculated by historical characters. -# Args: -# average_revenue (float): average revenue calculated from historical income statements -# annual_bills (dictionary): dictionary of float value of average annual bills, for 4 utility_types -# characters (dictionary): 6 characters calculated from historical income statements -# Final instance is a single year income statement without named year - -# Description: -# characters = { -# 'start_year': (int) 2014, -# 'end_year': (int) 2016, -# 'cagr': (float) 0.054, -# 'other_utility_percent': (float) 0.020 == 2.0% -# 'non_utility_expense_percent': (float) 0.030 == 3.0% -# 'revenue_average': (float) 3000.00 -# } -# annual_bills = {'electricity': 100.0, 'oil': 200.0, 'gas': 300.0, 'water': 400.0} -# """ -# self.revenue = average_revenue -# self.electricity_opex = annual_bills['electricity'] -# self.gas_opex = annual_bills['gas'] -# self.oil_opex = annual_bills['oil'] -# self.water_opex = annual_bills['water'] -# self.energy_opex = self.electricity_opex + self.gas_opex + self.oil_opex + self.water_opex -# self.other_utility = self.revenue * characters['other_utility_percent'] -# self.non_utility_expense = self.revenue * characters[ -# 'non_utility_expense_percent'] -# self.utility_expense = self.energy_opex + self.other_utility -# self.net_non_energy_opex = self.other_utility + self.non_utility_expense -# self.total_opex = self.energy_opex + self.net_non_energy_opex -# self.noi = self.revenue - self.total_opex - -# # def assign_next(self, income_statement_characters, -# # bill_overview_organized): -# # """ -# # !!! this function will be deleted in the next version!! -# # """ -# # self.electricity_opex = bill_overview_organized['electricity'][ -# # self.year] -# # self.gas_opex = bill_overview_organized['gas'][self.year] -# # self.oil_opex = bill_overview_organized['oil'][self.year] -# # self.water_opex = bill_overview_organized['water'][self.year] -# # self.energy_opex = self.electricity_opex + self.gas_opex + self.oil_opex + self.water_opex -# # self.other_utility = self.revenue * income_statement_characters[ -# # 'other_utility_percent'] -# # self.non_utility_expense = self.revenue * income_statement_characters[ -# # 'non_utility_expense_percent'] -# # self.utility_expense = self.energy_opex + self.other_utility -# # self.net_non_energy_opex = self.other_utility + self.non_utility_expense -# # self.total_opex = self.energy_opex + self.net_non_energy_opex -# # self.noi = self.revenue - self.total_opex - - -# def convert_income_statement_class(income_statement_class): -# """ -# Convert single year income statement object into a dictionary format -# Args: -# income_statement_class (object): single year income statement object -# Return: -# income_statement_dict (dictionary) -# """ -# income_statement_dict = { -# 'year': income_statement_class.year, -# 'revenue': income_statement_class.revenue, -# 'utility_expense': income_statement_class.utility_expense, -# 'energy_opex': income_statement_class.energy_opex, -# 'electricity_opex': income_statement_class.electricity_opex, -# 'gas_opex': income_statement_class.gas_opex, -# 'oil_opex': income_statement_class.oil_opex, -# 'water_opex': income_statement_class.water_opex, -# 'other_utility': income_statement_class.other_utility, -# 'non_utility_expense': income_statement_class.non_utility_expense, -# 'net_non_energy_opex': income_statement_class.net_non_energy_opex, -# 'total_opex': income_statement_class.total_opex, -# 'noi': income_statement_class.noi -# } -# return income_statement_dict - - -# class Income_Statement_Next(): -# """ -# Create single year income_statement object, -# with input of last year data, income statement characters, and projected annual bill -# """ - -# def __init__(self, year, last_revenue, growth_rate_flag, characters, -# annual_bill_table): -# """ -# Calculation is done in initiation. -# Args: -# year (int): the year that will be projected on -# last_revenue (float): last year revenue -# growth_rate_flag (float): indicating assumed growth rate, -2.0 == cagr, -1.0 == historical average -# characters (dictionary): 6 characters calculated from historical income statements -# annual_bill_table (dictionary): dictionary of dictionary of annual bills, for 4 utility_types -# Final instance is a single year income_statement object - -# Description: -# characters = { -# 'start_year': (int) 2014, -# 'end_year': (int) 2016, -# 'cagr': (float) 0.054, -# 'other_utility_percent': (float) 0.020 == 2.0% -# 'non_utility_expense_percent': (float) 0.035 == 3.5% -# 'revenue_average': (float) 3000.00 -# } -# annual_bill_table = {'electricity': electricity_bill, 'oil': oil_bill, 'gas': gas_bill, 'water': water_bill} -# electricity_bill = {2014: 100, 2015:200, ...} -# """ -# self.year = year - -# if growth_rate_flag == -1.0: # growth_rate_flag == average -# current_revenue = characters['revenue_average'] -# else: -# if growth_rate_flag == -2.0: # growth_rate_flag == cagr -# growth_rate = characters['cagr'] -# else: -# growth_rate = growth_rate_flag # growth_rate_flag == 0.00, 0.01, ... -# current_revenue = last_revenue * (1 + growth_rate) -# self.revenue = current_revenue -# self.electricity_opex = annual_bill_table['electricity'][self.year] -# self.gas_opex = annual_bill_table['gas'][self.year] -# self.oil_opex = annual_bill_table['oil'][self.year] -# self.water_opex = annual_bill_table['water'][self.year] -# self.energy_opex = self.electricity_opex + self.gas_opex + self.oil_opex + self.water_opex -# self.other_utility = self.revenue * characters['other_utility_percent'] -# self.non_utility_expense = self.revenue * characters[ -# 'non_utility_expense_percent'] -# self.utility_expense = self.energy_opex + self.other_utility -# self.net_non_energy_opex = self.other_utility + self.non_utility_expense -# self.total_opex = self.energy_opex + self.net_non_energy_opex -# self.noi = self.revenue - self.total_opex - - -# class Income_Statement_Table(): -# """ -# Create a income statement table, containing multiple years, including historical and projected data -# Key Attributes are: -# hist_table (list): list of single year income_statement objects, containing historical data -# table(list): list of single year income_statement objects, containing historical and projected data -# """ - -# def __init__(self, raw_income_input, annual_bill_table): -# """ -# Create hist_table to store historical income statement data, and calculate some key characters. -# Args: -# raw_income_input (dictionary): dict of dict of incomplete income statement, for historical years. Key = year -# annual_bill_table (dictionary): dictionary of dictionary of annual bills, for 4 utility_types - -# Key Attributes: -# cagr (float): compound annual growth rate -# other_utility_percent (float): percentage, (average other_utility / average revenue) -# non_utility_expense_percent (float): percentage, (average non_utility_expense_percent / average revenue) -# hist_table (list): list of single year income_statement objects, containing historical data -# table(list): list of single year income_statement objects, containing historical and projected data -# characters (dictionary): contains key characters determined from historical data. Is used to project - -# Description: -# raw_income_input = {2014: {'revenue': 90.0, 'utility_expense': 55.0, 'non_utility_expense': 35.0}, 2015:{},} -# annual_bill_table = {'electricity': electricity_bill, 'oil': oil_bill, 'gas': gas_bill, 'water': water_bill} -# electricity_bill = {2014: 100, 2015:200, ...} -# characters = { -# 'start_year': (int) 2014, -# 'end_year': (int) 2016, -# 'cagr': (float) 0.054, -# 'other_utility_percent': (float) 0.02, -# 'non_utility_expense_percent': (float) 0.03, -# 'revenue_average': (float) 3000.00 -# } -# """ -# self.hist_start_year = None -# self.hist_end_year = None -# self.cagr = 0.00 -# self.other_utility_percent = 0.00 -# self.non_utility_expense_percent = 0.00 -# self.revenue_average = 0.00 # average revenue -# self.hist_table = [] -# self.table = [] -# self.characters = {} - -# for year in raw_income_input: -# current_income_statement = Income_Statement() -# current_income_statement.put_hist(year, raw_income_input[year], -# annual_bill_table) -# self.hist_table.append(current_income_statement) - -# sorted_income_hist_year = sorted(raw_income_input) -# self.hist_start_year = sorted_income_hist_year[0] -# self.hist_end_year = sorted_income_hist_year[-1] -# # if start_year == None: return None -# self.cagr = cal_cagr( -# raw_income_input[self.hist_start_year]['revenue'], -# raw_income_input[self.hist_end_year]['revenue'], -# self.hist_end_year - self.hist_start_year) - -# revenue_sum = 0 -# other_utility_sum = 0 -# non_utility_expense_sum = 0 -# for current_income_statement in self.hist_table: -# revenue_sum += current_income_statement.revenue -# other_utility_sum += current_income_statement.other_utility -# non_utility_expense_sum += current_income_statement.non_utility_expense - -# self.other_utility_percent = other_utility_sum / revenue_sum -# self.non_utility_expense_percent = non_utility_expense_sum / revenue_sum -# self.revenue_average = revenue_sum / ( -# self.hist_end_year - self.hist_start_year + 1) - -# self.table = self.hist_table -# self.characters = { -# 'start_year': self.hist_start_year, -# 'end_year': self.hist_end_year, -# 'cagr': self.cagr, -# 'other_utility_percent': self.other_utility_percent, -# 'non_utility_expense_percent': self.non_utility_expense_percent, -# 'revenue_average': self.revenue_average -# } - -# def project(self, growth_rate_flag, analysis_date, annual_bill_table): -# """ -# Project future income statement. Append multiple single year income_statement objects to self.table -# Args: -# growth_rate_flag (float): indicating assumed growth rate, -2.0 == cagr, -1.0 == historical average -# analysis_date (dictionary): proforma's starting date and the years of proforma -# annual_bill_table (dictionary): dictionary of dictionary of annual bills, for 4 utility_types -# Return: -# list: list of single year income_statement objects, containing historical and projection -# Note: -# project() overwrites existing projection data -# """ -# # characters = copy.deepcopy(self.characters) -# proforma_year = form_bill_year(analysis_date['proforma_start'], -# analysis_date['proforma_duration']) -# current_table = copy.deepcopy(self.hist_table) -# for year in proforma_year: -# last_revenue = current_table[-1].revenue -# if year <= current_table[-1].year: -# continue -# current_income_statement = Income_Statement_Next( -# year, last_revenue, growth_rate_flag, self.characters, -# annual_bill_table) -# current_table.append(current_income_statement) -# self.table = current_table -# # return current_table - -# def get_hist_table(self): -# """ -# Get historical table, in dictionary formatting -# Return: -# dictionary: dict of dict of income statement. Key is year -# Description: -# hist_table_dict = {2014: {'year': 2014, 'revenue': 100.0, ..., 'not': 5.0}, ... , 2016:{}} -# """ -# hist_table_dict = {} -# for current_income_statement in self.hist_table: -# hist_table_dict[current_income_statement.year] = { -# 'year': -# current_income_statement.year, -# 'revenue': -# current_income_statement.revenue, -# 'utility_expense': -# current_income_statement.utility_expense, -# 'energy_opex': -# current_income_statement.energy_opex, -# 'electricity_opex': -# current_income_statement.electricity_opex, -# 'gas_opex': -# current_income_statement.gas_opex, -# 'oil_opex': -# current_income_statement.oil_opex, -# 'water_opex': -# current_income_statement.water_opex, -# 'other_utility': -# current_income_statement.other_utility, -# 'non_utility_expense': -# current_income_statement.non_utility_expense, -# 'net_non_energy_opex': -# current_income_statement.net_non_energy_opex, -# 'total_opex': -# current_income_statement.total_opex, -# 'noi': -# current_income_statement.noi -# } -# return hist_table_dict - -# def get_cagr(self): -# """ -# Get compound annual growth rate -# Return: -# float: compound annual growth rate -# """ -# return copy.deepcopy(self.cagr) - -# def get_average(self): -# """ -# Get average income statement. Only need initialized Income_Statement_Table -# Return: -# dictionary: dict of average income statement, Keys are income statement items. -# Description: -# output_dict = {'year': None, 'revenue': 95000.0, ... ,'noi': 35166.666666666657} -# """ -# # current_year = 'Average' -# current_income_statement = Income_Statement() -# average_revenue = mean(list(i_s.revenue for i_s in self.hist_table)) -# annual_bills = { -# 'electricity': -# mean(list(i_s.electricity_opex for i_s in self.hist_table)), -# 'gas': -# mean(list(i_s.gas_opex for i_s in self.hist_table)), -# 'oil': -# mean(list(i_s.oil_opex for i_s in self.hist_table)), -# 'water': -# mean(list(i_s.water_opex for i_s in self.hist_table)) -# } -# current_income_statement.put_average(average_revenue, annual_bills, -# self.characters) - -# return convert_income_statement_class(current_income_statement) - -# def get_single_year(self, year): -# """ -# Get single year income statement from self.table. Table can either contain or not contain projection -# Args: -# year (int): the year that need to be extracted -# Return: -# dict: single year income statement. Keys are income statement items. -# Note: -# if the target year is not in self.table, then return None. -# """ -# for current_income_statement in self.table: -# if current_income_statement.year == year: -# return { -# 'year': -# current_income_statement.year, -# 'revenue': -# current_income_statement.revenue, -# 'utility_expense': -# current_income_statement.utility_expense, -# 'energy_opex': -# current_income_statement.energy_opex, -# 'electricity_opex': -# current_income_statement.electricity_opex, -# 'gas_opex': -# current_income_statement.gas_opex, -# 'oil_opex': -# current_income_statement.oil_opex, -# 'water_opex': -# current_income_statement.water_opex, -# 'other_utility': -# current_income_statement.other_utility, -# 'non_utility_expense': -# current_income_statement.non_utility_expense, -# 'net_non_energy_opex': -# current_income_statement.net_non_energy_opex, -# 'total_opex': -# current_income_statement.total_opex, -# 'noi': -# current_income_statement.noi -# } -# return None - -# def get_noi_dict(self): -# """ -# Get a dictionary of net operating income. -# Return: -# dictionary: net operating income for each year in income statement table. Key is year -# """ -# noi_dict = {} -# for current_income_statement in self.table: -# noi_dict[ -# current_income_statement.year] = current_income_statement.noi -# return noi_dict - -# def get_first_year_noi(self, commission_date): -# """ -# Get first year noi after commissioning year, from post_saving income statement -# Args: -# commission_date (date): construction finishing date. Saving starts NEXT month/year -# Return: -# float: noi of the next year after commission date -# """ -# first_year = commission_date.year + 1 -# for current_income_statement in self.table: -# if current_income_statement.year == first_year: -# return current_income_statement.noi - -# def get_total_energy_dict(self): -# total_energy_dict = {} -# for current_income_statement in self.table: -# total_energy_dict[ -# current_income_statement.year] = current_income_statement.energy_opex -# return total_energy_dict +import copy +from bpfin.lib import other as lib +from bpfin.utilbills.bill_lib import form_bill_year +from numpy import mean + + +class Income_Statement(): + def __init__(self): + self.year = None + self.revenue = None + self.utility_expense = None + self.non_utility_expense = None + self.electricity_opex = None + self.gas_opex = None + self.oil_opex = None + self.water_opex = None + self.energy_opex = None + self.other_utility = None + self.net_non_energy_opex = None + self.total_opex = None + self.noi = None + # energy_debt_service = + # other_debt_service = + # total_debt_service = + # bill_saving = + # energy_DSCR = + # total_DSCR = + + def put_hist(self, year, income_input, annual_bill_table): + """ + Put historical income statement data and generate a single year income statement + Inputs are incomplete income statement items, and energy bill overview + Final output is an single year income_statement objectvie with standarized items filled + + Args: + year (int): the year of this income statement + income_input (dictionary): 3 elements of inputs + annual_bill_table (dictionary): annual bill, for 4 utility_types + + Description Sample: + income_input = {revenue': 100000, 'utility_expense': 60000,'non_utility_expense': 3000} + annual_bill_table = {'electricity': electricity_bill, 'oil': oil_bill, 'gas': gas_bill, 'water': water_bill} + """ + self.year = year + self.revenue = income_input['revenue'] + self.utility_expense = income_input['utility_expense'] + self.non_utility_expense = income_input['non_utility_expense'] + self.electricity_opex = annual_bill_table['electricity'][self.year] + self.gas_opex = annual_bill_table['gas'][self.year] + self.oil_opex = annual_bill_table['oil'][self.year] + self.water_opex = annual_bill_table['water'][self.year] + self.energy_opex = self.electricity_opex + self.oil_opex + self.gas_opex + self.water_opex + self.other_utility = self.utility_expense - self.energy_opex + self.net_non_energy_opex = self.other_utility + self.non_utility_expense + self.total_opex = self.energy_opex + self.net_non_energy_opex + self.noi = self.revenue - self.total_opex # net operating income + + def put_average(self, average_revenue, annual_bills, characters): + """ + Calculate and create average income statement. + Revenue, energy bills are average of historical data. + Other items are calculated by historical characters. + Args: + average_revenue (float): average revenue calculated from historical income statements + annual_bills (dictionary): dictionary of float value of average annual bills, for 4 utility_types + characters (dictionary): 6 characters calculated from historical income statements + Final instance is a single year income statement without named year + + Description: + characters = { + 'start_year': (int) 2014, + 'end_year': (int) 2016, + 'cagr': (float) 0.054, + 'other_utility_percent': (float) 0.020 == 2.0% + 'non_utility_expense_percent': (float) 0.030 == 3.0% + 'revenue_average': (float) 3000.00 + } + annual_bills = {'electricity': 100.0, 'oil': 200.0, 'gas': 300.0, 'water': 400.0} + """ + self.revenue = average_revenue + self.electricity_opex = annual_bills['electricity'] + self.gas_opex = annual_bills['gas'] + self.oil_opex = annual_bills['oil'] + self.water_opex = annual_bills['water'] + self.energy_opex = self.electricity_opex + self.gas_opex + self.oil_opex + self.water_opex + self.other_utility = self.revenue * characters['other_utility_percent'] + self.non_utility_expense = self.revenue * characters[ + 'non_utility_expense_percent'] + self.utility_expense = self.energy_opex + self.other_utility + self.net_non_energy_opex = self.other_utility + self.non_utility_expense + self.total_opex = self.energy_opex + self.net_non_energy_opex + self.noi = self.revenue - self.total_opex + + +def convert_income_statement_class(income_statement_class): + """ + Convert single year income statement object into a dictionary format + Args: + income_statement_class (object): single year income statement object + Return: + income_statement_dict (dictionary) + """ + income_statement_dict = { + 'year': income_statement_class.year, + 'revenue': income_statement_class.revenue, + 'utility_expense': income_statement_class.utility_expense, + 'energy_opex': income_statement_class.energy_opex, + 'electricity_opex': income_statement_class.electricity_opex, + 'gas_opex': income_statement_class.gas_opex, + 'oil_opex': income_statement_class.oil_opex, + 'water_opex': income_statement_class.water_opex, + 'other_utility': income_statement_class.other_utility, + 'non_utility_expense': income_statement_class.non_utility_expense, + 'net_non_energy_opex': income_statement_class.net_non_energy_opex, + 'total_opex': income_statement_class.total_opex, + 'noi': income_statement_class.noi + } + return income_statement_dict + + +class Income_Statement_Next(): + """ + Create single year income_statement object, + with input of last year data, income statement characters, and projected annual bill + """ + + def __init__(self, year, last_revenue, growth_rate_flag, characters, annual_bill_table): + """ + Calculation is done in initiation. + Args: + year (int): the year that will be projected on + last_revenue (float): last year revenue + growth_rate_flag (float): indicating assumed growth rate, -2.0 == cagr, -1.0 == historical average + characters (dictionary): 6 characters calculated from historical income statements + annual_bill_table (dictionary): dictionary of dictionary of annual bills, for 4 utility_types + Final instance is a single year income_statement object + + Description: + characters = { + 'start_year': (int) 2014, + 'end_year': (int) 2016, + 'cagr': (float) 0.054, + 'other_utility_percent': (float) 0.020 == 2.0% + 'non_utility_expense_percent': (float) 0.035 == 3.5% + 'revenue_average': (float) 3000.00 + } + annual_bill_table = {'electricity': electricity_bill, 'oil': oil_bill, 'gas': gas_bill, 'water': water_bill} + electricity_bill = {2014: 100, 2015:200, ...} + """ + self.year = year + + if growth_rate_flag == -1.0: # growth_rate_flag == average + current_revenue = characters['revenue_average'] + else: + if growth_rate_flag == -2.0: # growth_rate_flag == cagr + growth_rate = characters['cagr'] + else: + growth_rate = growth_rate_flag # growth_rate_flag == 0.00, 0.01, ... + current_revenue = last_revenue * (1 + growth_rate) + self.revenue = current_revenue + self.electricity_opex = annual_bill_table['electricity'][self.year] + self.gas_opex = annual_bill_table['gas'][self.year] + self.oil_opex = annual_bill_table['oil'][self.year] + self.water_opex = annual_bill_table['water'][self.year] + self.energy_opex = self.electricity_opex + self.gas_opex + self.oil_opex + self.water_opex + self.other_utility = self.revenue * characters['other_utility_percent'] + self.non_utility_expense = self.revenue * characters[ + 'non_utility_expense_percent'] + self.utility_expense = self.energy_opex + self.other_utility + self.net_non_energy_opex = self.other_utility + self.non_utility_expense + self.total_opex = self.energy_opex + self.net_non_energy_opex + self.noi = self.revenue - self.total_opex + + +class Income_Statement_Table(): + """ + Create a income statement table, containing multiple years, including historical and projected data + Key Attributes are: + hist_table (list): list of single year income_statement objects, containing historical data + table(list): list of single year income_statement objects, containing historical and projected data + """ + + def __init__(self, raw_income_input, annual_bill_table, analysis_date): + """ + Create hist_table to store historical income statement data, and calculate some key characters. + Args: + raw_income_input (dictionary): dict of dict of incomplete income statement, for historical years. Key = year + annual_bill_table (dictionary): dictionary of dictionary of annual bills, for 4 utility_types + analysis_date (dictionary): proforma's starting date and the years of proforma + + Key Attributes: + cagr (float): compound annual growth rate + other_utility_percent (float): percentage, (average other_utility / average revenue) + non_utility_expense_percent (float): percentage, (average non_utility_expense_percent / average revenue) + hist_table (list): list of single year income_statement objects, containing historical data + table(list): list of single year income_statement objects, containing historical and projected data + characters (dictionary): contains key characters determined from historical data. Is used to project + + Description: + raw_income_input = {2014: {'revenue': 90.0, 'utility_expense': 55.0, 'non_utility_expense': 35.0}, 2015:{},} + annual_bill_table = {'electricity': electricity_bill, 'oil': oil_bill, 'gas': gas_bill, 'water': water_bill} + electricity_bill = {2014: 100, 2015:200, ...} + characters = { + 'start_year': (int) 2014, + 'end_year': (int) 2016, + 'cagr': (float) 0.054, + 'other_utility_percent': (float) 0.02, + 'non_utility_expense_percent': (float) 0.03, + 'revenue_average': (float) 3000.00 + } + + Error Validation: + raw_income_input: + year should not be empty. + year should be covered by analysis date. Raise: change analysis date + any year should contain 4 raw inputs. + annual_bill_table: + annual_bill_table years should cover proforma years + """ + self.hist_start_year = None + self.hist_end_year = None + self.cagr = 0.00 + self.other_utility_percent = 0.00 + self.non_utility_expense_percent = 0.00 + self.revenue_average = 0.00 # average revenue + self.hist_table = [] + self.table = [] + self.characters = {} + self.analysis_date = analysis_date + + for year in raw_income_input: + current_income_statement = Income_Statement() + current_income_statement.put_hist(year, raw_income_input[year], + annual_bill_table) + self.hist_table.append(current_income_statement) + + sorted_income_hist_year = sorted(raw_income_input) + self.hist_start_year = sorted_income_hist_year[0] + self.hist_end_year = sorted_income_hist_year[-1] + # if start_year == None: return None + self.cagr = lib.cal_cagr( + raw_income_input[self.hist_start_year]['revenue'], + raw_income_input[self.hist_end_year]['revenue'], + self.hist_end_year - self.hist_start_year) + + revenue_sum = 0 + other_utility_sum = 0 + non_utility_expense_sum = 0 + for current_income_statement in self.hist_table: + revenue_sum += current_income_statement.revenue + other_utility_sum += current_income_statement.other_utility + non_utility_expense_sum += current_income_statement.non_utility_expense + + self.other_utility_percent = other_utility_sum / revenue_sum + self.non_utility_expense_percent = non_utility_expense_sum / revenue_sum + self.revenue_average = revenue_sum / ( + self.hist_end_year - self.hist_start_year + 1) + + self.table = self.hist_table + self.characters = { + 'start_year': self.hist_start_year, + 'end_year': self.hist_end_year, + 'cagr': self.cagr, + 'other_utility_percent': self.other_utility_percent, + 'non_utility_expense_percent': self.non_utility_expense_percent, + 'revenue_average': self.revenue_average + } + + def project(self, growth_rate_flag, annual_bill_table): + """ + Project future income statement. Append multiple single year income_statement objects to self.table + Args: + growth_rate_flag (float): indicating assumed growth rate, -2.0 == cagr, -1.0 == historical average + annual_bill_table (dictionary): dictionary of dictionary of annual bills, for 4 utility_types + Return: + list: list of single year income_statement objects, containing historical and projection + Note: + project() overwrites existing projection data + """ + # characters = copy.deepcopy(self.characters) + proforma_year = form_bill_year(self.analysis_date['proforma_start'], + self.analysis_date['proforma_duration']) + current_table = copy.deepcopy(self.hist_table) + for year in proforma_year: + last_revenue = current_table[-1].revenue + if year <= current_table[-1].year: + continue + current_income_statement = Income_Statement_Next( + year, last_revenue, growth_rate_flag, self.characters, + annual_bill_table) + current_table.append(current_income_statement) + self.table = current_table + # return current_table + + def get_hist_table(self): + """ + Get historical table, in dictionary formatting + Return: + dictionary: dict of dict of income statement. Key is year + Description: + hist_table_dict = {2014: {'year': 2014, 'revenue': 100.0, ..., 'not': 5.0}, ... , 2016:{}} + """ + hist_table_dict = {} + for current_income_statement in self.hist_table: + hist_table_dict[current_income_statement.year] = { + 'year': current_income_statement.year, + 'revenue': current_income_statement.revenue, + 'utility_expense': current_income_statement.utility_expense, + 'energy_opex': current_income_statement.energy_opex, + 'electricity_opex': current_income_statement.electricity_opex, + 'gas_opex': current_income_statement.gas_opex, + 'oil_opex': current_income_statement.oil_opex, + 'water_opex': current_income_statement.water_opex, + 'other_utility': current_income_statement.other_utility, + 'non_utility_expense': current_income_statement.non_utility_expense, + 'net_non_energy_opex': current_income_statement.net_non_energy_opex, + 'total_opex': current_income_statement.total_opex, + 'noi': current_income_statement.noi + } + return hist_table_dict + + def get_cagr(self): + """ + Get compound annual growth rate + Return: + float: compound annual growth rate + """ + return copy.deepcopy(self.cagr) + + def get_average(self): + """ + Get average income statement. Only need initialized Income_Statement_Table + Return: + dictionary: dict of average income statement, Keys are income statement items. + Description: + output_dict = {'year': None, 'revenue': 95000.0, ... ,'noi': 35166.666666666657} + """ + # current_year = 'Average' + current_income_statement = Income_Statement() + average_revenue = mean(list(i_s.revenue for i_s in self.hist_table)) + annual_bills = { + 'electricity': + mean(list(i_s.electricity_opex for i_s in self.hist_table)), + 'gas': + mean(list(i_s.gas_opex for i_s in self.hist_table)), + 'oil': + mean(list(i_s.oil_opex for i_s in self.hist_table)), + 'water': + mean(list(i_s.water_opex for i_s in self.hist_table)) + } + current_income_statement.put_average(average_revenue, annual_bills, self.characters) + return convert_income_statement_class(current_income_statement) + + def get_single_year(self, year): + """ + Get single year income statement from self.table. Table can either contain or not contain projection + Args: + year (int): the year that need to be extracted + Return: + dict: single year income statement. Keys are income statement items. + Note: + if the target year is not in self.table, then return None. + """ + for current_income_statement in self.table: + if current_income_statement.year == year: + return { + 'year': current_income_statement.year, + 'revenue': current_income_statement.revenue, + 'utility_expense': current_income_statement.utility_expense, + 'energy_opex': current_income_statement.energy_opex, + 'electricity_opex': current_income_statement.electricity_opex, + 'gas_opex': current_income_statement.gas_opex, + 'oil_opex': current_income_statement.oil_opex, + 'water_opex': current_income_statement.water_opex, + 'other_utility': current_income_statement.other_utility, + 'non_utility_expense': current_income_statement.non_utility_expense, + 'net_non_energy_opex': current_income_statement.net_non_energy_opex, + 'total_opex': current_income_statement.total_opex, + 'noi': current_income_statement.noi + } + return None + + def get_noi_dict(self): + """ + Get a dictionary of net operating income. + Return: + dictionary: net operating income for each year in income statement table. Key is year + """ + noi_dict = {} + for current_income_statement in self.table: + noi_dict[ + current_income_statement.year] = current_income_statement.noi + return noi_dict + + def get_first_year_noi(self, commission_date): + """ + Get first year noi after commissioning year, from post_saving income statement + Args: + commission_date (date): construction finishing date. Saving starts NEXT month/year + Return: + float: noi of the next year after commission date + """ + first_year = commission_date.year + 1 + for current_income_statement in self.table: + if current_income_statement.year == first_year: + return current_income_statement.noi + + def get_full_income_table(self): + """ + Get full projected income statement table + Return: + dictionary: dict of dict of income statement. Key is year + """ + # validate projection availability + if self.table[-1].year <= self.hist_end_year: + raise ValueError('income statement is not projected properly') + table_dict = {} + for current_income_statement in self.table: + table_dict[current_income_statement.year] = { + 'year': current_income_statement.year, + 'revenue': current_income_statement.revenue, + 'utility_expense': current_income_statement.utility_expense, + 'energy_opex': current_income_statement.energy_opex, + 'electricity_opex': current_income_statement.electricity_opex, + 'gas_opex': current_income_statement.gas_opex, + 'oil_opex': current_income_statement.oil_opex, + 'water_opex': current_income_statement.water_opex, + 'other_utility': current_income_statement.other_utility, + 'non_utility_expense': current_income_statement.non_utility_expense, + 'net_non_energy_opex': current_income_statement.net_non_energy_opex, + 'total_opex': current_income_statement.total_opex, + 'noi': current_income_statement.noi + } + return table_dict + + def get_total_energy_dict(self): + total_energy_dict = {} + for current_income_statement in self.table: + total_energy_dict[ + current_income_statement.year] = current_income_statement.energy_opex + return total_energy_dict diff --git a/bpfin/financials/financial_lib.py b/bpfin/financials/financial_lib.py index 253c1ec..2fead0d 100644 --- a/bpfin/financials/financial_lib.py +++ b/bpfin/financials/financial_lib.py @@ -43,7 +43,7 @@ def organize_bill_overview(bill_overview, analysis_date): average_bill_dict[i] = float(sum_bill) / year_number else: average_bill_dict[i] = 0 - # average_bill_dict[i] = float(sum(bill_dict[i][0][year] for year in bill_dict[i][0])) / len(bill_dict[i][0]) + # average_bill_dict[i] = float(sum(bill_dict[i][0][year] for year in bill_dict[i][0]))/len(bill_dict[i][0]) for year in proforma_year: for i in range(1, 5): @@ -149,26 +149,6 @@ class Income_Statement(): self.total_opex = self.energy_opex + self.net_non_energy_opex self.noi = self.revenue - self.total_opex - # def assign_next(self, income_statement_characters, - # bill_overview_organized): - # """ - # !!! this function will be deleted in the next version!! - # """ - # self.electricity_opex = bill_overview_organized['electricity'][ - # self.year] - # self.gas_opex = bill_overview_organized['gas'][self.year] - # self.oil_opex = bill_overview_organized['oil'][self.year] - # self.water_opex = bill_overview_organized['water'][self.year] - # self.energy_opex = self.electricity_opex + self.gas_opex + self.oil_opex + self.water_opex - # self.other_utility = self.revenue * income_statement_characters[ - # 'other_utility_percent'] - # self.non_utility_expense = self.revenue * income_statement_characters[ - # 'non_utility_expense_percent'] - # self.utility_expense = self.energy_opex + self.other_utility - # self.net_non_energy_opex = self.other_utility + self.non_utility_expense - # self.total_opex = self.energy_opex + self.net_non_energy_opex - # self.noi = self.revenue - self.total_opex - def convert_income_statement_class(income_statement_class): """ @@ -443,32 +423,19 @@ class Income_Statement_Table(): for current_income_statement in self.table: if current_income_statement.year == year: return { - 'year': - current_income_statement.year, - 'revenue': - current_income_statement.revenue, - 'utility_expense': - current_income_statement.utility_expense, - 'energy_opex': - current_income_statement.energy_opex, - 'electricity_opex': - current_income_statement.electricity_opex, - 'gas_opex': - current_income_statement.gas_opex, - 'oil_opex': - current_income_statement.oil_opex, - 'water_opex': - current_income_statement.water_opex, - 'other_utility': - current_income_statement.other_utility, - 'non_utility_expense': - current_income_statement.non_utility_expense, - 'net_non_energy_opex': - current_income_statement.net_non_energy_opex, - 'total_opex': - current_income_statement.total_opex, - 'noi': - current_income_statement.noi + 'year': current_income_statement.year, + 'revenue': current_income_statement.revenue, + 'utility_expense': current_income_statement.utility_expense, + 'energy_opex': current_income_statement.energy_opex, + 'electricity_opex': current_income_statement.electricity_opex, + 'gas_opex': current_income_statement.gas_opex, + 'oil_opex': current_income_statement.oil_opex, + 'water_opex': current_income_statement.water_opex, + 'other_utility': current_income_statement.other_utility, + 'non_utility_expense': current_income_statement.non_utility_expense, + 'net_non_energy_opex': current_income_statement.net_non_energy_opex, + 'total_opex': current_income_statement.total_opex, + 'noi': current_income_statement.noi } return None diff --git a/bpfin/lib/back_end_call.py b/bpfin/lib/back_end_call.py index 0df33f3..449ba98 100644 --- a/bpfin/lib/back_end_call.py +++ b/bpfin/lib/back_end_call.py @@ -1,6 +1,7 @@ from bpfin.utilbills.bill import Bill -from bpfin.financials.financial_lib import Income_Statement_Table -# from bpfin.tests.testdata import feature_data as db +# from bpfin.financials.financial_lib import Income_Statement_Table +from bpfin.financials.financial_income import Income_Statement_Table +from bpfin.tests.testdata import feature_data as db # import pprint @@ -134,7 +135,7 @@ def prior_income_statement(raw_income_input, raw_bill_table, raw_annual_bill_tab analysis_date (dictionary): proforma's starting date and the years of proforma growth_rate_flag (float): indicating assumed growth rate, -2.0 == cagr, -1.0 == historical average Returns: - prior_income_statement (dictionary): dict of dict of prior_saving income statement. Key is year + prior_income (dictionary): dict of dict of prior_saving income statement. Key is year next_year_income (dictionary): next year income statement. Keys are income statement items. average_income (dictionary): single year income statement for historical average. Keys = income statement items historical_cagr (float): compound annual growth rate @@ -147,7 +148,7 @@ def prior_income_statement(raw_income_input, raw_bill_table, raw_annual_bill_tab 'gas': dict of gas_bill, 'water': dict of water_bill} - prior_income_statement = {2014: {'year': 2014, 'revenue': 100.0, ..., 'not': 5.0}, ... , 2016:{}} + prior_income = {2014: {'year': 2014, 'revenue': 100.0, ..., 'not': 5.0}, ... , 2016:{}} """ annual_bill_table = annual_bill(raw_bill_table, raw_annual_bill_table, analysis_date) @@ -164,12 +165,12 @@ def prior_income_statement(raw_income_input, raw_bill_table, raw_annual_bill_tab # **** ugly test **** # print('\nmonthly_bill =', monthly_bill(db.raw_bill_table, db.analysis_date)) # print('\nannual_bill =', annual_bill(db.raw_bill_table, db.raw_annual_bill_table, db.analysis_date)) -# print('\nprior_income_statement =', prior_income_statement( -# db.raw_income_input, -# db.prior_annual_bill, -# db.analysis_date, -# -2.0)) - +print('\nprior_income_statement =', prior_income_statement( + db.raw_income_input, + db.raw_bill_table, + db.raw_annual_bill_table, + db.analysis_date, + -2.0)) # writein = str(result) # f = open('data_generation.py', 'w') diff --git a/bpfin/tests/test_utilbills/test_back_end_call.py b/bpfin/tests/test_utilbills/test_back_end_call.py index b991a09..fa2b995 100644 --- a/bpfin/tests/test_utilbills/test_back_end_call.py +++ b/bpfin/tests/test_utilbills/test_back_end_call.py @@ -26,7 +26,6 @@ def test_prior_income_statement(): output_historical_cagr = db.historical_cagr prior_income, next_year_income, average_income, historical_cagr = prior_income_statement( db.raw_income_input, - # db.prior_annual_bill, db.raw_bill_table, db.raw_annual_bill_table, db.analysis_date, -- GitLab From 63e42dd75b3b4663c468289d7bbb3dfc887b65ab Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Fri, 19 May 2017 12:09:02 -0400 Subject: [PATCH 05/37] Improve test files for backend calls for Bill class. Need to improve Income Statement as well --- bpfin/lib/back_end_call.py | 17 +- .../test_utilbills/test_back_end_call.py | 34 +- bpfin/tests/test_utilbills/test_bill.py | 40 +- bpfin/tests/testdata/feature_data.py | 1447 +++++++++-------- 4 files changed, 874 insertions(+), 664 deletions(-) diff --git a/bpfin/lib/back_end_call.py b/bpfin/lib/back_end_call.py index 449ba98..684fcda 100644 --- a/bpfin/lib/back_end_call.py +++ b/bpfin/lib/back_end_call.py @@ -2,7 +2,7 @@ from bpfin.utilbills.bill import Bill # from bpfin.financials.financial_lib import Income_Statement_Table from bpfin.financials.financial_income import Income_Statement_Table from bpfin.tests.testdata import feature_data as db -# import pprint +import pprint UTILITY_TYPE_LIST = ['electricity', 'gas', 'oil', 'water'] @@ -163,14 +163,25 @@ def prior_income_statement(raw_income_input, raw_bill_table, raw_annual_bill_tab # **** ugly test **** +# print(db.raw_bill_table) # print('\nmonthly_bill =', monthly_bill(db.raw_bill_table, db.analysis_date)) # print('\nannual_bill =', annual_bill(db.raw_bill_table, db.raw_annual_bill_table, db.analysis_date)) -print('\nprior_income_statement =', prior_income_statement( +# print('\nprior_income_statement =', prior_income_statement( +# db.raw_income_input, +# db.raw_bill_table, +# db.raw_annual_bill_table, +# db.analysis_date, +# -2.0)) + +prior_income_statement_result = prior_income_statement( db.raw_income_input, db.raw_bill_table, db.raw_annual_bill_table, db.analysis_date, - -2.0)) + -2.0) + +pp = pprint.PrettyPrinter(width=120, indent=4, compact=True) +pp.pprint(prior_income_statement_result) # writein = str(result) # f = open('data_generation.py', 'w') diff --git a/bpfin/tests/test_utilbills/test_back_end_call.py b/bpfin/tests/test_utilbills/test_back_end_call.py index fa2b995..c281259 100644 --- a/bpfin/tests/test_utilbills/test_back_end_call.py +++ b/bpfin/tests/test_utilbills/test_back_end_call.py @@ -6,8 +6,8 @@ from bpfin.tests.testdata import sample_data as sdb def test_monthly_bill(): output_dict = { 'electricity': db.prior_annual_bill['electricity'], - 'gas': None, - 'oil': None, + 'gas': db.prior_annual_bill['gas'], + 'oil': db.prior_annual_bill['oil'], 'water': None} result_dict = monthly_bill(db.raw_bill_table, db.analysis_date) assert output_dict == result_dict @@ -19,18 +19,18 @@ def test_annual_bill(): assert output_dict == result_dict -def test_prior_income_statement(): - output_income_statement = db.prior_income_statement_cagr - output_next_year_income = db.next_year_income - output_average_income = db.average_income - output_historical_cagr = db.historical_cagr - prior_income, next_year_income, average_income, historical_cagr = prior_income_statement( - db.raw_income_input, - db.raw_bill_table, - db.raw_annual_bill_table, - db.analysis_date, - -2.0) - assert output_income_statement == prior_income - assert output_next_year_income == next_year_income - assert output_average_income == average_income - assert output_historical_cagr == historical_cagr +# def test_prior_income_statement(): +# output_income_statement = db.prior_income_statement_cagr +# output_next_year_income = db.next_year_income +# output_average_income = db.average_income +# output_historical_cagr = db.historical_cagr +# prior_income, next_year_income, average_income, historical_cagr = prior_income_statement( +# db.raw_income_input, +# db.raw_bill_table, +# db.raw_annual_bill_table, +# db.analysis_date, +# -2.0) +# assert output_income_statement == prior_income +# assert output_next_year_income == next_year_income +# assert output_average_income == average_income +# assert output_historical_cagr == historical_cagr diff --git a/bpfin/tests/test_utilbills/test_bill.py b/bpfin/tests/test_utilbills/test_bill.py index 5e27f23..02ebf74 100644 --- a/bpfin/tests/test_utilbills/test_bill.py +++ b/bpfin/tests/test_utilbills/test_bill.py @@ -1,8 +1,42 @@ -# from datetime import date -# from bpfin.utilbills.bill import Bill_Table -# from bpfin.tests.testdata import feature_data as db +from datetime import date +from bpfin.utilbills.bill import Bill +from bpfin.tests.testdata import feature_data as db +UTILITY_TYPE_LIST = ['electricity', 'gas', 'oil', 'water'] + + +def test_Bill_put_month(): + """ + test Bill with utility inputs + """ + analysis_date = db.analysis_date + + for utility in UTILITY_TYPE_LIST: + if db.raw_bill_table[utility]: + input_raw_bill = db.raw_bill_table[utility] + current_bill = Bill(utility, analysis_date) + current_bill.put_month_bill(input_raw_bill) + output_annual_bill = db.prior_annual_bill[utility] + # print('\n', current_bill.get_annual_bill()) + assert output_annual_bill == current_bill.get_annual_bill() + + +def test_Bill_put_annual(): + """ + test Bill with utility inputs + """ + analysis_date = db.analysis_date + + for utility in UTILITY_TYPE_LIST: + if not db.raw_bill_table[utility]: + input_raw_annual_bill = db.raw_annual_bill_table[utility] + current_bill = Bill(utility, analysis_date) + current_bill.put_annual_bill(input_raw_annual_bill) + output_annual_bill = db.prior_annual_bill[utility] + # print('\n', current_bill.get_annual_bill()) + assert output_annual_bill == current_bill.get_annual_bill() + # def test_Bill_Table_put_month(): # """ # test Bill_Table with only inputing month bill diff --git a/bpfin/tests/testdata/feature_data.py b/bpfin/tests/testdata/feature_data.py index d9895af..dbd96c1 100644 --- a/bpfin/tests/testdata/feature_data.py +++ b/bpfin/tests/testdata/feature_data.py @@ -1,7 +1,6 @@ """ feature_data.py is a fake database to store demo test data """ -import datetime from datetime import date # from bpfin.utilbills.bill import form_bill_list_month # from bpfin.utilbills.bill import form_annual_bill_table @@ -14,13 +13,13 @@ import pprint # pro-forma projection time base analysis_date = { - 'proforma_start': datetime.date(2012, 1, 15), + 'proforma_start': date(2012, 1, 15), 'proforma_duration': 25} # Engineering Scenarios and project economics cost_estimation = 150000.00 -commission_date = datetime.date(2017, 3, 14) +commission_date = date(2017, 3, 14) # required debt service coverage ratio @@ -56,73 +55,203 @@ full_saving_dict = { # dict of engineering analysis, {'date_from': [], 'date_to': [], 'heating': [], 'cooling': [], 'other': []} -e_raw_bill = { - 'date_from': [ - date(2015, 1, 28), date(2015, 2, 27), date(2015, 3, 30), date(2015, 4, 28), - date(2015, 5, 28), date(2015, 6, 26), date(2015, 7, 28), date(2015, 8, 26), - date(2015, 9, 25), date(2015, 10, 27), date(2015, 11, 25), date(2015, 12, 29), - date(2016, 1, 28), date(2016, 2, 29), date(2016, 3, 29), date(2016, 4, 27), - date(2016, 5, 26), date(2016, 6, 27), date(2016, 7, 27), date(2016, 8, 25), - date(2016, 9, 26), date(2016, 10, 26), date(2016, 11, 28) - ], - 'date_to': [ - date(2015, 2, 27), date(2015, 3, 30), date(2015, 4, 28), date(2015, 5, 28), - date(2015, 6, 26), date(2015, 7, 28), date(2015, 8, 26), date(2015, 9, 25), - date(2015, 10, 27), date(2015, 11, 25), date(2015, 12, 29), date(2016, 1, 28), - date(2016, 2, 29), date(2016, 3, 29), date(2016, 4, 27), date(2016, 5, 26), - date(2016, 6, 27), date(2016, 7, 27), date(2016, 8, 25), date(2016, 9, 26), - date(2016, 10, 26), date(2016, 11, 28), date(2016, 12, 28) - ], - 'usage': [ - 214.66, 189.42, 190.8, 168.92, 189.02, 179.64, 154.95, 162.13, - 136.16, 144.06, 208.85, 182.55, 98.13, 104.19, 90.05, - 88.19, 101.05, 87.05, 86.88, 98.17, 89.07, 91.93, 117.88 - ], - 'charge': [ - 172.33, 163.88, 163.49, 196.46, 169.68, 152.56, 126.16, - 137.14, 136.1, 130.65, 172.37, 145.44, 71.73, 68.12, 63.57, - 68.28, 71.66, 56.21, 57.25, 63.6, 67.42, 39.62, 56.01 - ] -} +# e_raw_bill = { +# 'date_from': [ +# date(2015, 1, 28), date(2015, 2, 27), date(2015, 3, 30), date(2015, 4, 28), +# date(2015, 5, 28), date(2015, 6, 26), date(2015, 7, 28), date(2015, 8, 26), +# date(2015, 9, 25), date(2015, 10, 27), date(2015, 11, 25), date(2015, 12, 29), +# date(2016, 1, 28), date(2016, 2, 29), date(2016, 3, 29), date(2016, 4, 27), +# date(2016, 5, 26), date(2016, 6, 27), date(2016, 7, 27), date(2016, 8, 25), +# date(2016, 9, 26), date(2016, 10, 26), date(2016, 11, 28) +# ], +# 'date_to': [ +# date(2015, 2, 27), date(2015, 3, 30), date(2015, 4, 28), date(2015, 5, 28), +# date(2015, 6, 26), date(2015, 7, 28), date(2015, 8, 26), date(2015, 9, 25), +# date(2015, 10, 27), date(2015, 11, 25), date(2015, 12, 29), date(2016, 1, 28), +# date(2016, 2, 29), date(2016, 3, 29), date(2016, 4, 27), date(2016, 5, 26), +# date(2016, 6, 27), date(2016, 7, 27), date(2016, 8, 25), date(2016, 9, 26), +# date(2016, 10, 26), date(2016, 11, 28), date(2016, 12, 28) +# ], +# 'usage': [ +# 214.66, 189.42, 190.8, 168.92, 189.02, 179.64, 154.95, 162.13, +# 136.16, 144.06, 208.85, 182.55, 98.13, 104.19, 90.05, +# 88.19, 101.05, 87.05, 86.88, 98.17, 89.07, 91.93, 117.88 +# ], +# 'charge': [ +# 172.33, 163.88, 163.49, 196.46, 169.68, 152.56, 126.16, +# 137.14, 136.1, 130.65, 172.37, 145.44, 71.73, 68.12, 63.57, +# 68.28, 71.66, 56.21, 57.25, 63.6, 67.42, 39.62, 56.01 +# ] +# } -raw_bill_table = { - 'electricity': e_raw_bill, - # 'gas': None, - # 'oil': None, - # 'water': None, -} +raw_elec_bill_demo = {} +raw_elec_bill_demo['utility_type'] = 'electricity' +raw_elec_bill_demo['date_from'] = [ + date(2016, 11, 28), date(2016, 10, 26), date(2016, 9, 26), + date(2016, 8, 25), date(2016, 7, 27), date(2016, 6, 27), + date(2016, 5, 26), date(2016, 4, 27), date(2016, 3, 29), + date(2016, 2, 29), date(2016, 1, 28), date(2016, 12, 29), + date(2015, 11, 25), date(2015, 10, 27), date(2015, 9, 25), + date(2015, 8, 26), date(2015, 7, 28), date(2015, 6, 26), + date(2015, 5, 28), date(2015, 4, 28), date(2015, 3, 30), + date(2015, 2, 27), date(2015, 1, 28)] +raw_elec_bill_demo['date_to'] = [ + date(2016, 12, 28), date(2016, 11, 28), date(2016, 10, 26), + date(2016, 9, 26), date(2016, 8, 25), date(2016, 7, 27), + date(2016, 6, 27), date(2016, 5, 26), date(2016, 4, 27), + date(2016, 3, 29), date(2016, 2, 29), date(2016, 1, 28), + date(2016, 12, 29), date(2015, 11, 25), date(2015, 10, 27), + date(2015, 9, 25), date(2015, 8, 26), date(2015, 7, 28), + date(2015, 6, 26), date(2015, 5, 28), date(2015, 4, 28), + date(2015, 3, 30), date(2015, 2, 27)] +raw_elec_bill_demo['charge'] = [ + 56.01, 39.62, 67.42, 63.6, + 57.25, 56.21, 71.66, 68.28, + 63.57, 68.12, 71.73, 145.44, + 172.37, 130.65, 136.1, 137.14, + 126.16, 152.56, 169.68, 196.46, + 163.49, 163.88, 172.33] +raw_elec_bill_demo['usage'] = [ + 117.88, 91.93, 89.07, 98.17, + 86.88, 87.05, 101.05, 88.19, + 90.05, 104.19, 98.13, 182.55, + 208.85, 144.06, 136.16, 162.13, + 154.95, 179.64, 189.02, 168.92, + 190.8, 189.42, 214.66] + +raw_gas_bill_demo = {} +raw_gas_bill_demo['utility_type'] = 'gas' +raw_gas_bill_demo['date_from'] = [ + date(2016, 11, 22), date(2016, 10, 18), date(2016, 9, 30), + date(2016, 9, 19), date(2016, 8, 18), date(2016, 7, 20), + date(2016, 6, 20), date(2016, 5, 18), date(2016, 4, 19), + date(2016, 3, 18), date(2016, 2, 17), date(2016, 1, 19), + date(2015, 12, 16), date(2015, 11, 16), date(2015, 10, 16), + date(2015, 9, 19), date(2015, 8, 18), date(2015, 7, 20), + date(2015, 6, 18), date(2015, 5, 19)] +raw_gas_bill_demo['date_to'] = [ + date(2016, 12, 16), date(2016, 11, 22), date(2016, 10, 18), + date(2016, 9, 30), date(2016, 9, 19), date(2016, 8, 18), + date(2016, 7, 20), date(2016, 6, 20), date(2016, 5, 18), + date(2016, 4, 19), date(2016, 3, 18), date(2016, 2, 17), + date(2016, 1, 19), date(2015, 12, 16), date(2015, 11, 16), + date(2015, 10, 16), date(2015, 9, 19), date(2015, 8, 18), + date(2015, 7, 20), date(2015, 6, 18)] +raw_gas_bill_demo['charge'] = [ + 304.79, 456.54, 232.75, 372.16, + 192.29, 379.36, 385.14, 400.74, + 343.49, 377.99, 378.44, 361.68, + 454.84, 397.33, 401.29, 354.76, + 412.32, 378.43, 414.33, 390.65] +raw_gas_bill_demo['usage'] = [ + 322.00, 470.00, 241.00, 148.00, + 429.00, 389.00, 402.00, 443.00, + 389.00, 429.00, 402.00, 389.00, + 456.00, 402.00, 416.00, 362.00, + 429.00, 389.00, 429.00, 402.00] +raw_oil_bill_demo = {} +raw_oil_bill_demo['utility_type'] = 'oil' +raw_oil_bill_demo['date_from'] = [ + date(2016, 11, 28), date(2016, 10, 26), date(2016, 9, 26), + date(2016, 8, 25), date(2016, 7, 27), date(2016, 6, 27), + date(2016, 5, 26), date(2016, 4, 27), date(2016, 3, 29), + date(2016, 2, 29), date(2016, 1, 28), date(2016, 12, 29), + date(2015, 11, 25), date(2015, 10, 27), date(2015, 9, 25), + date(2015, 8, 26), date(2015, 7, 28), date(2015, 6, 26), + date(2015, 5, 28), date(2015, 4, 28), date(2015, 3, 30), + date(2015, 2, 27), date(2015, 1, 28)] +raw_oil_bill_demo['date_to'] = [ + date(2016, 12, 28), date(2016, 11, 28), date(2016, 10, 26), + date(2016, 9, 26), date(2016, 8, 25), date(2016, 7, 27), + date(2016, 6, 27), date(2016, 5, 26), date(2016, 4, 27), + date(2016, 3, 29), date(2016, 2, 29), date(2016, 1, 28), + date(2016, 12, 29), date(2015, 11, 25), date(2015, 10, 27), + date(2015, 9, 25), date(2015, 8, 26), date(2015, 7, 28), + date(2015, 6, 26), date(2015, 5, 28), date(2015, 4, 28), + date(2015, 3, 30), date(2015, 2, 27)] +raw_oil_bill_demo['charge'] = [ + 3100, 2400, 3380, 1850, + 3000, 3200, 6700, 5300, + 4850, 5130, 5700, 3120, + 2420, 3400, 1870, 3020, + 3220, 6720, 5320, 4870, + 5150, 5720, 3680] +raw_oil_bill_demo['usage'] = [ + 1200, 700, 1000, 500, + 800, 900, 1700, 1400, + 1200, 1300, 1500, 1200, + 750, 1050, 550, 850, + 950, 1750, 1450, 1250, + 1350, 1550, 1450] + +raw_water_bill_demo = {} +raw_water_bill_demo['utility_type'] = 'water' +raw_water_bill_demo['date_from'] = [ + date(2016, 1, 3), date(2015, 1, 1), date(2014, 1, 2)] +raw_water_bill_demo['date_to'] = [ + date(2016, 12, 28), date(2016, 1, 2), date(2014, 12, 31)] +raw_water_bill_demo['charge'] = [ + 20000, 20500, 21000] +raw_water_bill_demo['usage'] = [ + 3500000, 3600000, 3300000] + +raw_bill_table = { + 'gas': raw_gas_bill_demo, + 'electricity': raw_elec_bill_demo, + 'oil': raw_oil_bill_demo, + 'water': None} # raw annual_bill -annual_bill_gas = {2014: 0, 2015: 1020, 2016: 1220, 2017: 1520} -annual_bill_oil = {2015: 1010, 2016: 1210, 2017: 1510} -annual_bill_water = {2015: 0, 2016: 0, 2017: 0} +# annual_bill_gas = {2014: 0, 2015: 1020, 2016: 1220, 2017: 1520} +# annual_bill_oil = {2015: 1010, 2016: 1210, 2017: 1510} +annual_bill_water = {2014: 20000, 2015: 20500, 2016: 21000} raw_annual_bill_table = { - # 'electricity': None, # True == Mannual Input - 'gas': annual_bill_gas, - 'oil': annual_bill_oil, + 'electricity': None, # True == Mannual Input + 'gas': None, + 'oil': None, 'water': annual_bill_water } # raw income_statement +# raw_income_input = { +# 2014: { +# 'revenue': 90000, +# 'utility_expense': 55000, +# 'non_utility_expense': 3500 +# }, +# 2015: { +# 'revenue': 95000, +# 'utility_expense': 55000, +# 'non_utility_expense': 3000 +# }, +# 2016: { +# 'revenue': 100000, +# 'utility_expense': 60000, +# 'non_utility_expense': 3000 +# } +# } + + raw_income_input = { 2014: { - 'revenue': 90000, - 'utility_expense': 55000, - 'non_utility_expense': 3500 + 'revenue': 200000, + 'utility_expense': 77000, + 'non_utility_expense': 105000, }, 2015: { - 'revenue': 95000, - 'utility_expense': 55000, - 'non_utility_expense': 3000 + 'revenue': 196000, + 'utility_expense': 77400, + 'non_utility_expense': 104000, }, 2016: { - 'revenue': 100000, - 'utility_expense': 60000, - 'non_utility_expense': 3000 + 'revenue': 205000, + 'utility_expense': 78100, + 'non_utility_expense': 130000, } } + # saving scenarios percent_saving_dict = { 'electricity': 0.25, @@ -140,604 +269,640 @@ full_saving_dict = { prior_annual_bill = { 'electricity': { - 2012: 1302.3894189123205, - 2013: 1325.5398892097569, - 2014: 1346.0795010524571, - 2015: 1357.4370596899435, - 2016: 1368.4645719731475, - 2017: 1395.2434398071116, - 2018: 1429.9391383624793, - 2019: 1465.1219842627888, - 2020: 1499.442976989403, - 2021: 1531.5444508417731, - 2022: 1560.6164039629107, - 2023: 1589.1048030135796, - 2024: 1618.1893852141502, - 2025: 1648.2611314796882, - 2026: 1680.5743815217027, - 2027: 1715.4591028542839, - 2028: 1751.2717401473571, - 2029: 1787.1346258078672, - 2030: 1822.9958881766795, - 2031: 1858.9654290419135, - 2032: 1895.3329028685823, - 2033: 1932.5220357027845, - 2034: 1970.7052052121689, - 2035: 2009.9298853655182, - 2036: 2050.2008318127446 + 2012: 792.50603354980865, 2013: 806.56436875723125, 2014: 819.06930386346062, 2015: 825.90552345154924, + 2016: 832.68423357284746, 2017: 849.02230670593224, 2018: 870.14337868170207, 2019: 891.54208077704823, + 2020: 912.4254645897646, 2021: 931.94007239274924, 2022: 949.62365204805212, 2023: 966.95721096995919, + 2024: 984.65685227063227, 2025: 1002.9565908187957, 2026: 1022.6293693938102, 2027: 1043.8599889408579, + 2028: 1065.650260619291, 2029: 1087.4697953564814, 2030: 1109.2892523473229, 2031: 1131.1744618622365, + 2032: 1153.3039252083101, 2033: 1175.9341789481377, 2034: 1199.1695873801598, 2035: 1223.0386652944458, + 2036: 1247.5443683668141 }, 'gas': { - 2014: 0, - 2015: 1020, - 2016: 1220, - 2017: 1520, - 2012: 1253.3333333333333, - 2013: 1253.3333333333333, - 2018: 1253.3333333333333, - 2019: 1253.3333333333333, - 2020: 1253.3333333333333, - 2021: 1253.3333333333333, - 2022: 1253.3333333333333, - 2023: 1253.3333333333333, - 2024: 1253.3333333333333, - 2025: 1253.3333333333333, - 2026: 1253.3333333333333, - 2027: 1253.3333333333333, - 2028: 1253.3333333333333, - 2029: 1253.3333333333333, - 2030: 1253.3333333333333, - 2031: 1253.3333333333333, - 2032: 1253.3333333333333, - 2033: 1253.3333333333333, - 2034: 1253.3333333333333, - 2035: 1253.3333333333333, - 2036: 1253.3333333333333 + 2012: 4475.7823032289816, 2013: 4554.23035844273, 2014: 4625.0674743716318, 2015: 4661.2913287497577, + 2016: 4701.7495360589701, 2017: 4795.4503391884955, 2018: 4915.0282767633271, 2019: 5035.5379855566225, + 2020: 5153.4461029776512, 2021: 5263.0160958060724, 2022: 5362.6629176416373, 2023: 5460.5010514877649, + 2024: 5560.5157868837869, 2025: 5663.9000896622329, 2026: 5775.3403422790016, 2027: 5895.3500983195381, + 2028: 6018.354334038997, 2029: 6141.4801983648376, 2030: 6264.6360349883253, 2031: 6388.1588176948035, + 2032: 6513.1311498178793, 2033: 6640.9586307853224, 2034: 6772.2131729990733, 2035: 6907.0434291160136, + 2036: 7045.4681428808135 }, 'oil': { - 2015: 1010, - 2016: 1210, - 2017: 1510, - 2012: 1243.3333333333333, - 2013: 1243.3333333333333, - 2014: 1243.3333333333333, - 2018: 1243.3333333333333, - 2019: 1243.3333333333333, - 2020: 1243.3333333333333, - 2021: 1243.3333333333333, - 2022: 1243.3333333333333, - 2023: 1243.3333333333333, - 2024: 1243.3333333333333, - 2025: 1243.3333333333333, - 2026: 1243.3333333333333, - 2027: 1243.3333333333333, - 2028: 1243.3333333333333, - 2029: 1243.3333333333333, - 2030: 1243.3333333333333, - 2031: 1243.3333333333333, - 2032: 1243.3333333333333, - 2033: 1243.3333333333333, - 2034: 1243.3333333333333, - 2035: 1243.3333333333333, - 2036: 1243.3333333333333 + 2012: 29234.099384206329, 2013: 29755.35937994433, 2014: 30216.03963037725, 2015: 30474.979346602693, + 2016: 30718.862565999072, 2017: 31317.518165038713, 2018: 32095.810899238011, 2019: 32886.130778177096, + 2020: 33656.574871338729, 2021: 34378.237209910454, 2022: 35031.181929600622, 2023: 35670.741459090197, + 2024: 36323.497554619345, 2025: 36998.445300671876, 2026: 37723.192824355341, 2027: 38506.050354491614, + 2028: 39310.02024337896, 2029: 40115.192469629976, 2030: 40920.276277032368, 2031: 41727.798007431789, + 2032: 42544.132418124602, 2033: 43378.864396965881, 2034: 44235.89304442647, 2035: 45116.305108602697, + 2036: 46020.203841190028 }, - 'water': { - 2015: 0, - 2016: 0, - 2017: 0, - 2012: 0, - 2013: 0, - 2014: 0, - 2018: 0, - 2019: 0, - 2020: 0, - 2021: 0, - 2022: 0, - 2023: 0, - 2024: 0, - 2025: 0, - 2026: 0, - 2027: 0, - 2028: 0, - 2029: 0, - 2030: 0, - 2031: 0, - 2032: 0, - 2033: 0, - 2034: 0, - 2035: 0, - 2036: 0 + 'water': { + 2014: 20000, 2015: 20500, 2016: 21000, 2012: 20500.0, 2013: 20500.0, 2017: 20500.0, 2018: 20500.0, + 2019: 20500.0, 2020: 20500.0, 2021: 20500.0, 2022: 20500.0, 2023: 20500.0, 2024: 20500.0, 2025: 20500.0, + 2026: 20500.0, 2027: 20500.0, 2028: 20500.0, 2029: 20500.0, 2030: 20500.0, 2031: 20500.0, 2032: 20500.0, + 2033: 20500.0, 2034: 20500.0, 2035: 20500.0, 2036: 20500.0 } } +# prior_annual_bill = { +# 'electricity': { +# 2012: 1302.3894189123205, +# 2013: 1325.5398892097569, +# 2014: 1346.0795010524571, +# 2015: 1357.4370596899435, +# 2016: 1368.4645719731475, +# 2017: 1395.2434398071116, +# 2018: 1429.9391383624793, +# 2019: 1465.1219842627888, +# 2020: 1499.442976989403, +# 2021: 1531.5444508417731, +# 2022: 1560.6164039629107, +# 2023: 1589.1048030135796, +# 2024: 1618.1893852141502, +# 2025: 1648.2611314796882, +# 2026: 1680.5743815217027, +# 2027: 1715.4591028542839, +# 2028: 1751.2717401473571, +# 2029: 1787.1346258078672, +# 2030: 1822.9958881766795, +# 2031: 1858.9654290419135, +# 2032: 1895.3329028685823, +# 2033: 1932.5220357027845, +# 2034: 1970.7052052121689, +# 2035: 2009.9298853655182, +# 2036: 2050.2008318127446 +# }, +# 'gas': { +# 2014: 0, +# 2015: 1020, +# 2016: 1220, +# 2017: 1520, +# 2012: 1253.3333333333333, +# 2013: 1253.3333333333333, +# 2018: 1253.3333333333333, +# 2019: 1253.3333333333333, +# 2020: 1253.3333333333333, +# 2021: 1253.3333333333333, +# 2022: 1253.3333333333333, +# 2023: 1253.3333333333333, +# 2024: 1253.3333333333333, +# 2025: 1253.3333333333333, +# 2026: 1253.3333333333333, +# 2027: 1253.3333333333333, +# 2028: 1253.3333333333333, +# 2029: 1253.3333333333333, +# 2030: 1253.3333333333333, +# 2031: 1253.3333333333333, +# 2032: 1253.3333333333333, +# 2033: 1253.3333333333333, +# 2034: 1253.3333333333333, +# 2035: 1253.3333333333333, +# 2036: 1253.3333333333333 +# }, +# 'oil': { +# 2015: 1010, +# 2016: 1210, +# 2017: 1510, +# 2012: 1243.3333333333333, +# 2013: 1243.3333333333333, +# 2014: 1243.3333333333333, +# 2018: 1243.3333333333333, +# 2019: 1243.3333333333333, +# 2020: 1243.3333333333333, +# 2021: 1243.3333333333333, +# 2022: 1243.3333333333333, +# 2023: 1243.3333333333333, +# 2024: 1243.3333333333333, +# 2025: 1243.3333333333333, +# 2026: 1243.3333333333333, +# 2027: 1243.3333333333333, +# 2028: 1243.3333333333333, +# 2029: 1243.3333333333333, +# 2030: 1243.3333333333333, +# 2031: 1243.3333333333333, +# 2032: 1243.3333333333333, +# 2033: 1243.3333333333333, +# 2034: 1243.3333333333333, +# 2035: 1243.3333333333333, +# 2036: 1243.3333333333333 +# }, +# 'water': { +# 2015: 0, +# 2016: 0, +# 2017: 0, +# 2012: 0, +# 2013: 0, +# 2014: 0, +# 2018: 0, +# 2019: 0, +# 2020: 0, +# 2021: 0, +# 2022: 0, +# 2023: 0, +# 2024: 0, +# 2025: 0, +# 2026: 0, +# 2027: 0, +# 2028: 0, +# 2029: 0, +# 2030: 0, +# 2031: 0, +# 2032: 0, +# 2033: 0, +# 2034: 0, +# 2035: 0, +# 2036: 0 +# } +# } -prior_income_statement_cagr = { - 2014: { - 'year': 2014, - 'revenue': 90000, - 'utility_expense': 55000, - 'energy_opex': 2589.41283438579, - 'electricity_opex': 1346.079501052457, - 'gas_opex': 0, - 'oil_opex': 1243.3333333333333, - 'water_opex': 0, - 'other_utility': 52410.58716561421, - 'non_utility_expense': 3500, - 'net_non_energy_opex': 55910.58716561421, - 'total_opex': 58500.0, - 'noi': 31500.0 - }, - 2015: { - 'year': 2015, - 'revenue': 95000, - 'utility_expense': 55000, - 'energy_opex': 3387.4370596899435, - 'electricity_opex': 1357.4370596899435, - 'gas_opex': 1020, - 'oil_opex': 1010, - 'water_opex': 0, - 'other_utility': 51612.562940310054, - 'non_utility_expense': 3000, - 'net_non_energy_opex': 54612.562940310054, - 'total_opex': 58000.0, - 'noi': 37000.0 - }, - 2016: { - 'year': 2016, - 'revenue': 100000, - 'utility_expense': 60000, - 'energy_opex': 3798.4645719731475, - 'electricity_opex': 1368.4645719731475, - 'gas_opex': 1220, - 'oil_opex': 1210, - 'water_opex': 0, - 'other_utility': 56201.53542802685, - 'non_utility_expense': 3000, - 'net_non_energy_opex': 59201.53542802685, - 'total_opex': 63000.0, - 'noi': 37000.0 - }, - 2017: { - 'year': 2017, - 'revenue': 105409.25533894598, - 'utility_expense': 63685.47076980913, - 'energy_opex': 4425.243439807112, - 'electricity_opex': 1395.2434398071116, - 'gas_opex': 1520, - 'oil_opex': 1510, - 'water_opex': 0, - 'other_utility': 59260.22733000202, - 'non_utility_expense': 3513.6418446315324, - 'net_non_energy_opex': 62773.869174633546, - 'total_opex': 67199.11261444066, - 'noi': 38210.14272450532 - }, - 2018: { - 'year': 2018, - 'revenue': 111111.11111111112, - 'utility_expense': 66392.37014575081, - 'energy_opex': 3926.605805029146, - 'electricity_opex': 1429.9391383624793, - 'gas_opex': 1253.3333333333333, - 'oil_opex': 1243.3333333333333, - 'water_opex': 0, - 'other_utility': 62465.764340721675, - 'non_utility_expense': 3703.703703703704, - 'net_non_energy_opex': 66169.46804442538, - 'total_opex': 70096.07384945452, - 'noi': 41015.0372616566 - }, - 2019: { - 'year': 2019, - 'revenue': 117121.3948210511, - 'utility_expense': 69806.48568426503, - 'energy_opex': 3961.788650929455, - 'electricity_opex': 1465.1219842627888, - 'gas_opex': 1253.3333333333333, - 'oil_opex': 1243.3333333333333, - 'water_opex': 0, - 'other_utility': 65844.69703333559, - 'non_utility_expense': 3904.0464940350366, - 'net_non_energy_opex': 69748.74352737062, - 'total_opex': 73710.53217830008, - 'noi': 43410.86264275102 - }, - 2020: { - 'year': 2020, - 'revenue': 123456.79012345681, - 'utility_expense': 73402.51446668015, - 'energy_opex': 3996.1096436560692, - 'electricity_opex': 1499.442976989403, - 'gas_opex': 1253.3333333333333, - 'oil_opex': 1243.3333333333333, - 'water_opex': 0, - 'other_utility': 69406.40482302409, - 'non_utility_expense': 4115.22633744856, - 'net_non_energy_opex': 73521.63116047265, - 'total_opex': 77517.74080412873, - 'noi': 45939.049319328085 - }, - 2021: { - 'year': 2021, - 'revenue': 130134.88313450124, - 'utility_expense': 77188.98559899243, - 'energy_opex': 4028.211117508439, - 'electricity_opex': 1531.5444508417731, - 'gas_opex': 1253.3333333333333, - 'oil_opex': 1243.3333333333333, - 'water_opex': 0, - 'other_utility': 73160.77448148398, - 'non_utility_expense': 4337.829437816708, - 'net_non_energy_opex': 77498.60391930069, - 'total_opex': 81526.81503680913, - 'noi': 48608.068097692114 - }, - 2022: { - 'year': 2022, - 'revenue': 137174.21124828537, - 'utility_expense': 81175.51065176747, - 'energy_opex': 4057.283070629577, - 'electricity_opex': 1560.6164039629107, - 'gas_opex': 1253.3333333333333, - 'oil_opex': 1243.3333333333333, - 'water_opex': 0, - 'other_utility': 77118.2275811379, - 'non_utility_expense': 4572.4737082761785, - 'net_non_energy_opex': 81690.70128941408, - 'total_opex': 85747.98436004366, - 'noi': 51426.22688824171 - }, - 2023: { - 'year': 2023, - 'revenue': 144594.3145938903, - 'utility_expense': 85375.52089355137, - 'energy_opex': 4085.771469680246, - 'electricity_opex': 1589.1048030135796, - 'gas_opex': 1253.3333333333333, - 'oil_opex': 1243.3333333333333, - 'water_opex': 0, - 'other_utility': 81289.74942387112, - 'non_utility_expense': 4819.81048646301, - 'net_non_energy_opex': 86109.55991033414, - 'total_opex': 90195.33138001438, - 'noi': 54398.98321387592 - }, - 2024: { - 'year': 2024, - 'revenue': 152415.79027587266, - 'utility_expense': 89801.7755864785, - 'energy_opex': 4114.856051880816, - 'electricity_opex': 1618.1893852141502, - 'gas_opex': 1253.3333333333333, - 'oil_opex': 1243.3333333333333, - 'water_opex': 0, - 'other_utility': 85686.91953459768, - 'non_utility_expense': 5080.526342529089, - 'net_non_energy_opex': 90767.44587712677, - 'total_opex': 94882.30192900759, - 'noi': 57533.488346865066 - }, - 2025: { - 'year': 2025, - 'revenue': 160660.349548767, - 'utility_expense': 94466.87160244759, - 'energy_opex': 4144.927798146355, - 'electricity_opex': 1648.2611314796882, - 'gas_opex': 1253.3333333333333, - 'oil_opex': 1243.3333333333333, - 'water_opex': 0, - 'other_utility': 90321.94380430123, - 'non_utility_expense': 5355.3449849589, - 'net_non_energy_opex': 95677.28878926013, - 'total_opex': 99822.21658740648, - 'noi': 60838.13296136052 - }, - 2026: { - 'year': 2026, - 'revenue': 169350.87808430297, - 'utility_expense': 99384.92941996356, - 'energy_opex': 4177.241048188369, - 'electricity_opex': 1680.5743815217027, - 'gas_opex': 1253.3333333333333, - 'oil_opex': 1243.3333333333333, - 'water_opex': 0, - 'other_utility': 95207.68837177519, - 'non_utility_expense': 5645.029269476766, - 'net_non_energy_opex': 100852.71764125196, - 'total_opex': 105029.95868944033, - 'noi': 64320.919394862634 - }, - 2027: { - 'year': 2027, - 'revenue': 178511.49949863003, - 'utility_expense': 104569.84110763346, - 'energy_opex': 4212.125769520951, - 'electricity_opex': 1715.4591028542839, - 'gas_opex': 1253.3333333333333, - 'oil_opex': 1243.3333333333333, - 'water_opex': 0, - 'other_utility': 100357.71533811251, - 'non_utility_expense': 5950.383316621001, - 'net_non_energy_opex': 106308.0986547335, - 'total_opex': 110520.22442425445, - 'noi': 67991.27507437558 - }, - 2028: { - 'year': 2028, - 'revenue': 188167.6423158922, - 'utility_expense': 110034.25881989759, - 'energy_opex': 4247.938406814023, - 'electricity_opex': 1751.2717401473571, - 'gas_opex': 1253.3333333333333, - 'oil_opex': 1243.3333333333333, - 'water_opex': 0, - 'other_utility': 105786.32041308357, - 'non_utility_expense': 6272.254743863074, - 'net_non_energy_opex': 112058.57515694664, - 'total_opex': 116306.51356376066, - 'noi': 71861.12875213155 - }, - 2029: { - 'year': 2029, - 'revenue': 198346.1105540334, - 'utility_expense': 115792.37389037732, - 'energy_opex': 4283.8012924745335, - 'electricity_opex': 1787.1346258078672, - 'gas_opex': 1253.3333333333333, - 'oil_opex': 1243.3333333333333, - 'water_opex': 0, - 'other_utility': 111508.57259790279, - 'non_utility_expense': 6611.5370184677795, - 'net_non_energy_opex': 118120.10961637057, - 'total_opex': 122403.9109088451, - 'noi': 75942.1996451883 - }, - 2030: { - 'year': 2030, - 'revenue': 209075.15812876914, - 'utility_expense': 121860.01856938066, - 'energy_opex': 4319.662554843346, - 'electricity_opex': 1822.9958881766795, - 'gas_opex': 1253.3333333333333, - 'oil_opex': 1243.3333333333333, - 'water_opex': 0, - 'other_utility': 117540.3560145373, - 'non_utility_expense': 6969.171937625638, - 'net_non_energy_opex': 124509.52795216294, - 'total_opex': 128829.1905070063, - 'noi': 80245.96762176284 - }, - 2031: { - 'year': 2031, - 'revenue': 220384.56728225935, - 'utility_expense': 128254.04609337838, - 'energy_opex': 4355.63209570858, - 'electricity_opex': 1858.9654290419135, - 'gas_opex': 1253.3333333333333, - 'oil_opex': 1243.3333333333333, - 'water_opex': 0, - 'other_utility': 123898.41399766979, - 'non_utility_expense': 7346.152242741978, - 'net_non_energy_opex': 131244.56624041178, - 'total_opex': 135600.19833612035, - 'noi': 84784.368946139 - }, - 2032: { - 'year': 2032, - 'revenue': 232305.73125418797, - 'utility_expense': 134992.39514124338, - 'energy_opex': 4391.999569535249, - 'electricity_opex': 1895.3329028685823, - 'gas_opex': 1253.3333333333333, - 'oil_opex': 1243.3333333333333, - 'water_opex': 0, - 'other_utility': 130600.39557170814, - 'non_utility_expense': 7743.524375139598, - 'net_non_energy_opex': 138343.91994684775, - 'total_opex': 142735.919516383, - 'noi': 89569.81173780496 - }, - 2033: { - 'year': 2033, - 'revenue': 244871.74142473264, - 'utility_expense': 142094.09314422478, - 'energy_opex': 4429.188702369451, - 'electricity_opex': 1932.5220357027845, - 'gas_opex': 1253.3333333333333, - 'oil_opex': 1243.3333333333333, - 'water_opex': 0, - 'other_utility': 137664.90444185532, - 'non_utility_expense': 8162.3913808244215, - 'net_non_energy_opex': 145827.29582267973, - 'total_opex': 150256.4845250492, - 'noi': 94615.25689968345 - }, - 2034: { - 'year': 2034, - 'revenue': 258117.47917131998, - 'utility_expense': 149578.9225071101, - 'energy_opex': 4467.371871878835, - 'electricity_opex': 1970.705205212169, - 'gas_opex': 1253.3333333333333, - 'oil_opex': 1243.3333333333333, - 'water_opex': 0, - 'other_utility': 145111.55063523128, - 'non_utility_expense': 8603.915972377332, - 'net_non_energy_opex': 153715.4666076086, - 'total_opex': 158182.83847948743, - 'noi': 99934.64069183255 - }, - 2035: { - 'year': 2035, - 'revenue': 272079.71269414737, - 'utility_expense': 157467.601487427, - 'energy_opex': 4506.596552032184, - 'electricity_opex': 2009.9298853655182, - 'gas_opex': 1253.3333333333333, - 'oil_opex': 1243.3333333333333, - 'water_opex': 0, - 'other_utility': 152961.0049353948, - 'non_utility_expense': 9069.323756471578, - 'net_non_energy_opex': 162030.32869186637, - 'total_opex': 166536.92524389856, - 'noi': 105542.78745024881 - }, - 2036: { - 'year': 2036, - 'revenue': 286797.19907924446, - 'utility_expense': 165781.9237598475, - 'energy_opex': 4546.867498479411, - 'electricity_opex': 2050.2008318127446, - 'gas_opex': 1253.3333333333333, - 'oil_opex': 1243.3333333333333, - 'water_opex': 0, - 'other_utility': 161235.0562613681, - 'non_utility_expense': 9559.906635974816, - 'net_non_energy_opex': 170794.96289734292, - 'total_opex': 175341.83039582233, - 'noi': 111455.36868342213 - } -} +# prior_income_statement_cagr = { +# 2014: { +# 'year': 2014, +# 'revenue': 90000, +# 'utility_expense': 55000, +# 'energy_opex': 2589.41283438579, +# 'electricity_opex': 1346.079501052457, +# 'gas_opex': 0, +# 'oil_opex': 1243.3333333333333, +# 'water_opex': 0, +# 'other_utility': 52410.58716561421, +# 'non_utility_expense': 3500, +# 'net_non_energy_opex': 55910.58716561421, +# 'total_opex': 58500.0, +# 'noi': 31500.0 +# }, +# 2015: { +# 'year': 2015, +# 'revenue': 95000, +# 'utility_expense': 55000, +# 'energy_opex': 3387.4370596899435, +# 'electricity_opex': 1357.4370596899435, +# 'gas_opex': 1020, +# 'oil_opex': 1010, +# 'water_opex': 0, +# 'other_utility': 51612.562940310054, +# 'non_utility_expense': 3000, +# 'net_non_energy_opex': 54612.562940310054, +# 'total_opex': 58000.0, +# 'noi': 37000.0 +# }, +# 2016: { +# 'year': 2016, +# 'revenue': 100000, +# 'utility_expense': 60000, +# 'energy_opex': 3798.4645719731475, +# 'electricity_opex': 1368.4645719731475, +# 'gas_opex': 1220, +# 'oil_opex': 1210, +# 'water_opex': 0, +# 'other_utility': 56201.53542802685, +# 'non_utility_expense': 3000, +# 'net_non_energy_opex': 59201.53542802685, +# 'total_opex': 63000.0, +# 'noi': 37000.0 +# }, +# 2017: { +# 'year': 2017, +# 'revenue': 105409.25533894598, +# 'utility_expense': 63685.47076980913, +# 'energy_opex': 4425.243439807112, +# 'electricity_opex': 1395.2434398071116, +# 'gas_opex': 1520, +# 'oil_opex': 1510, +# 'water_opex': 0, +# 'other_utility': 59260.22733000202, +# 'non_utility_expense': 3513.6418446315324, +# 'net_non_energy_opex': 62773.869174633546, +# 'total_opex': 67199.11261444066, +# 'noi': 38210.14272450532 +# }, +# 2018: { +# 'year': 2018, +# 'revenue': 111111.11111111112, +# 'utility_expense': 66392.37014575081, +# 'energy_opex': 3926.605805029146, +# 'electricity_opex': 1429.9391383624793, +# 'gas_opex': 1253.3333333333333, +# 'oil_opex': 1243.3333333333333, +# 'water_opex': 0, +# 'other_utility': 62465.764340721675, +# 'non_utility_expense': 3703.703703703704, +# 'net_non_energy_opex': 66169.46804442538, +# 'total_opex': 70096.07384945452, +# 'noi': 41015.0372616566 +# }, +# 2019: { +# 'year': 2019, +# 'revenue': 117121.3948210511, +# 'utility_expense': 69806.48568426503, +# 'energy_opex': 3961.788650929455, +# 'electricity_opex': 1465.1219842627888, +# 'gas_opex': 1253.3333333333333, +# 'oil_opex': 1243.3333333333333, +# 'water_opex': 0, +# 'other_utility': 65844.69703333559, +# 'non_utility_expense': 3904.0464940350366, +# 'net_non_energy_opex': 69748.74352737062, +# 'total_opex': 73710.53217830008, +# 'noi': 43410.86264275102 +# }, +# 2020: { +# 'year': 2020, +# 'revenue': 123456.79012345681, +# 'utility_expense': 73402.51446668015, +# 'energy_opex': 3996.1096436560692, +# 'electricity_opex': 1499.442976989403, +# 'gas_opex': 1253.3333333333333, +# 'oil_opex': 1243.3333333333333, +# 'water_opex': 0, +# 'other_utility': 69406.40482302409, +# 'non_utility_expense': 4115.22633744856, +# 'net_non_energy_opex': 73521.63116047265, +# 'total_opex': 77517.74080412873, +# 'noi': 45939.049319328085 +# }, +# 2021: { +# 'year': 2021, +# 'revenue': 130134.88313450124, +# 'utility_expense': 77188.98559899243, +# 'energy_opex': 4028.211117508439, +# 'electricity_opex': 1531.5444508417731, +# 'gas_opex': 1253.3333333333333, +# 'oil_opex': 1243.3333333333333, +# 'water_opex': 0, +# 'other_utility': 73160.77448148398, +# 'non_utility_expense': 4337.829437816708, +# 'net_non_energy_opex': 77498.60391930069, +# 'total_opex': 81526.81503680913, +# 'noi': 48608.068097692114 +# }, +# 2022: { +# 'year': 2022, +# 'revenue': 137174.21124828537, +# 'utility_expense': 81175.51065176747, +# 'energy_opex': 4057.283070629577, +# 'electricity_opex': 1560.6164039629107, +# 'gas_opex': 1253.3333333333333, +# 'oil_opex': 1243.3333333333333, +# 'water_opex': 0, +# 'other_utility': 77118.2275811379, +# 'non_utility_expense': 4572.4737082761785, +# 'net_non_energy_opex': 81690.70128941408, +# 'total_opex': 85747.98436004366, +# 'noi': 51426.22688824171 +# }, +# 2023: { +# 'year': 2023, +# 'revenue': 144594.3145938903, +# 'utility_expense': 85375.52089355137, +# 'energy_opex': 4085.771469680246, +# 'electricity_opex': 1589.1048030135796, +# 'gas_opex': 1253.3333333333333, +# 'oil_opex': 1243.3333333333333, +# 'water_opex': 0, +# 'other_utility': 81289.74942387112, +# 'non_utility_expense': 4819.81048646301, +# 'net_non_energy_opex': 86109.55991033414, +# 'total_opex': 90195.33138001438, +# 'noi': 54398.98321387592 +# }, +# 2024: { +# 'year': 2024, +# 'revenue': 152415.79027587266, +# 'utility_expense': 89801.7755864785, +# 'energy_opex': 4114.856051880816, +# 'electricity_opex': 1618.1893852141502, +# 'gas_opex': 1253.3333333333333, +# 'oil_opex': 1243.3333333333333, +# 'water_opex': 0, +# 'other_utility': 85686.91953459768, +# 'non_utility_expense': 5080.526342529089, +# 'net_non_energy_opex': 90767.44587712677, +# 'total_opex': 94882.30192900759, +# 'noi': 57533.488346865066 +# }, +# 2025: { +# 'year': 2025, +# 'revenue': 160660.349548767, +# 'utility_expense': 94466.87160244759, +# 'energy_opex': 4144.927798146355, +# 'electricity_opex': 1648.2611314796882, +# 'gas_opex': 1253.3333333333333, +# 'oil_opex': 1243.3333333333333, +# 'water_opex': 0, +# 'other_utility': 90321.94380430123, +# 'non_utility_expense': 5355.3449849589, +# 'net_non_energy_opex': 95677.28878926013, +# 'total_opex': 99822.21658740648, +# 'noi': 60838.13296136052 +# }, +# 2026: { +# 'year': 2026, +# 'revenue': 169350.87808430297, +# 'utility_expense': 99384.92941996356, +# 'energy_opex': 4177.241048188369, +# 'electricity_opex': 1680.5743815217027, +# 'gas_opex': 1253.3333333333333, +# 'oil_opex': 1243.3333333333333, +# 'water_opex': 0, +# 'other_utility': 95207.68837177519, +# 'non_utility_expense': 5645.029269476766, +# 'net_non_energy_opex': 100852.71764125196, +# 'total_opex': 105029.95868944033, +# 'noi': 64320.919394862634 +# }, +# 2027: { +# 'year': 2027, +# 'revenue': 178511.49949863003, +# 'utility_expense': 104569.84110763346, +# 'energy_opex': 4212.125769520951, +# 'electricity_opex': 1715.4591028542839, +# 'gas_opex': 1253.3333333333333, +# 'oil_opex': 1243.3333333333333, +# 'water_opex': 0, +# 'other_utility': 100357.71533811251, +# 'non_utility_expense': 5950.383316621001, +# 'net_non_energy_opex': 106308.0986547335, +# 'total_opex': 110520.22442425445, +# 'noi': 67991.27507437558 +# }, +# 2028: { +# 'year': 2028, +# 'revenue': 188167.6423158922, +# 'utility_expense': 110034.25881989759, +# 'energy_opex': 4247.938406814023, +# 'electricity_opex': 1751.2717401473571, +# 'gas_opex': 1253.3333333333333, +# 'oil_opex': 1243.3333333333333, +# 'water_opex': 0, +# 'other_utility': 105786.32041308357, +# 'non_utility_expense': 6272.254743863074, +# 'net_non_energy_opex': 112058.57515694664, +# 'total_opex': 116306.51356376066, +# 'noi': 71861.12875213155 +# }, +# 2029: { +# 'year': 2029, +# 'revenue': 198346.1105540334, +# 'utility_expense': 115792.37389037732, +# 'energy_opex': 4283.8012924745335, +# 'electricity_opex': 1787.1346258078672, +# 'gas_opex': 1253.3333333333333, +# 'oil_opex': 1243.3333333333333, +# 'water_opex': 0, +# 'other_utility': 111508.57259790279, +# 'non_utility_expense': 6611.5370184677795, +# 'net_non_energy_opex': 118120.10961637057, +# 'total_opex': 122403.9109088451, +# 'noi': 75942.1996451883 +# }, +# 2030: { +# 'year': 2030, +# 'revenue': 209075.15812876914, +# 'utility_expense': 121860.01856938066, +# 'energy_opex': 4319.662554843346, +# 'electricity_opex': 1822.9958881766795, +# 'gas_opex': 1253.3333333333333, +# 'oil_opex': 1243.3333333333333, +# 'water_opex': 0, +# 'other_utility': 117540.3560145373, +# 'non_utility_expense': 6969.171937625638, +# 'net_non_energy_opex': 124509.52795216294, +# 'total_opex': 128829.1905070063, +# 'noi': 80245.96762176284 +# }, +# 2031: { +# 'year': 2031, +# 'revenue': 220384.56728225935, +# 'utility_expense': 128254.04609337838, +# 'energy_opex': 4355.63209570858, +# 'electricity_opex': 1858.9654290419135, +# 'gas_opex': 1253.3333333333333, +# 'oil_opex': 1243.3333333333333, +# 'water_opex': 0, +# 'other_utility': 123898.41399766979, +# 'non_utility_expense': 7346.152242741978, +# 'net_non_energy_opex': 131244.56624041178, +# 'total_opex': 135600.19833612035, +# 'noi': 84784.368946139 +# }, +# 2032: { +# 'year': 2032, +# 'revenue': 232305.73125418797, +# 'utility_expense': 134992.39514124338, +# 'energy_opex': 4391.999569535249, +# 'electricity_opex': 1895.3329028685823, +# 'gas_opex': 1253.3333333333333, +# 'oil_opex': 1243.3333333333333, +# 'water_opex': 0, +# 'other_utility': 130600.39557170814, +# 'non_utility_expense': 7743.524375139598, +# 'net_non_energy_opex': 138343.91994684775, +# 'total_opex': 142735.919516383, +# 'noi': 89569.81173780496 +# }, +# 2033: { +# 'year': 2033, +# 'revenue': 244871.74142473264, +# 'utility_expense': 142094.09314422478, +# 'energy_opex': 4429.188702369451, +# 'electricity_opex': 1932.5220357027845, +# 'gas_opex': 1253.3333333333333, +# 'oil_opex': 1243.3333333333333, +# 'water_opex': 0, +# 'other_utility': 137664.90444185532, +# 'non_utility_expense': 8162.3913808244215, +# 'net_non_energy_opex': 145827.29582267973, +# 'total_opex': 150256.4845250492, +# 'noi': 94615.25689968345 +# }, +# 2034: { +# 'year': 2034, +# 'revenue': 258117.47917131998, +# 'utility_expense': 149578.9225071101, +# 'energy_opex': 4467.371871878835, +# 'electricity_opex': 1970.705205212169, +# 'gas_opex': 1253.3333333333333, +# 'oil_opex': 1243.3333333333333, +# 'water_opex': 0, +# 'other_utility': 145111.55063523128, +# 'non_utility_expense': 8603.915972377332, +# 'net_non_energy_opex': 153715.4666076086, +# 'total_opex': 158182.83847948743, +# 'noi': 99934.64069183255 +# }, +# 2035: { +# 'year': 2035, +# 'revenue': 272079.71269414737, +# 'utility_expense': 157467.601487427, +# 'energy_opex': 4506.596552032184, +# 'electricity_opex': 2009.9298853655182, +# 'gas_opex': 1253.3333333333333, +# 'oil_opex': 1243.3333333333333, +# 'water_opex': 0, +# 'other_utility': 152961.0049353948, +# 'non_utility_expense': 9069.323756471578, +# 'net_non_energy_opex': 162030.32869186637, +# 'total_opex': 166536.92524389856, +# 'noi': 105542.78745024881 +# }, +# 2036: { +# 'year': 2036, +# 'revenue': 286797.19907924446, +# 'utility_expense': 165781.9237598475, +# 'energy_opex': 4546.867498479411, +# 'electricity_opex': 2050.2008318127446, +# 'gas_opex': 1253.3333333333333, +# 'oil_opex': 1243.3333333333333, +# 'water_opex': 0, +# 'other_utility': 161235.0562613681, +# 'non_utility_expense': 9559.906635974816, +# 'net_non_energy_opex': 170794.96289734292, +# 'total_opex': 175341.83039582233, +# 'noi': 111455.36868342213 +# } +# } -next_year_income = { - 'year': 2017, - 'revenue': 105409.25533894598, - 'utility_expense': 63685.47076980913, - 'energy_opex': 4425.243439807112, - 'electricity_opex': 1395.2434398071116, - 'gas_opex': 1520, - 'oil_opex': 1510, - 'water_opex': 0, - 'other_utility': 59260.22733000202, - 'non_utility_expense': 3513.6418446315324, - 'net_non_energy_opex': 62773.869174633546, - 'total_opex': 67199.11261444066, - 'noi': 38210.14272450532 -} +# next_year_income = { +# 'year': 2017, +# 'revenue': 105409.25533894598, +# 'utility_expense': 63685.47076980913, +# 'energy_opex': 4425.243439807112, +# 'electricity_opex': 1395.2434398071116, +# 'gas_opex': 1520, +# 'oil_opex': 1510, +# 'water_opex': 0, +# 'other_utility': 59260.22733000202, +# 'non_utility_expense': 3513.6418446315324, +# 'net_non_energy_opex': 62773.869174633546, +# 'total_opex': 67199.11261444066, +# 'noi': 38210.14272450532 +# } -average_income = { - 'year': None, - 'revenue': 95000.0, - 'utility_expense': 56666.666666666657, - 'energy_opex': 3258.4381553496269, - 'electricity_opex': 1357.327044238516, - 'gas_opex': 746.66666666666663, - 'oil_opex': 1154.4444444444443, - 'water_opex': 0.0, - 'other_utility': 53408.228511317029, - 'non_utility_expense': 3166.6666666666665, - 'net_non_energy_opex': 56574.895177983693, - 'total_opex': 59833.333333333321, - 'noi': 35166.666666666679 -} +# average_income = { +# 'year': None, +# 'revenue': 95000.0, +# 'utility_expense': 56666.666666666657, +# 'energy_opex': 3258.4381553496269, +# 'electricity_opex': 1357.327044238516, +# 'gas_opex': 746.66666666666663, +# 'oil_opex': 1154.4444444444443, +# 'water_opex': 0.0, +# 'other_utility': 53408.228511317029, +# 'non_utility_expense': 3166.6666666666665, +# 'net_non_energy_opex': 56574.895177983693, +# 'total_opex': 59833.333333333321, +# 'noi': 35166.666666666679 +# } -historical_cagr = 0.05409255338945984 +# historical_cagr = 0.05409255338945984 + +# post_annual_bill_table = { +# 'electricity': { +# 2012: 1302.3894189123205, +# 2013: 1325.5398892097569, +# 2014: 1346.0795010524571, +# 2015: 1357.4370596899435, +# 2016: 1368.4645719731475, +# 2017: 1143.5987943889527, +# 2018: 1072.4543537718594, +# 2019: 1098.8414881970916, +# 2020: 1124.5822327420522, +# 2021: 1148.6583381313299, +# 2022: 1170.4623029721829, +# 2023: 1191.8286022601849, +# 2024: 1213.6420389106127, +# 2025: 1236.195848609766, +# 2026: 1260.4307861412767, +# 2027: 1286.5943271407125, +# 2028: 1313.453805110518, +# 2029: 1340.3509693559004, +# 2030: 1367.2469161325098, +# 2031: 1394.224071781435, +# 2032: 1421.4996771514368, +# 2033: 1449.3915267770883, +# 2034: 1478.0289039091267, +# 2035: 1507.4474140241387, +# 2036: 1537.6506238595582 +# }, +# 'gas': { +# 2012: 1253.3333333333333, +# 2013: 1253.3333333333333, +# 2014: 0, +# 2015: 1020, +# 2016: 1220, +# 2017: 1406.0, +# 2018: 1128.0, +# 2019: 1128.0, +# 2020: 1128.0, +# 2021: 1128.0, +# 2022: 1128.0, +# 2023: 1128.0, +# 2024: 1128.0, +# 2025: 1128.0, +# 2026: 1128.0, +# 2027: 1128.0, +# 2028: 1128.0, +# 2029: 1128.0, +# 2030: 1128.0, +# 2031: 1128.0, +# 2032: 1128.0, +# 2033: 1128.0, +# 2034: 1128.0, +# 2035: 1128.0, +# 2036: 1128.0 +# }, +# 'oil': { +# 2012: 1243.3333333333333, +# 2013: 1243.3333333333333, +# 2014: 1243.3333333333333, +# 2015: 1010, +# 2016: 1210, +# 2017: 603.9999999999999, +# 2018: 248.6666666666666, +# 2019: 248.6666666666666, +# 2020: 248.6666666666666, +# 2021: 248.6666666666666, +# 2022: 248.6666666666666, +# 2023: 248.6666666666666, +# 2024: 248.6666666666666, +# 2025: 248.6666666666666, +# 2026: 248.6666666666666, +# 2027: 248.6666666666666, +# 2028: 248.6666666666666, +# 2029: 248.6666666666666, +# 2030: 248.6666666666666, +# 2031: 248.6666666666666, +# 2032: 248.6666666666666, +# 2033: 248.6666666666666, +# 2034: 248.6666666666666, +# 2035: 248.6666666666666, +# 2036: 248.6666666666666 +# }, +# 'water': { +# 2012: 0, +# 2013: 0, +# 2014: 0, +# 2015: 0, +# 2016: 0, +# 2017: 0.0, +# 2018: 0.0, +# 2019: 0.0, +# 2020: 0.0, +# 2021: 0.0, +# 2022: 0.0, +# 2023: 0.0, +# 2024: 0.0, +# 2025: 0.0, +# 2026: 0.0, +# 2027: 0.0, +# 2028: 0.0, +# 2029: 0.0, +# 2030: 0.0, +# 2031: 0.0, +# 2032: 0.0, +# 2033: 0.0, +# 2034: 0.0, +# 2035: 0.0, +# 2036: 0.0 +# } +# } -post_annual_bill_table = { - 'electricity': { - 2012: 1302.3894189123205, - 2013: 1325.5398892097569, - 2014: 1346.0795010524571, - 2015: 1357.4370596899435, - 2016: 1368.4645719731475, - 2017: 1143.5987943889527, - 2018: 1072.4543537718594, - 2019: 1098.8414881970916, - 2020: 1124.5822327420522, - 2021: 1148.6583381313299, - 2022: 1170.4623029721829, - 2023: 1191.8286022601849, - 2024: 1213.6420389106127, - 2025: 1236.195848609766, - 2026: 1260.4307861412767, - 2027: 1286.5943271407125, - 2028: 1313.453805110518, - 2029: 1340.3509693559004, - 2030: 1367.2469161325098, - 2031: 1394.224071781435, - 2032: 1421.4996771514368, - 2033: 1449.3915267770883, - 2034: 1478.0289039091267, - 2035: 1507.4474140241387, - 2036: 1537.6506238595582 - }, - 'gas': { - 2012: 1253.3333333333333, - 2013: 1253.3333333333333, - 2014: 0, - 2015: 1020, - 2016: 1220, - 2017: 1406.0, - 2018: 1128.0, - 2019: 1128.0, - 2020: 1128.0, - 2021: 1128.0, - 2022: 1128.0, - 2023: 1128.0, - 2024: 1128.0, - 2025: 1128.0, - 2026: 1128.0, - 2027: 1128.0, - 2028: 1128.0, - 2029: 1128.0, - 2030: 1128.0, - 2031: 1128.0, - 2032: 1128.0, - 2033: 1128.0, - 2034: 1128.0, - 2035: 1128.0, - 2036: 1128.0 - }, - 'oil': { - 2012: 1243.3333333333333, - 2013: 1243.3333333333333, - 2014: 1243.3333333333333, - 2015: 1010, - 2016: 1210, - 2017: 603.9999999999999, - 2018: 248.6666666666666, - 2019: 248.6666666666666, - 2020: 248.6666666666666, - 2021: 248.6666666666666, - 2022: 248.6666666666666, - 2023: 248.6666666666666, - 2024: 248.6666666666666, - 2025: 248.6666666666666, - 2026: 248.6666666666666, - 2027: 248.6666666666666, - 2028: 248.6666666666666, - 2029: 248.6666666666666, - 2030: 248.6666666666666, - 2031: 248.6666666666666, - 2032: 248.6666666666666, - 2033: 248.6666666666666, - 2034: 248.6666666666666, - 2035: 248.6666666666666, - 2036: 248.6666666666666 - }, - 'water': { - 2012: 0, - 2013: 0, - 2014: 0, - 2015: 0, - 2016: 0, - 2017: 0.0, - 2018: 0.0, - 2019: 0.0, - 2020: 0.0, - 2021: 0.0, - 2022: 0.0, - 2023: 0.0, - 2024: 0.0, - 2025: 0.0, - 2026: 0.0, - 2027: 0.0, - 2028: 0.0, - 2029: 0.0, - 2030: 0.0, - 2031: 0.0, - 2032: 0.0, - 2033: 0.0, - 2034: 0.0, - 2035: 0.0, - 2036: 0.0 - } -} -- GitLab From a1e374046f3336bd473e04587d7cec0cf3f7bcdb Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Fri, 19 May 2017 15:05:15 -0400 Subject: [PATCH 06/37] Create growth_rate_flag validation func, test file --- bpfin/financials/financial_income.py | 18 +- bpfin/lib/back_end_call.py | 21 +- bpfin/lib/other.py | 3 + .../test_financials/test_financial_income.py | 10 + .../test_back_end_call.py | 30 +- bpfin/tests/testdata/feature_data.py | 897 ++++++++---------- data_generation.py | 1 + 7 files changed, 431 insertions(+), 549 deletions(-) create mode 100644 bpfin/tests/test_financials/test_financial_income.py rename bpfin/tests/{test_utilbills => test_lib}/test_back_end_call.py (50%) create mode 100644 data_generation.py diff --git a/bpfin/financials/financial_income.py b/bpfin/financials/financial_income.py index 6f7cc18..8c1d8b5 100644 --- a/bpfin/financials/financial_income.py +++ b/bpfin/financials/financial_income.py @@ -2,6 +2,7 @@ import copy from bpfin.lib import other as lib from bpfin.utilbills.bill_lib import form_bill_year from numpy import mean +from bpfin.lib.other import UTILITY_TYPE_LIST class Income_Statement(): @@ -277,7 +278,8 @@ class Income_Statement_Table(): Note: project() overwrites existing projection data """ - # characters = copy.deepcopy(self.characters) + if not validate_growth_rate_flag(growth_rate_flag): + raise ValueError('growth_rate input is not valid') proforma_year = form_bill_year(self.analysis_date['proforma_start'], self.analysis_date['proforma_duration']) current_table = copy.deepcopy(self.hist_table) @@ -439,3 +441,17 @@ class Income_Statement_Table(): total_energy_dict[ current_income_statement.year] = current_income_statement.energy_opex return total_energy_dict + + +def validate_growth_rate_flag(growth_rate_flag): + """ + Validate growth_rate_flag + the input is either -2, -1 or >= 0 + """ + if growth_rate_flag >= 0: + return True + if growth_rate_flag == -1: + return True + if growth_rate_flag == -2: + return True + return False diff --git a/bpfin/lib/back_end_call.py b/bpfin/lib/back_end_call.py index 684fcda..5a87e54 100644 --- a/bpfin/lib/back_end_call.py +++ b/bpfin/lib/back_end_call.py @@ -1,3 +1,4 @@ +from bpfin.lib.other import UTILITY_TYPE_LIST from bpfin.utilbills.bill import Bill # from bpfin.financials.financial_lib import Income_Statement_Table from bpfin.financials.financial_income import Income_Statement_Table @@ -5,9 +6,6 @@ from bpfin.tests.testdata import feature_data as db import pprint -UTILITY_TYPE_LIST = ['electricity', 'gas', 'oil', 'water'] - - # Bill Overview Monthly Input def monthly_bill(raw_bill_table, analysis_date): """ @@ -166,24 +164,17 @@ def prior_income_statement(raw_income_input, raw_bill_table, raw_annual_bill_tab # print(db.raw_bill_table) # print('\nmonthly_bill =', monthly_bill(db.raw_bill_table, db.analysis_date)) # print('\nannual_bill =', annual_bill(db.raw_bill_table, db.raw_annual_bill_table, db.analysis_date)) -# print('\nprior_income_statement =', prior_income_statement( +# prior_income_statement_result = prior_income_statement( # db.raw_income_input, # db.raw_bill_table, # db.raw_annual_bill_table, # db.analysis_date, -# -2.0)) - -prior_income_statement_result = prior_income_statement( - db.raw_income_input, - db.raw_bill_table, - db.raw_annual_bill_table, - db.analysis_date, - -2.0) +# -2.0) -pp = pprint.PrettyPrinter(width=120, indent=4, compact=True) -pp.pprint(prior_income_statement_result) +# pp = pprint.PrettyPrinter(width=120, indent=4, compact=True) +# pp.pprint(prior_income_statement_result) -# writein = str(result) +# writein = str(prior_income_statement_result) # f = open('data_generation.py', 'w') # f.write(writein) # f.close() diff --git a/bpfin/lib/other.py b/bpfin/lib/other.py index d08cf0f..8db14de 100644 --- a/bpfin/lib/other.py +++ b/bpfin/lib/other.py @@ -4,6 +4,9 @@ import numpy as np from scipy.optimize import linprog +UTILITY_TYPE_LIST = ['electricity', 'gas', 'oil', 'water'] + + def add_year_dictionary(dict_1, dict_2): summed_dict = {x: dict_1.get(x, 0) + dict_2.get(x, 0) for x in set(dict_1).union(dict_2)} return summed_dict diff --git a/bpfin/tests/test_financials/test_financial_income.py b/bpfin/tests/test_financials/test_financial_income.py new file mode 100644 index 0000000..b43e819 --- /dev/null +++ b/bpfin/tests/test_financials/test_financial_income.py @@ -0,0 +1,10 @@ +from bpfin.lib.other import UTILITY_TYPE_LIST +from bpfin.tests.testdata import feature_data as db +from bpfin.financials.financial_income import validate_growth_rate_flag + + +def test_validate_growth(): + input_list = [0.02, 0.01, 0, -0.5, -1, -1.5, -2, -2.5, -3] + output_list = [True, True, True, False, True, False, True, False, False] + for (growth, validation) in zip(input_list, output_list): + assert validation == validate_growth_rate_flag(growth) diff --git a/bpfin/tests/test_utilbills/test_back_end_call.py b/bpfin/tests/test_lib/test_back_end_call.py similarity index 50% rename from bpfin/tests/test_utilbills/test_back_end_call.py rename to bpfin/tests/test_lib/test_back_end_call.py index c281259..49063a5 100644 --- a/bpfin/tests/test_utilbills/test_back_end_call.py +++ b/bpfin/tests/test_lib/test_back_end_call.py @@ -19,18 +19,18 @@ def test_annual_bill(): assert output_dict == result_dict -# def test_prior_income_statement(): -# output_income_statement = db.prior_income_statement_cagr -# output_next_year_income = db.next_year_income -# output_average_income = db.average_income -# output_historical_cagr = db.historical_cagr -# prior_income, next_year_income, average_income, historical_cagr = prior_income_statement( -# db.raw_income_input, -# db.raw_bill_table, -# db.raw_annual_bill_table, -# db.analysis_date, -# -2.0) -# assert output_income_statement == prior_income -# assert output_next_year_income == next_year_income -# assert output_average_income == average_income -# assert output_historical_cagr == historical_cagr +def test_prior_income_statement(): + output_income_statement = db.prior_income_statement_cagr + output_next_year_income = db.next_year_income + output_average_income = db.average_income + output_historical_cagr = db.historical_cagr + prior_income, next_year_income, average_income, historical_cagr = prior_income_statement( + db.raw_income_input, + db.raw_bill_table, + db.raw_annual_bill_table, + db.analysis_date, + -2.0) + assert output_income_statement == prior_income + assert output_next_year_income == next_year_income + assert output_average_income == average_income + assert output_historical_cagr == historical_cagr diff --git a/bpfin/tests/testdata/feature_data.py b/bpfin/tests/testdata/feature_data.py index dbd96c1..1263521 100644 --- a/bpfin/tests/testdata/feature_data.py +++ b/bpfin/tests/testdata/feature_data.py @@ -54,36 +54,6 @@ full_saving_dict = { } # dict of engineering analysis, {'date_from': [], 'date_to': [], 'heating': [], 'cooling': [], 'other': []} - -# e_raw_bill = { -# 'date_from': [ -# date(2015, 1, 28), date(2015, 2, 27), date(2015, 3, 30), date(2015, 4, 28), -# date(2015, 5, 28), date(2015, 6, 26), date(2015, 7, 28), date(2015, 8, 26), -# date(2015, 9, 25), date(2015, 10, 27), date(2015, 11, 25), date(2015, 12, 29), -# date(2016, 1, 28), date(2016, 2, 29), date(2016, 3, 29), date(2016, 4, 27), -# date(2016, 5, 26), date(2016, 6, 27), date(2016, 7, 27), date(2016, 8, 25), -# date(2016, 9, 26), date(2016, 10, 26), date(2016, 11, 28) -# ], -# 'date_to': [ -# date(2015, 2, 27), date(2015, 3, 30), date(2015, 4, 28), date(2015, 5, 28), -# date(2015, 6, 26), date(2015, 7, 28), date(2015, 8, 26), date(2015, 9, 25), -# date(2015, 10, 27), date(2015, 11, 25), date(2015, 12, 29), date(2016, 1, 28), -# date(2016, 2, 29), date(2016, 3, 29), date(2016, 4, 27), date(2016, 5, 26), -# date(2016, 6, 27), date(2016, 7, 27), date(2016, 8, 25), date(2016, 9, 26), -# date(2016, 10, 26), date(2016, 11, 28), date(2016, 12, 28) -# ], -# 'usage': [ -# 214.66, 189.42, 190.8, 168.92, 189.02, 179.64, 154.95, 162.13, -# 136.16, 144.06, 208.85, 182.55, 98.13, 104.19, 90.05, -# 88.19, 101.05, 87.05, 86.88, 98.17, 89.07, 91.93, 117.88 -# ], -# 'charge': [ -# 172.33, 163.88, 163.49, 196.46, 169.68, 152.56, 126.16, -# 137.14, 136.1, 130.65, 172.37, 145.44, 71.73, 68.12, 63.57, -# 68.28, 71.66, 56.21, 57.25, 63.6, 67.42, 39.62, 56.01 -# ] -# } - raw_elec_bill_demo = {} raw_elec_bill_demo['utility_type'] = 'electricity' raw_elec_bill_demo['date_from'] = [ @@ -302,498 +272,389 @@ prior_annual_bill = { 2033: 20500.0, 2034: 20500.0, 2035: 20500.0, 2036: 20500.0 } } -# prior_annual_bill = { -# 'electricity': { -# 2012: 1302.3894189123205, -# 2013: 1325.5398892097569, -# 2014: 1346.0795010524571, -# 2015: 1357.4370596899435, -# 2016: 1368.4645719731475, -# 2017: 1395.2434398071116, -# 2018: 1429.9391383624793, -# 2019: 1465.1219842627888, -# 2020: 1499.442976989403, -# 2021: 1531.5444508417731, -# 2022: 1560.6164039629107, -# 2023: 1589.1048030135796, -# 2024: 1618.1893852141502, -# 2025: 1648.2611314796882, -# 2026: 1680.5743815217027, -# 2027: 1715.4591028542839, -# 2028: 1751.2717401473571, -# 2029: 1787.1346258078672, -# 2030: 1822.9958881766795, -# 2031: 1858.9654290419135, -# 2032: 1895.3329028685823, -# 2033: 1932.5220357027845, -# 2034: 1970.7052052121689, -# 2035: 2009.9298853655182, -# 2036: 2050.2008318127446 -# }, -# 'gas': { -# 2014: 0, -# 2015: 1020, -# 2016: 1220, -# 2017: 1520, -# 2012: 1253.3333333333333, -# 2013: 1253.3333333333333, -# 2018: 1253.3333333333333, -# 2019: 1253.3333333333333, -# 2020: 1253.3333333333333, -# 2021: 1253.3333333333333, -# 2022: 1253.3333333333333, -# 2023: 1253.3333333333333, -# 2024: 1253.3333333333333, -# 2025: 1253.3333333333333, -# 2026: 1253.3333333333333, -# 2027: 1253.3333333333333, -# 2028: 1253.3333333333333, -# 2029: 1253.3333333333333, -# 2030: 1253.3333333333333, -# 2031: 1253.3333333333333, -# 2032: 1253.3333333333333, -# 2033: 1253.3333333333333, -# 2034: 1253.3333333333333, -# 2035: 1253.3333333333333, -# 2036: 1253.3333333333333 -# }, -# 'oil': { -# 2015: 1010, -# 2016: 1210, -# 2017: 1510, -# 2012: 1243.3333333333333, -# 2013: 1243.3333333333333, -# 2014: 1243.3333333333333, -# 2018: 1243.3333333333333, -# 2019: 1243.3333333333333, -# 2020: 1243.3333333333333, -# 2021: 1243.3333333333333, -# 2022: 1243.3333333333333, -# 2023: 1243.3333333333333, -# 2024: 1243.3333333333333, -# 2025: 1243.3333333333333, -# 2026: 1243.3333333333333, -# 2027: 1243.3333333333333, -# 2028: 1243.3333333333333, -# 2029: 1243.3333333333333, -# 2030: 1243.3333333333333, -# 2031: 1243.3333333333333, -# 2032: 1243.3333333333333, -# 2033: 1243.3333333333333, -# 2034: 1243.3333333333333, -# 2035: 1243.3333333333333, -# 2036: 1243.3333333333333 -# }, -# 'water': { -# 2015: 0, -# 2016: 0, -# 2017: 0, -# 2012: 0, -# 2013: 0, -# 2014: 0, -# 2018: 0, -# 2019: 0, -# 2020: 0, -# 2021: 0, -# 2022: 0, -# 2023: 0, -# 2024: 0, -# 2025: 0, -# 2026: 0, -# 2027: 0, -# 2028: 0, -# 2029: 0, -# 2030: 0, -# 2031: 0, -# 2032: 0, -# 2033: 0, -# 2034: 0, -# 2035: 0, -# 2036: 0 -# } -# } -# prior_income_statement_cagr = { -# 2014: { -# 'year': 2014, -# 'revenue': 90000, -# 'utility_expense': 55000, -# 'energy_opex': 2589.41283438579, -# 'electricity_opex': 1346.079501052457, -# 'gas_opex': 0, -# 'oil_opex': 1243.3333333333333, -# 'water_opex': 0, -# 'other_utility': 52410.58716561421, -# 'non_utility_expense': 3500, -# 'net_non_energy_opex': 55910.58716561421, -# 'total_opex': 58500.0, -# 'noi': 31500.0 -# }, -# 2015: { -# 'year': 2015, -# 'revenue': 95000, -# 'utility_expense': 55000, -# 'energy_opex': 3387.4370596899435, -# 'electricity_opex': 1357.4370596899435, -# 'gas_opex': 1020, -# 'oil_opex': 1010, -# 'water_opex': 0, -# 'other_utility': 51612.562940310054, -# 'non_utility_expense': 3000, -# 'net_non_energy_opex': 54612.562940310054, -# 'total_opex': 58000.0, -# 'noi': 37000.0 -# }, -# 2016: { -# 'year': 2016, -# 'revenue': 100000, -# 'utility_expense': 60000, -# 'energy_opex': 3798.4645719731475, -# 'electricity_opex': 1368.4645719731475, -# 'gas_opex': 1220, -# 'oil_opex': 1210, -# 'water_opex': 0, -# 'other_utility': 56201.53542802685, -# 'non_utility_expense': 3000, -# 'net_non_energy_opex': 59201.53542802685, -# 'total_opex': 63000.0, -# 'noi': 37000.0 -# }, -# 2017: { -# 'year': 2017, -# 'revenue': 105409.25533894598, -# 'utility_expense': 63685.47076980913, -# 'energy_opex': 4425.243439807112, -# 'electricity_opex': 1395.2434398071116, -# 'gas_opex': 1520, -# 'oil_opex': 1510, -# 'water_opex': 0, -# 'other_utility': 59260.22733000202, -# 'non_utility_expense': 3513.6418446315324, -# 'net_non_energy_opex': 62773.869174633546, -# 'total_opex': 67199.11261444066, -# 'noi': 38210.14272450532 -# }, -# 2018: { -# 'year': 2018, -# 'revenue': 111111.11111111112, -# 'utility_expense': 66392.37014575081, -# 'energy_opex': 3926.605805029146, -# 'electricity_opex': 1429.9391383624793, -# 'gas_opex': 1253.3333333333333, -# 'oil_opex': 1243.3333333333333, -# 'water_opex': 0, -# 'other_utility': 62465.764340721675, -# 'non_utility_expense': 3703.703703703704, -# 'net_non_energy_opex': 66169.46804442538, -# 'total_opex': 70096.07384945452, -# 'noi': 41015.0372616566 -# }, -# 2019: { -# 'year': 2019, -# 'revenue': 117121.3948210511, -# 'utility_expense': 69806.48568426503, -# 'energy_opex': 3961.788650929455, -# 'electricity_opex': 1465.1219842627888, -# 'gas_opex': 1253.3333333333333, -# 'oil_opex': 1243.3333333333333, -# 'water_opex': 0, -# 'other_utility': 65844.69703333559, -# 'non_utility_expense': 3904.0464940350366, -# 'net_non_energy_opex': 69748.74352737062, -# 'total_opex': 73710.53217830008, -# 'noi': 43410.86264275102 -# }, -# 2020: { -# 'year': 2020, -# 'revenue': 123456.79012345681, -# 'utility_expense': 73402.51446668015, -# 'energy_opex': 3996.1096436560692, -# 'electricity_opex': 1499.442976989403, -# 'gas_opex': 1253.3333333333333, -# 'oil_opex': 1243.3333333333333, -# 'water_opex': 0, -# 'other_utility': 69406.40482302409, -# 'non_utility_expense': 4115.22633744856, -# 'net_non_energy_opex': 73521.63116047265, -# 'total_opex': 77517.74080412873, -# 'noi': 45939.049319328085 -# }, -# 2021: { -# 'year': 2021, -# 'revenue': 130134.88313450124, -# 'utility_expense': 77188.98559899243, -# 'energy_opex': 4028.211117508439, -# 'electricity_opex': 1531.5444508417731, -# 'gas_opex': 1253.3333333333333, -# 'oil_opex': 1243.3333333333333, -# 'water_opex': 0, -# 'other_utility': 73160.77448148398, -# 'non_utility_expense': 4337.829437816708, -# 'net_non_energy_opex': 77498.60391930069, -# 'total_opex': 81526.81503680913, -# 'noi': 48608.068097692114 -# }, -# 2022: { -# 'year': 2022, -# 'revenue': 137174.21124828537, -# 'utility_expense': 81175.51065176747, -# 'energy_opex': 4057.283070629577, -# 'electricity_opex': 1560.6164039629107, -# 'gas_opex': 1253.3333333333333, -# 'oil_opex': 1243.3333333333333, -# 'water_opex': 0, -# 'other_utility': 77118.2275811379, -# 'non_utility_expense': 4572.4737082761785, -# 'net_non_energy_opex': 81690.70128941408, -# 'total_opex': 85747.98436004366, -# 'noi': 51426.22688824171 -# }, -# 2023: { -# 'year': 2023, -# 'revenue': 144594.3145938903, -# 'utility_expense': 85375.52089355137, -# 'energy_opex': 4085.771469680246, -# 'electricity_opex': 1589.1048030135796, -# 'gas_opex': 1253.3333333333333, -# 'oil_opex': 1243.3333333333333, -# 'water_opex': 0, -# 'other_utility': 81289.74942387112, -# 'non_utility_expense': 4819.81048646301, -# 'net_non_energy_opex': 86109.55991033414, -# 'total_opex': 90195.33138001438, -# 'noi': 54398.98321387592 -# }, -# 2024: { -# 'year': 2024, -# 'revenue': 152415.79027587266, -# 'utility_expense': 89801.7755864785, -# 'energy_opex': 4114.856051880816, -# 'electricity_opex': 1618.1893852141502, -# 'gas_opex': 1253.3333333333333, -# 'oil_opex': 1243.3333333333333, -# 'water_opex': 0, -# 'other_utility': 85686.91953459768, -# 'non_utility_expense': 5080.526342529089, -# 'net_non_energy_opex': 90767.44587712677, -# 'total_opex': 94882.30192900759, -# 'noi': 57533.488346865066 -# }, -# 2025: { -# 'year': 2025, -# 'revenue': 160660.349548767, -# 'utility_expense': 94466.87160244759, -# 'energy_opex': 4144.927798146355, -# 'electricity_opex': 1648.2611314796882, -# 'gas_opex': 1253.3333333333333, -# 'oil_opex': 1243.3333333333333, -# 'water_opex': 0, -# 'other_utility': 90321.94380430123, -# 'non_utility_expense': 5355.3449849589, -# 'net_non_energy_opex': 95677.28878926013, -# 'total_opex': 99822.21658740648, -# 'noi': 60838.13296136052 -# }, -# 2026: { -# 'year': 2026, -# 'revenue': 169350.87808430297, -# 'utility_expense': 99384.92941996356, -# 'energy_opex': 4177.241048188369, -# 'electricity_opex': 1680.5743815217027, -# 'gas_opex': 1253.3333333333333, -# 'oil_opex': 1243.3333333333333, -# 'water_opex': 0, -# 'other_utility': 95207.68837177519, -# 'non_utility_expense': 5645.029269476766, -# 'net_non_energy_opex': 100852.71764125196, -# 'total_opex': 105029.95868944033, -# 'noi': 64320.919394862634 -# }, -# 2027: { -# 'year': 2027, -# 'revenue': 178511.49949863003, -# 'utility_expense': 104569.84110763346, -# 'energy_opex': 4212.125769520951, -# 'electricity_opex': 1715.4591028542839, -# 'gas_opex': 1253.3333333333333, -# 'oil_opex': 1243.3333333333333, -# 'water_opex': 0, -# 'other_utility': 100357.71533811251, -# 'non_utility_expense': 5950.383316621001, -# 'net_non_energy_opex': 106308.0986547335, -# 'total_opex': 110520.22442425445, -# 'noi': 67991.27507437558 -# }, -# 2028: { -# 'year': 2028, -# 'revenue': 188167.6423158922, -# 'utility_expense': 110034.25881989759, -# 'energy_opex': 4247.938406814023, -# 'electricity_opex': 1751.2717401473571, -# 'gas_opex': 1253.3333333333333, -# 'oil_opex': 1243.3333333333333, -# 'water_opex': 0, -# 'other_utility': 105786.32041308357, -# 'non_utility_expense': 6272.254743863074, -# 'net_non_energy_opex': 112058.57515694664, -# 'total_opex': 116306.51356376066, -# 'noi': 71861.12875213155 -# }, -# 2029: { -# 'year': 2029, -# 'revenue': 198346.1105540334, -# 'utility_expense': 115792.37389037732, -# 'energy_opex': 4283.8012924745335, -# 'electricity_opex': 1787.1346258078672, -# 'gas_opex': 1253.3333333333333, -# 'oil_opex': 1243.3333333333333, -# 'water_opex': 0, -# 'other_utility': 111508.57259790279, -# 'non_utility_expense': 6611.5370184677795, -# 'net_non_energy_opex': 118120.10961637057, -# 'total_opex': 122403.9109088451, -# 'noi': 75942.1996451883 -# }, -# 2030: { -# 'year': 2030, -# 'revenue': 209075.15812876914, -# 'utility_expense': 121860.01856938066, -# 'energy_opex': 4319.662554843346, -# 'electricity_opex': 1822.9958881766795, -# 'gas_opex': 1253.3333333333333, -# 'oil_opex': 1243.3333333333333, -# 'water_opex': 0, -# 'other_utility': 117540.3560145373, -# 'non_utility_expense': 6969.171937625638, -# 'net_non_energy_opex': 124509.52795216294, -# 'total_opex': 128829.1905070063, -# 'noi': 80245.96762176284 -# }, -# 2031: { -# 'year': 2031, -# 'revenue': 220384.56728225935, -# 'utility_expense': 128254.04609337838, -# 'energy_opex': 4355.63209570858, -# 'electricity_opex': 1858.9654290419135, -# 'gas_opex': 1253.3333333333333, -# 'oil_opex': 1243.3333333333333, -# 'water_opex': 0, -# 'other_utility': 123898.41399766979, -# 'non_utility_expense': 7346.152242741978, -# 'net_non_energy_opex': 131244.56624041178, -# 'total_opex': 135600.19833612035, -# 'noi': 84784.368946139 -# }, -# 2032: { -# 'year': 2032, -# 'revenue': 232305.73125418797, -# 'utility_expense': 134992.39514124338, -# 'energy_opex': 4391.999569535249, -# 'electricity_opex': 1895.3329028685823, -# 'gas_opex': 1253.3333333333333, -# 'oil_opex': 1243.3333333333333, -# 'water_opex': 0, -# 'other_utility': 130600.39557170814, -# 'non_utility_expense': 7743.524375139598, -# 'net_non_energy_opex': 138343.91994684775, -# 'total_opex': 142735.919516383, -# 'noi': 89569.81173780496 -# }, -# 2033: { -# 'year': 2033, -# 'revenue': 244871.74142473264, -# 'utility_expense': 142094.09314422478, -# 'energy_opex': 4429.188702369451, -# 'electricity_opex': 1932.5220357027845, -# 'gas_opex': 1253.3333333333333, -# 'oil_opex': 1243.3333333333333, -# 'water_opex': 0, -# 'other_utility': 137664.90444185532, -# 'non_utility_expense': 8162.3913808244215, -# 'net_non_energy_opex': 145827.29582267973, -# 'total_opex': 150256.4845250492, -# 'noi': 94615.25689968345 -# }, -# 2034: { -# 'year': 2034, -# 'revenue': 258117.47917131998, -# 'utility_expense': 149578.9225071101, -# 'energy_opex': 4467.371871878835, -# 'electricity_opex': 1970.705205212169, -# 'gas_opex': 1253.3333333333333, -# 'oil_opex': 1243.3333333333333, -# 'water_opex': 0, -# 'other_utility': 145111.55063523128, -# 'non_utility_expense': 8603.915972377332, -# 'net_non_energy_opex': 153715.4666076086, -# 'total_opex': 158182.83847948743, -# 'noi': 99934.64069183255 -# }, -# 2035: { -# 'year': 2035, -# 'revenue': 272079.71269414737, -# 'utility_expense': 157467.601487427, -# 'energy_opex': 4506.596552032184, -# 'electricity_opex': 2009.9298853655182, -# 'gas_opex': 1253.3333333333333, -# 'oil_opex': 1243.3333333333333, -# 'water_opex': 0, -# 'other_utility': 152961.0049353948, -# 'non_utility_expense': 9069.323756471578, -# 'net_non_energy_opex': 162030.32869186637, -# 'total_opex': 166536.92524389856, -# 'noi': 105542.78745024881 -# }, -# 2036: { -# 'year': 2036, -# 'revenue': 286797.19907924446, -# 'utility_expense': 165781.9237598475, -# 'energy_opex': 4546.867498479411, -# 'electricity_opex': 2050.2008318127446, -# 'gas_opex': 1253.3333333333333, -# 'oil_opex': 1243.3333333333333, -# 'water_opex': 0, -# 'other_utility': 161235.0562613681, -# 'non_utility_expense': 9559.906635974816, -# 'net_non_energy_opex': 170794.96289734292, -# 'total_opex': 175341.83039582233, -# 'noi': 111455.36868342213 -# } -# } +prior_income_statement_cagr = { + 2014: { + 'year': 2014, + 'revenue': 200000, + 'utility_expense': 77000, + 'energy_opex': 55660.176408612344, + 'electricity_opex': 819.06930386346062, + 'gas_opex': 4625.0674743716318, + 'oil_opex': 30216.03963037725, + 'water_opex': 20000, + 'other_utility': 21339.823591387656, + 'non_utility_expense': 105000, + 'net_non_energy_opex': 126339.82359138766, + 'total_opex': 182000.0, + 'noi': 18000.0 + }, + 2015: { + 'year': 2015, + 'revenue': 196000, + 'utility_expense': 77400, + 'energy_opex': 56462.176198804002, + 'electricity_opex': 825.90552345154924, + 'gas_opex': 4661.2913287497577, + 'oil_opex': 30474.979346602693, + 'water_opex': 20500, + 'other_utility': 20937.823801195998, + 'non_utility_expense': 104000, + 'net_non_energy_opex': 124937.82380119601, + 'total_opex': 181400.0, + 'noi': 14600.0 + }, + 2016: { + 'year': 2016, + 'revenue': 205000, + 'utility_expense': 78100, + 'energy_opex': 57253.29633563089, + 'electricity_opex': 832.68423357284746, + 'gas_opex': 4701.7495360589701, + 'oil_opex': 30718.862565999072, + 'water_opex': 21000, + 'other_utility': 20846.70366436911, + 'non_utility_expense': 130000, + 'net_non_energy_opex': 150846.70366436912, + 'total_opex': 208100.0, + 'noi': -3100.0 + }, + 2017: { + 'year': 2017, + 'revenue': 207546.681495995, + 'utility_expense': 79261.074976421922, + 'energy_opex': 57461.990810933145, + 'electricity_opex': 849.02230670593224, + 'gas_opex': 4795.4503391884955, + 'oil_opex': 31317.518165038713, + 'water_opex': 20500.0, + 'other_utility': 21799.08416548877, + 'non_utility_expense': 117068.76044449637, + 'net_non_energy_opex': 138867.84460998513, + 'total_opex': 196329.83542091827, + 'noi': 11216.846075076726 + }, + 2018: { + 'year': 2018, + 'revenue': 210124.99999999994, + 'utility_expense': 80450.873180044437, + 'energy_opex': 58380.98255468304, + 'electricity_opex': 870.14337868170207, + 'gas_opex': 4915.0282767633271, + 'oil_opex': 32095.810899238011, + 'water_opex': 20500.0, + 'other_utility': 22069.890625361393, + 'non_utility_expense': 118523.08652246254, + 'net_non_energy_opex': 140592.97714782393, + 'total_opex': 198973.95970250695, + 'noi': 11151.040297492989 + }, + 2019: { + 'year': 2019, + 'revenue': 212735.3485333948, + 'utility_expense': 81657.272114136751, + 'energy_opex': 59313.210844510766, + 'electricity_opex': 891.54208077704823, + 'gas_opex': 5035.5379855566225, + 'oil_opex': 32886.130778177096, + 'water_opex': 20500.0, + 'other_utility': 22344.061269625981, + 'non_utility_expense': 119995.47945560873, + 'net_non_energy_opex': 142339.54072523472, + 'total_opex': 201652.75156974548, + 'noi': 11082.596963649325 + }, + 2020: { + 'year': 2020, + 'revenue': 215378.12499999988, + 'utility_expense': 82844.084329901569, + 'energy_opex': 60222.446438906147, + 'electricity_opex': 912.4254645897646, + 'gas_opex': 5153.4461029776512, + 'oil_opex': 33656.574871338729, + 'water_opex': 20500.0, + 'other_utility': 22621.637890995422, + 'non_utility_expense': 121486.16368552408, + 'net_non_energy_opex': 144107.8015765195, + 'total_opex': 204330.24801542563, + 'noi': 11047.87698457425 + }, + 2021: { + 'year': 2021, + 'revenue': 218053.7322467296, + 'utility_expense': 83975.856179475901, + 'energy_opex': 61073.193378109274, + 'electricity_opex': 931.94007239274924, + 'gas_opex': 5263.0160958060724, + 'oil_opex': 34378.237209910454, + 'water_opex': 20500.0, + 'other_utility': 22902.662801366623, + 'non_utility_expense': 122995.3664419989, + 'net_non_energy_opex': 145898.02924336554, + 'total_opex': 206971.22262147482, + 'noi': 11082.509625254781 + }, + 2022: { + 'year': 2022, + 'revenue': 220762.5781249998, + 'utility_expense': 85030.647337560615, + 'energy_opex': 61843.468499290313, + 'electricity_opex': 949.62365204805212, + 'gas_opex': 5362.6629176416373, + 'oil_opex': 35031.181929600622, + 'water_opex': 20500.0, + 'other_utility': 23187.178838270298, + 'non_utility_expense': 124523.31777766213, + 'net_non_energy_opex': 147710.49661593244, + 'total_opex': 209553.96511522276, + 'noi': 11208.613009777036 + }, + 2023: { + 'year': 2023, + 'revenue': 223505.07555289776, + 'utility_expense': 86073.429092948703, + 'energy_opex': 62598.19972154792, + 'electricity_opex': 966.95721096995919, + 'gas_opex': 5460.5010514877649, + 'oil_opex': 35670.741459090197, + 'water_opex': 20500.0, + 'other_utility': 23475.229371400783, + 'non_utility_expense': 126070.25060304883, + 'net_non_energy_opex': 149545.47997444961, + 'total_opex': 212143.67969599753, + 'noi': 11361.395856900228 + }, + 2024: { + 'year': 2024, + 'revenue': 226281.6425781247, + 'utility_expense': 87135.528503000809, + 'energy_opex': 63368.670193773767, + 'electricity_opex': 984.65685227063227, + 'gas_opex': 5560.5157868837869, + 'oil_opex': 36323.497554619345, + 'water_opex': 20500.0, + 'other_utility': 23766.858309227046, + 'non_utility_expense': 127636.40072210363, + 'net_non_energy_opex': 151403.25903133067, + 'total_opex': 214771.92922510445, + 'noi': 11509.713353020255 + }, + 2025: { + 'year': 2025, + 'revenue': 229092.70244172015, + 'utility_expense': 88227.412086838711, + 'energy_opex': 64165.301981152908, + 'electricity_opex': 1002.9565908187957, + 'gas_opex': 5663.9000896622329, + 'oil_opex': 36998.445300671876, + 'water_opex': 20500.0, + 'other_utility': 24062.110105685795, + 'non_utility_expense': 129222.00686812503, + 'net_non_energy_opex': 153284.11697381083, + 'total_opex': 217449.41895496374, + 'noi': 11643.283486756409 + }, + 2026: { + 'year': 2026, + 'revenue': 231938.6836425778, + 'utility_expense': 89382.192302985874, + 'energy_opex': 65021.162536028154, + 'electricity_opex': 1022.6293693938102, + 'gas_opex': 5775.3403422790016, + 'oil_opex': 37723.192824355341, + 'water_opex': 20500.0, + 'other_utility': 24361.029766957719, + 'non_utility_expense': 130827.3107401562, + 'net_non_energy_opex': 155188.34050711393, + 'total_opex': 220209.50304314209, + 'noi': 11729.180599435698 + }, + 2027: { + 'year': 2027, + 'revenue': 234820.0200027631, + 'utility_expense': 90608.923300079943, + 'energy_opex': 65945.260441752005, + 'electricity_opex': 1043.8599889408579, + 'gas_opex': 5895.3500983195381, + 'oil_opex': 38506.050354491614, + 'water_opex': 20500.0, + 'other_utility': 24663.662858327934, + 'non_utility_expense': 132452.55703982813, + 'net_non_energy_opex': 157116.21989815607, + 'total_opex': 223061.48033990807, + 'noi': 11758.539662855037 + }, + 2028: { + 'year': 2028, + 'revenue': 237737.1507336422, + 'utility_expense': 91864.080349168915, + 'energy_opex': 66894.02483803725, + 'electricity_opex': 1065.650260619291, + 'gas_opex': 6018.354334038997, + 'oil_opex': 39310.02024337896, + 'water_opex': 20500.0, + 'other_utility': 24970.055511131657, + 'non_utility_expense': 134097.9935086601, + 'net_non_energy_opex': 159068.04901979174, + 'total_opex': 225962.07385782897, + 'noi': 11775.076875813218 + }, + 2029: { + 'year': 2029, + 'revenue': 240690.52050283214, + 'utility_expense': 93124.396893137426, + 'energy_opex': 67844.142463351294, + 'electricity_opex': 1087.4697953564814, + 'gas_opex': 6141.4801983648376, + 'oil_opex': 40115.192469629976, + 'water_opex': 20500.0, + 'other_utility': 25280.254429786128, + 'non_utility_expense': 135763.8709658238, + 'net_non_energy_opex': 161044.12539560991, + 'total_opex': 228888.26785896119, + 'noi': 11802.252643870946 + }, + 2030: { + 'year': 2030, + 'revenue': 243680.5795019832, + 'utility_expense': 94388.508463277947, + 'energy_opex': 68794.201564368006, + 'electricity_opex': 1109.2892523473229, + 'gas_opex': 6264.6360349883253, + 'oil_opex': 40920.276277032368, + 'water_opex': 20500.0, + 'other_utility': 25594.306898909941, + 'non_utility_expense': 137450.44334637656, + 'net_non_energy_opex': 163044.7502452865, + 'total_opex': 231838.95180965451, + 'noi': 11841.627692328679 + }, + 2031: { + 'year': 2031, + 'revenue': 246707.78351540287, + 'utility_expense': 95659.392077519587, + 'energy_opex': 69747.131286988821, + 'electricity_opex': 1131.1744618622365, + 'gas_opex': 6388.1588176948035, + 'oil_opex': 41727.798007431789, + 'water_opex': 20500.0, + 'other_utility': 25912.260790530774, + 'non_utility_expense': 139157.96773996935, + 'net_non_energy_opex': 165070.22853050011, + 'total_opex': 234817.35981748893, + 'noi': 11890.423697913939 + }, + 2032: { + 'year': 2032, + 'revenue': 249772.5939895327, + 'utility_expense': 96944.732064533484, + 'energy_opex': 70710.567493150797, + 'electricity_opex': 1153.3039252083101, + 'gas_opex': 6513.1311498178793, + 'oil_opex': 42544.132418124602, + 'water_opex': 20500.0, + 'other_utility': 26234.164571382684, + 'non_utility_expense': 140886.70443003593, + 'net_non_energy_opex': 167120.86900141861, + 'total_opex': 237831.43649456941, + 'noi': 11941.157494963292 + }, + 2033: { + 'year': 2033, + 'revenue': 252875.4781032879, + 'utility_expense': 98255.82451699338, + 'energy_opex': 71695.757206699345, + 'electricity_opex': 1175.9341789481377, + 'gas_opex': 6640.9586307853224, + 'oil_opex': 43378.864396965881, + 'water_opex': 20500.0, + 'other_utility': 26560.067310294038, + 'non_utility_expense': 142636.91693346857, + 'net_non_energy_opex': 169196.98424376262, + 'total_opex': 240892.74145046197, + 'noi': 11982.73665282593 + }, + 2034: { + 'year': 2034, + 'revenue': 256016.90883927097, + 'utility_expense': 99597.294490472937, + 'energy_opex': 72707.2758048057, + 'electricity_opex': 1199.1695873801598, + 'gas_opex': 6772.2131729990733, + 'oil_opex': 44235.89304442647, + 'water_opex': 20500.0, + 'other_utility': 26890.018685667244, + 'non_utility_expense': 144408.8720407868, + 'net_non_energy_opex': 171298.89072645406, + 'total_opex': 244006.16653125978, + 'noi': 12010.742308011191 + }, + 2035: { + 'year': 2035, + 'revenue': 259197.36505587003, + 'utility_expense': 100970.45619606454, + 'energy_opex': 73746.387203013161, + 'electricity_opex': 1223.0386652944458, + 'gas_opex': 6907.0434291160136, + 'oil_opex': 45116.305108602697, + 'water_opex': 20500.0, + 'other_utility': 27224.068993051384, + 'non_utility_expense': 146202.83985680525, + 'net_non_energy_opex': 173426.90884985664, + 'total_opex': 247173.29605286982, + 'noi': 12024.069003000215 + }, + 2036: { + 'year': 2036, + 'revenue': 262417.3315602527, + 'utility_expense': 102375.48550524657, + 'energy_opex': 74813.216352437652, + 'electricity_opex': 1247.5443683668141, + 'gas_opex': 7045.4681428808135, + 'oil_opex': 46020.203841190028, + 'water_opex': 20500.0, + 'other_utility': 27562.269152808924, + 'non_utility_expense': 148019.09384180643, + 'net_non_energy_opex': 175581.36299461537, + 'total_opex': 250394.57934705302, + 'noi': 12022.752213199681 + } +} -# next_year_income = { -# 'year': 2017, -# 'revenue': 105409.25533894598, -# 'utility_expense': 63685.47076980913, -# 'energy_opex': 4425.243439807112, -# 'electricity_opex': 1395.2434398071116, -# 'gas_opex': 1520, -# 'oil_opex': 1510, -# 'water_opex': 0, -# 'other_utility': 59260.22733000202, -# 'non_utility_expense': 3513.6418446315324, -# 'net_non_energy_opex': 62773.869174633546, -# 'total_opex': 67199.11261444066, -# 'noi': 38210.14272450532 -# } +next_year_income = { + 'year': 2017, + 'revenue': 207546.681495995, + 'utility_expense': 79261.074976421922, + 'energy_opex': 57461.990810933145, + 'electricity_opex': 849.02230670593224, + 'gas_opex': 4795.4503391884955, + 'oil_opex': 31317.518165038713, + 'water_opex': 20500.0, + 'other_utility': 21799.08416548877, + 'non_utility_expense': 117068.76044449637, + 'net_non_energy_opex': 138867.84460998513, + 'total_opex': 196329.83542091827, + 'noi': 11216.846075076726 +} -# average_income = { -# 'year': None, -# 'revenue': 95000.0, -# 'utility_expense': 56666.666666666657, -# 'energy_opex': 3258.4381553496269, -# 'electricity_opex': 1357.327044238516, -# 'gas_opex': 746.66666666666663, -# 'oil_opex': 1154.4444444444443, -# 'water_opex': 0.0, -# 'other_utility': 53408.228511317029, -# 'non_utility_expense': 3166.6666666666665, -# 'net_non_energy_opex': 56574.895177983693, -# 'total_opex': 59833.333333333321, -# 'noi': 35166.666666666679 -# } +average_income = { + 'year': None, + 'revenue': 200333.33333333334, + 'utility_expense': 77500.0, + 'energy_opex': 56458.549647682405, + 'electricity_opex': 825.88635362928574, + 'gas_opex': 4662.7027797267865, + 'oil_opex': 30469.960514326336, + 'water_opex': 20500.0, + 'other_utility': 21041.450352317588, + 'non_utility_expense': 113000.00000000001, + 'net_non_energy_opex': 134041.4503523176, + 'total_opex': 190500.0, + 'noi': 9833.333333333343 +} + +historical_cagr = 0.01242283656582921 -# historical_cagr = 0.05409255338945984 # post_annual_bill_table = { # 'electricity': { diff --git a/data_generation.py b/data_generation.py new file mode 100644 index 0000000..70b6433 --- /dev/null +++ b/data_generation.py @@ -0,0 +1 @@ +({2014: {'year': 2014, 'revenue': 200000, 'utility_expense': 77000, 'energy_opex': 55660.176408612344, 'electricity_opex': 819.06930386346062, 'gas_opex': 4625.0674743716318, 'oil_opex': 30216.03963037725, 'water_opex': 20000, 'other_utility': 21339.823591387656, 'non_utility_expense': 105000, 'net_non_energy_opex': 126339.82359138766, 'total_opex': 182000.0, 'noi': 18000.0}, 2015: {'year': 2015, 'revenue': 196000, 'utility_expense': 77400, 'energy_opex': 56462.176198804002, 'electricity_opex': 825.90552345154924, 'gas_opex': 4661.2913287497577, 'oil_opex': 30474.979346602693, 'water_opex': 20500, 'other_utility': 20937.823801195998, 'non_utility_expense': 104000, 'net_non_energy_opex': 124937.82380119601, 'total_opex': 181400.0, 'noi': 14600.0}, 2016: {'year': 2016, 'revenue': 205000, 'utility_expense': 78100, 'energy_opex': 57253.29633563089, 'electricity_opex': 832.68423357284746, 'gas_opex': 4701.7495360589701, 'oil_opex': 30718.862565999072, 'water_opex': 21000, 'other_utility': 20846.70366436911, 'non_utility_expense': 130000, 'net_non_energy_opex': 150846.70366436912, 'total_opex': 208100.0, 'noi': -3100.0}, 2017: {'year': 2017, 'revenue': 207546.681495995, 'utility_expense': 79261.074976421922, 'energy_opex': 57461.990810933145, 'electricity_opex': 849.02230670593224, 'gas_opex': 4795.4503391884955, 'oil_opex': 31317.518165038713, 'water_opex': 20500.0, 'other_utility': 21799.08416548877, 'non_utility_expense': 117068.76044449637, 'net_non_energy_opex': 138867.84460998513, 'total_opex': 196329.83542091827, 'noi': 11216.846075076726}, 2018: {'year': 2018, 'revenue': 210124.99999999994, 'utility_expense': 80450.873180044437, 'energy_opex': 58380.98255468304, 'electricity_opex': 870.14337868170207, 'gas_opex': 4915.0282767633271, 'oil_opex': 32095.810899238011, 'water_opex': 20500.0, 'other_utility': 22069.890625361393, 'non_utility_expense': 118523.08652246254, 'net_non_energy_opex': 140592.97714782393, 'total_opex': 198973.95970250695, 'noi': 11151.040297492989}, 2019: {'year': 2019, 'revenue': 212735.3485333948, 'utility_expense': 81657.272114136751, 'energy_opex': 59313.210844510766, 'electricity_opex': 891.54208077704823, 'gas_opex': 5035.5379855566225, 'oil_opex': 32886.130778177096, 'water_opex': 20500.0, 'other_utility': 22344.061269625981, 'non_utility_expense': 119995.47945560873, 'net_non_energy_opex': 142339.54072523472, 'total_opex': 201652.75156974548, 'noi': 11082.596963649325}, 2020: {'year': 2020, 'revenue': 215378.12499999988, 'utility_expense': 82844.084329901569, 'energy_opex': 60222.446438906147, 'electricity_opex': 912.4254645897646, 'gas_opex': 5153.4461029776512, 'oil_opex': 33656.574871338729, 'water_opex': 20500.0, 'other_utility': 22621.637890995422, 'non_utility_expense': 121486.16368552408, 'net_non_energy_opex': 144107.8015765195, 'total_opex': 204330.24801542563, 'noi': 11047.87698457425}, 2021: {'year': 2021, 'revenue': 218053.7322467296, 'utility_expense': 83975.856179475901, 'energy_opex': 61073.193378109274, 'electricity_opex': 931.94007239274924, 'gas_opex': 5263.0160958060724, 'oil_opex': 34378.237209910454, 'water_opex': 20500.0, 'other_utility': 22902.662801366623, 'non_utility_expense': 122995.3664419989, 'net_non_energy_opex': 145898.02924336554, 'total_opex': 206971.22262147482, 'noi': 11082.509625254781}, 2022: {'year': 2022, 'revenue': 220762.5781249998, 'utility_expense': 85030.647337560615, 'energy_opex': 61843.468499290313, 'electricity_opex': 949.62365204805212, 'gas_opex': 5362.6629176416373, 'oil_opex': 35031.181929600622, 'water_opex': 20500.0, 'other_utility': 23187.178838270298, 'non_utility_expense': 124523.31777766213, 'net_non_energy_opex': 147710.49661593244, 'total_opex': 209553.96511522276, 'noi': 11208.613009777036}, 2023: {'year': 2023, 'revenue': 223505.07555289776, 'utility_expense': 86073.429092948703, 'energy_opex': 62598.19972154792, 'electricity_opex': 966.95721096995919, 'gas_opex': 5460.5010514877649, 'oil_opex': 35670.741459090197, 'water_opex': 20500.0, 'other_utility': 23475.229371400783, 'non_utility_expense': 126070.25060304883, 'net_non_energy_opex': 149545.47997444961, 'total_opex': 212143.67969599753, 'noi': 11361.395856900228}, 2024: {'year': 2024, 'revenue': 226281.6425781247, 'utility_expense': 87135.528503000809, 'energy_opex': 63368.670193773767, 'electricity_opex': 984.65685227063227, 'gas_opex': 5560.5157868837869, 'oil_opex': 36323.497554619345, 'water_opex': 20500.0, 'other_utility': 23766.858309227046, 'non_utility_expense': 127636.40072210363, 'net_non_energy_opex': 151403.25903133067, 'total_opex': 214771.92922510445, 'noi': 11509.713353020255}, 2025: {'year': 2025, 'revenue': 229092.70244172015, 'utility_expense': 88227.412086838711, 'energy_opex': 64165.301981152908, 'electricity_opex': 1002.9565908187957, 'gas_opex': 5663.9000896622329, 'oil_opex': 36998.445300671876, 'water_opex': 20500.0, 'other_utility': 24062.110105685795, 'non_utility_expense': 129222.00686812503, 'net_non_energy_opex': 153284.11697381083, 'total_opex': 217449.41895496374, 'noi': 11643.283486756409}, 2026: {'year': 2026, 'revenue': 231938.6836425778, 'utility_expense': 89382.192302985874, 'energy_opex': 65021.162536028154, 'electricity_opex': 1022.6293693938102, 'gas_opex': 5775.3403422790016, 'oil_opex': 37723.192824355341, 'water_opex': 20500.0, 'other_utility': 24361.029766957719, 'non_utility_expense': 130827.3107401562, 'net_non_energy_opex': 155188.34050711393, 'total_opex': 220209.50304314209, 'noi': 11729.180599435698}, 2027: {'year': 2027, 'revenue': 234820.0200027631, 'utility_expense': 90608.923300079943, 'energy_opex': 65945.260441752005, 'electricity_opex': 1043.8599889408579, 'gas_opex': 5895.3500983195381, 'oil_opex': 38506.050354491614, 'water_opex': 20500.0, 'other_utility': 24663.662858327934, 'non_utility_expense': 132452.55703982813, 'net_non_energy_opex': 157116.21989815607, 'total_opex': 223061.48033990807, 'noi': 11758.539662855037}, 2028: {'year': 2028, 'revenue': 237737.1507336422, 'utility_expense': 91864.080349168915, 'energy_opex': 66894.02483803725, 'electricity_opex': 1065.650260619291, 'gas_opex': 6018.354334038997, 'oil_opex': 39310.02024337896, 'water_opex': 20500.0, 'other_utility': 24970.055511131657, 'non_utility_expense': 134097.9935086601, 'net_non_energy_opex': 159068.04901979174, 'total_opex': 225962.07385782897, 'noi': 11775.076875813218}, 2029: {'year': 2029, 'revenue': 240690.52050283214, 'utility_expense': 93124.396893137426, 'energy_opex': 67844.142463351294, 'electricity_opex': 1087.4697953564814, 'gas_opex': 6141.4801983648376, 'oil_opex': 40115.192469629976, 'water_opex': 20500.0, 'other_utility': 25280.254429786128, 'non_utility_expense': 135763.8709658238, 'net_non_energy_opex': 161044.12539560991, 'total_opex': 228888.26785896119, 'noi': 11802.252643870946}, 2030: {'year': 2030, 'revenue': 243680.5795019832, 'utility_expense': 94388.508463277947, 'energy_opex': 68794.201564368006, 'electricity_opex': 1109.2892523473229, 'gas_opex': 6264.6360349883253, 'oil_opex': 40920.276277032368, 'water_opex': 20500.0, 'other_utility': 25594.306898909941, 'non_utility_expense': 137450.44334637656, 'net_non_energy_opex': 163044.7502452865, 'total_opex': 231838.95180965451, 'noi': 11841.627692328679}, 2031: {'year': 2031, 'revenue': 246707.78351540287, 'utility_expense': 95659.392077519587, 'energy_opex': 69747.131286988821, 'electricity_opex': 1131.1744618622365, 'gas_opex': 6388.1588176948035, 'oil_opex': 41727.798007431789, 'water_opex': 20500.0, 'other_utility': 25912.260790530774, 'non_utility_expense': 139157.96773996935, 'net_non_energy_opex': 165070.22853050011, 'total_opex': 234817.35981748893, 'noi': 11890.423697913939}, 2032: {'year': 2032, 'revenue': 249772.5939895327, 'utility_expense': 96944.732064533484, 'energy_opex': 70710.567493150797, 'electricity_opex': 1153.3039252083101, 'gas_opex': 6513.1311498178793, 'oil_opex': 42544.132418124602, 'water_opex': 20500.0, 'other_utility': 26234.164571382684, 'non_utility_expense': 140886.70443003593, 'net_non_energy_opex': 167120.86900141861, 'total_opex': 237831.43649456941, 'noi': 11941.157494963292}, 2033: {'year': 2033, 'revenue': 252875.4781032879, 'utility_expense': 98255.82451699338, 'energy_opex': 71695.757206699345, 'electricity_opex': 1175.9341789481377, 'gas_opex': 6640.9586307853224, 'oil_opex': 43378.864396965881, 'water_opex': 20500.0, 'other_utility': 26560.067310294038, 'non_utility_expense': 142636.91693346857, 'net_non_energy_opex': 169196.98424376262, 'total_opex': 240892.74145046197, 'noi': 11982.73665282593}, 2034: {'year': 2034, 'revenue': 256016.90883927097, 'utility_expense': 99597.294490472937, 'energy_opex': 72707.2758048057, 'electricity_opex': 1199.1695873801598, 'gas_opex': 6772.2131729990733, 'oil_opex': 44235.89304442647, 'water_opex': 20500.0, 'other_utility': 26890.018685667244, 'non_utility_expense': 144408.8720407868, 'net_non_energy_opex': 171298.89072645406, 'total_opex': 244006.16653125978, 'noi': 12010.742308011191}, 2035: {'year': 2035, 'revenue': 259197.36505587003, 'utility_expense': 100970.45619606454, 'energy_opex': 73746.387203013161, 'electricity_opex': 1223.0386652944458, 'gas_opex': 6907.0434291160136, 'oil_opex': 45116.305108602697, 'water_opex': 20500.0, 'other_utility': 27224.068993051384, 'non_utility_expense': 146202.83985680525, 'net_non_energy_opex': 173426.90884985664, 'total_opex': 247173.29605286982, 'noi': 12024.069003000215}, 2036: {'year': 2036, 'revenue': 262417.3315602527, 'utility_expense': 102375.48550524657, 'energy_opex': 74813.216352437652, 'electricity_opex': 1247.5443683668141, 'gas_opex': 7045.4681428808135, 'oil_opex': 46020.203841190028, 'water_opex': 20500.0, 'other_utility': 27562.269152808924, 'non_utility_expense': 148019.09384180643, 'net_non_energy_opex': 175581.36299461537, 'total_opex': 250394.57934705302, 'noi': 12022.752213199681}}, {'year': 2017, 'revenue': 207546.681495995, 'utility_expense': 79261.074976421922, 'energy_opex': 57461.990810933145, 'electricity_opex': 849.02230670593224, 'gas_opex': 4795.4503391884955, 'oil_opex': 31317.518165038713, 'water_opex': 20500.0, 'other_utility': 21799.08416548877, 'non_utility_expense': 117068.76044449637, 'net_non_energy_opex': 138867.84460998513, 'total_opex': 196329.83542091827, 'noi': 11216.846075076726}, {'year': None, 'revenue': 200333.33333333334, 'utility_expense': 77500.0, 'energy_opex': 56458.549647682405, 'electricity_opex': 825.88635362928574, 'gas_opex': 4662.7027797267865, 'oil_opex': 30469.960514326336, 'water_opex': 20500.0, 'other_utility': 21041.450352317588, 'non_utility_expense': 113000.00000000001, 'net_non_energy_opex': 134041.4503523176, 'total_opex': 190500.0, 'noi': 9833.333333333343}, 0.01242283656582921) \ No newline at end of file -- GitLab From 8d1bd9f6db76fbe7eabfb59240b64939321c3012 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Fri, 19 May 2017 18:07:15 -0400 Subject: [PATCH 07/37] Add validate_annual_bill_table(). Not finished yet --- bpfin/financials/financial_income.py | 58 +++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/bpfin/financials/financial_income.py b/bpfin/financials/financial_income.py index 8c1d8b5..706dadb 100644 --- a/bpfin/financials/financial_income.py +++ b/bpfin/financials/financial_income.py @@ -148,8 +148,9 @@ class Income_Statement_Next(): annual_bill_table = {'electricity': electricity_bill, 'oil': oil_bill, 'gas': gas_bill, 'water': water_bill} electricity_bill = {2014: 100, 2015:200, ...} """ + if not validate_growth_rate_flag(growth_rate_flag): + raise ValueError('growth_rate input is not valid') self.year = year - if growth_rate_flag == -1.0: # growth_rate_flag == average current_revenue = characters['revenue_average'] else: @@ -165,8 +166,7 @@ class Income_Statement_Next(): self.water_opex = annual_bill_table['water'][self.year] self.energy_opex = self.electricity_opex + self.gas_opex + self.oil_opex + self.water_opex self.other_utility = self.revenue * characters['other_utility_percent'] - self.non_utility_expense = self.revenue * characters[ - 'non_utility_expense_percent'] + self.non_utility_expense = self.revenue * characters['non_utility_expense_percent'] self.utility_expense = self.energy_opex + self.other_utility self.net_non_energy_opex = self.other_utility + self.non_utility_expense self.total_opex = self.energy_opex + self.net_non_energy_opex @@ -218,6 +218,15 @@ class Income_Statement_Table(): annual_bill_table: annual_bill_table years should cover proforma years """ + if not validate_empty(raw_income_input): + raise ValueError('Income_Statement_Table-init() raw_income_input is empty') + if not validate_empty(analysis_date): + raise ValueError('Income_Statement_Table-init() analysis_date is empty') + # validate annual_bill_table + if not validate_annual_bill_table(annual_bill_table): + raise ValueError('Income_Statement_Table-init() annual_bill_table is invalid') + # validate raw_income_input + self.hist_start_year = None self.hist_end_year = None self.cagr = 0.00 @@ -229,16 +238,14 @@ class Income_Statement_Table(): self.characters = {} self.analysis_date = analysis_date - for year in raw_income_input: + for year in raw_income_input.keys(): current_income_statement = Income_Statement() - current_income_statement.put_hist(year, raw_income_input[year], - annual_bill_table) + current_income_statement.put_hist(year, raw_income_input[year], annual_bill_table) self.hist_table.append(current_income_statement) sorted_income_hist_year = sorted(raw_income_input) self.hist_start_year = sorted_income_hist_year[0] self.hist_end_year = sorted_income_hist_year[-1] - # if start_year == None: return None self.cagr = lib.cal_cagr( raw_income_input[self.hist_start_year]['revenue'], raw_income_input[self.hist_end_year]['revenue'], @@ -254,8 +261,7 @@ class Income_Statement_Table(): self.other_utility_percent = other_utility_sum / revenue_sum self.non_utility_expense_percent = non_utility_expense_sum / revenue_sum - self.revenue_average = revenue_sum / ( - self.hist_end_year - self.hist_start_year + 1) + self.revenue_average = revenue_sum / (self.hist_end_year - self.hist_start_year + 1) self.table = self.hist_table self.characters = { @@ -455,3 +461,37 @@ def validate_growth_rate_flag(growth_rate_flag): if growth_rate_flag == -2: return True return False + + +def validate_annual_bill_table(annual_bill_table): + """ + check annual bill table data + variable should have 4 keys, which are utility types + All utilities should have same year range (same starting year and length) + bill charge values are not None + """ + if not len(annual_bill_table.keys()) == len(UTILITY_TYPE_LIST): + return False + + start_year = sorted(annual_bill_table['electricity'].keys())[0] + duration = len(annual_bill_table['electricity'].keys()) + + for utility in UTILITY_TYPE_LIST: + if sorted(annual_bill_table[utility].keys())[0] != start_year: + return False + if len(annual_bill_table[utility].keys()) != duration: + return False + for charge in annual_bill_table[utility].values(): + if not charge: + return False + return True + + +def validate_empty(parameter): + """ + check empty for input parameter + """ + if not parameter: + return False + else: + return True -- GitLab From 0426746c3151efe91cc1c00a6442cede6e22cded Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Sun, 21 May 2017 12:04:02 -0400 Subject: [PATCH 08/37] Add to do task in saving and scenario func --- bpfin/financials/financial_lib.py | 5 +++-- bpfin/financials/scenario.py | 12 +++++++++++- bpfin/tests/testdata/feature_data.py | 3 ++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/bpfin/financials/financial_lib.py b/bpfin/financials/financial_lib.py index 2fead0d..df7f34f 100644 --- a/bpfin/financials/financial_lib.py +++ b/bpfin/financials/financial_lib.py @@ -9,6 +9,8 @@ from numpy import mean def organize_bill_overview(bill_overview, analysis_date): """take bill_overview as inputs, fill in the blank annual bill with average numbers + !! this func should be deleted when financial_income.py and back_end_call.py is online + Args: bill_overview (dictionary): original annual bill input, with blank cells, for 4 utility_types analysis_date (dictionary): proforma's starting date and the years of proforma @@ -182,8 +184,7 @@ class Income_Statement_Next(): with input of last year data, income statement characters, and projected annual bill """ - def __init__(self, year, last_revenue, growth_rate_flag, characters, - annual_bill_table): + def __init__(self, year, last_revenue, growth_rate_flag, characters, annual_bill_table): """ Calculation is done in initiation. Args: diff --git a/bpfin/financials/scenario.py b/bpfin/financials/scenario.py index bdce9e1..e733cae 100644 --- a/bpfin/financials/scenario.py +++ b/bpfin/financials/scenario.py @@ -29,6 +29,7 @@ class Scenario(): loan_list (object): Loan_List object, used to store loan options, and result of financing planning saving_overview (object): Saving_Overview object, calculate and store scenario based saving results scheduled_loan_list (list): list of Loan objects. Store financing plans for each loan option + """ def __init__(self, analysis_date, commission_date, construction_cost, bill_overview, prior_annual_bill_table, other_debt_service, @@ -56,6 +57,13 @@ class Scenario(): bill_overview (dictionary): dict of a list, list[0] = dict of annual bill, allow some year missing, for 4 utility_types list[1] = boolean value, False == from manual input, True == from scraper + To Do: + bill_overview -> raw_bill_table + prior_annual_bill_table -> raw_annual_bill_table + other_debt_service -> raw_liability + prior_income_statement_table -> raw_income_table + prior_balance_sheet_table -> raw_cash_input + loan_input_list -> loan_input_list """ self.analysis_date = analysis_date self.commission_date = copy.deepcopy(commission_date) @@ -110,7 +118,9 @@ class Scenario(): 'cust_saving_dscr': float, customer required lower limit of (saving / debt service) ratio} To Do: clarify commission date and loan start date - balance sheet is not considering in energy loan. Which is should. And it changes get_graph_dict + balance sheet is not considering in energy loan. Which should. And it changes get_graph_dict + + prior_month_bill -> self.prior_month_bill """ # calculate saving, by generating saving_overview object self.saving_overview.put_saving( diff --git a/bpfin/tests/testdata/feature_data.py b/bpfin/tests/testdata/feature_data.py index 1263521..21a364c 100644 --- a/bpfin/tests/testdata/feature_data.py +++ b/bpfin/tests/testdata/feature_data.py @@ -231,11 +231,12 @@ percent_saving_dict = { } full_saving_dict = { - 'electricity': None, # dict of engineering analysis, {'date_from': [], 'date_to': [], 'heating': [], 'cooling': [], 'other': []} + 'electricity': None, 'gas': None, 'oil': None, 'water': None } +# dict of engineering analysis, {'date_from': [], 'date_to': [], 'heating': [], 'cooling': [], 'other': []} prior_annual_bill = { 'electricity': { -- GitLab From 038b4535f28f2e686187c7ad1f8efe9a61ac66aa Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Tue, 23 May 2017 11:30:08 -0400 Subject: [PATCH 09/37] Merge from master --- bpfin/utilbills/bill.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bpfin/utilbills/bill.py b/bpfin/utilbills/bill.py index 161f54d..8179015 100644 --- a/bpfin/utilbills/bill.py +++ b/bpfin/utilbills/bill.py @@ -9,10 +9,11 @@ from bpfin.lib.other import form_date_calendar from bpfin.utilbills.bill_month_normalize_rough import bill_month_normalize_rough from bpfin.utilbills.bill_prior_proj_rough import bill_prior_proj_rough from bpfin.utilbills.inflation_sample_data import inflation_coeff_dict +from bpfin.lib.other import UTILITY_TYPE_LIST # from bpfin.tests.testdata import feature_data as db -UTILITY_TYPE_LIST = ['electricity', 'gas', 'oil', 'water'] +# UTILITY_TYPE_LIST = ['electricity', 'gas', 'oil', 'water'] def validate_raw_bill(raw_bill): -- GitLab From 27281f528189d549f7fbe03d7e097224bc380400 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Tue, 23 May 2017 16:21:10 -0400 Subject: [PATCH 10/37] Create form_prior_month_bill (), which will be used for scenario and saving. Should be merged to back_end_call.monthly_bill() --- bpfin/financials/financial_saving.py | 739 ++++++++++++++------------- bpfin/lib/back_end_call.py | 2 + bpfin/utilbills/bill.py | 63 ++- 3 files changed, 454 insertions(+), 350 deletions(-) diff --git a/bpfin/financials/financial_saving.py b/bpfin/financials/financial_saving.py index 72c769c..ab91000 100644 --- a/bpfin/financials/financial_saving.py +++ b/bpfin/financials/financial_saving.py @@ -12,355 +12,398 @@ # from bpfin.tests.testdata import sample_data as db # from bpfin.tests.testdata import feature_data as fdb +import datetime +import copy +from bpfin.utilbills.bill_lib import cal_last_day +from bpfin.utilbills.bill_lib import annualizing_projection +from bpfin.utilbills.bill_lib import form_year_calendar +from bpfin.utilbills.bill_lib import form_bill_calendar +from bpfin.utilbills.bill_post_proj_rough import bill_post_proj_rough +from bpfin.tests.testdata import sample_data as db + + +class Saving(): + """ + Calculate savings and project bills with commissioning date considered. For one utility type + Attributes: + is_manual_input (boolean): lable indicating is bill input by scraper or manual. Yes == manual input + commissioning_date (date): the date that construction work finished, saving starts at NEXT month + proforma_date (list): list of dates, months of pro-forma time period + proforma_usage (list) : list of monthly usage, for pro-forma period + Data before commissioning date == historical + Data after commissioning date == post saving data + proforma_charge (list) : list of monthly charge, for pro-forma period + Data before commissioning date == historical + Data after commissioning date == post saving data + proforma_saving_usage (list) : monthly savings on usage, for pro-forma period + Data before commissioning date == historical + Data after commissioning date == post saving data + proforma_saving_charge (list) : monthly savings on usage, for pro-forma period + Data before commissioning date == historical + Data after commissioning date == post saving data + first_year_saving_usage (float) : first 12 months saving on usage. + first_year_saving_charge (float) : first 12 months saving on charge. If data is annual, saving is on NEXT year + annual_proforma_usage (dictionary) : key is year, value is float, annual usage + annual_proforma_charge (dictionary) : key is year, value is float, annual charge + first_year_prior_charge (float): first 12 months prior_saving charge. If data is annual, charge is for NEXT year + percent_saving (float): percentage saving on first year charge. 0.2 == 20% + """ + def __init__(self, is_manual_input, commissioning_date, proforma_date): + """ + Initiate Saving object. + Args: + is_manual_input (boolean): lable indicating is bill input by scraper or manual. Yes == manual input + commissioning_date (date): the date that construction work finished, saving starts at NEXT month + proforma_date (list): list of dates, months of pro-forma time period + """ + self.is_manual_input = is_manual_input + self.commissioning_date = commissioning_date + self.proforma_date = proforma_date + self.proforma_usage = None + self.proforma_charge = None + self.proforma_saving_usage = None + self.proforma_saving_charge = None + self.first_year_saving_charge = None + self.first_year_saving_usage = None + self.annual_proforma_usage = None + self.annual_proforma_charge = None + self.first_year_prior_charge = None + self.percent_saving = 0 + + def put_monthly_proforma(self, prior_saving_usage, post_saving_usage, prior_saving_charge, post_saving_charge): + """ + Put monthly prior_saving and post_saving, generate: monthly usage and charge for pro-forma purpose. + Also generate first year savings, and annual usage and annual charge + + Args: + prior_saving_usage (list): list of float, usage without (prior to) savings + post_saving_usage (list): list of float, usage with (post to) savings + prior_saving_charge (list): list of float, charge without (prior to) savings + post_saving_charge (list): list of float, charge with (post to) savings + """ + if self.is_manual_input is False: + saving_start_date = datetime.date( + self.commissioning_date.year, + self.commissioning_date.month, + cal_last_day(self.commissioning_date.year, self.commissioning_date.month)) + + saving_usage_dict = {} + saving_charge_dict = {} + proforma_usage_dict = {} + proforma_charge_dict = {} + first_year_saving_usage = 0 + first_year_saving_charge = 0 + first_yr_counter = 0 + first_year_prior_charge = 0 + for date, prior_usage, post_usage, prior_charge, post_charge in zip( + self.proforma_date, + prior_saving_usage, + post_saving_usage, + prior_saving_charge, + post_saving_charge): + if date > saving_start_date: + saving_usage_dict[date] = prior_usage - post_usage + saving_charge_dict[date] = prior_charge - post_charge + proforma_usage_dict[date] = post_usage + proforma_charge_dict[date] = post_charge + if first_yr_counter <= 12: + first_year_saving_usage += prior_usage - post_usage + first_year_saving_charge += prior_charge - post_charge + first_year_prior_charge += prior_charge + first_yr_counter += 1 + else: + saving_usage_dict[date] = 0 + saving_charge_dict[date] = 0 + proforma_usage_dict[date] = prior_usage + proforma_charge_dict[date] = prior_charge + + self.proforma_usage = list(proforma_usage_dict.values()) + self.proforma_charge = list(proforma_charge_dict.values()) + self.proforma_saving_usage = list(saving_usage_dict.values()) + self.proforma_saving_charge = list(saving_charge_dict.values()) + self.first_year_saving_usage = first_year_saving_usage + self.first_year_saving_charge = first_year_saving_charge + self.annual_proforma_usage = annualizing_projection(self.proforma_date, self.proforma_charge) + self.annual_proforma_charge = annualizing_projection(self.proforma_date, self.proforma_charge) + self.first_year_prior_charge = first_year_prior_charge + self.percent_saving = first_year_saving_charge / first_year_prior_charge + + def put_annual_proforma(self, annual_charge, percent_saving): + """ + Put annual prior_saving charge, calculate saving on charge and overall percentage saving + + Args: + annual_charge (dictionary): dict of annual prior saving charge, {2014: 100, ...}, with future estimated + percent_saving (float): percent of saving, 0.030 == 3.0% + """ + if self.is_manual_input is True: + annual_saving_dict = {} + annual_charge_dict = {} + proforma_year = form_year_calendar(self.proforma_date[0], self.proforma_date[-1]) + for year in proforma_year: + if year < self.commissioning_date.year: + annual_saving_dict[year] = 0 + annual_charge_dict[year] = annual_charge[year] + if year > self.commissioning_date.year: + annual_saving_dict[year] = annual_charge[year] * percent_saving + annual_charge_dict[year] = annual_charge[year] * (1 - percent_saving) + if year == self.commissioning_date.year: + effective_saving = (12 - self.commissioning_date.month) / 12 * percent_saving # partial year saving + annual_saving_dict[year] = annual_charge[year] * effective_saving + annual_charge_dict[year] = annual_charge[year] * (1 - effective_saving) + + first_year = self.commissioning_date.year + 1 + self.first_year_saving_charge = annual_saving_dict[first_year] + self.annual_proforma_charge = annual_charge_dict + self.first_year_prior_charge = annual_charge[first_year] + self.percent_saving = ( + annual_saving_dict[first_year] / annual_charge[first_year] if annual_charge[first_year] != 0 else 0) + + def get_proforma_charge(self): + """ + Get proforma_charge, for monthly pro-forma, not available for annual + Return: + list: proforma_charge + """ + return self.proforma_charge + + def get_proforma_saving_charge(self): + """ + Get proforma_saving_charge, for monthly pro-forma, not available for annual + Return: + list: proforma_saving_charge + """ + return self.proforma_saving_charge + + def get_percent_saving(self): + """ + Get percentage saving on charge + Return: + float: overall percentage saving on charge + """ + return self.percent_saving + + def get_first_year_saving_charge(self): + """ + Get first year saving + Return: + float: sum of first 12 months of savings + """ + return self.first_year_saving_charge + + def get_first_year_prior_charge(self): + """ + Get prior charge for first year after commissioning + Return: + float: prior charge for first year after commissioning + """ + return self.first_year_prior_charge + + def get_annual_proforma_charge(self): + """ + Calculate and return annual pro-forma charge + Return: + dictionary: dict of annual item, {year: annual charge} + """ + return self.annual_proforma_charge + + +class Saving_Overview(): + """ + Generate saving schedule, annual usages and charges for 4 utility types + Also calculate percentage saving on usages and charges. + If rate plan applies, usage % saving can be different from charge % saving + Saving_Overview should be scenario based, it is an "attribute" of a scenario + + Attributes: + manual_input_dict(dictionary): key is utility type, value is boolean. True == mannual_input + prior_annual_bill_table (dictionary): annual bill, for 4 utility_types + proforma_date (list): list of dates, months of pro-forma time period + commissioning_date (date): the date that construction work finished, saving starts at NEXT month + utility_saving_dict (dictionary): dict of Saving objects, for 4 utility types + saving_percent_charge (dictionary): key is utility type, value is float {'electricity': float} + total_first_year_saving (float): dollar saving for the first 12 month after commissioning + total_saving_percent (float): percentage saving on charge for the first 12 month after commissioning + + Description: + prior_annual_bill_table = {'electricity': electricity_bill, 'oil': oil_bill, ...} + electricity_bill = {2014: 100, 2015:200, ...} + """ + + def __init__( + self, + manual_input_dict, + prior_annual_bill_table, + analysis_date, # consider to replace it with proforma_date + commissioning_date): + """ + Initiate Saving_Overview. + Take in manual_input_dict, annual and monthly bills, commissioning_date and percentage savings + Generate Saving objects, pro-forma date period + + Args: + manual_input_dict (dictionary): dict of boolean, indicating if bill is manually input + prior_annual_bill_table (dictionary): dict of dict of annual charge, for 4 utility_types + analysis_date (dictionary): proforma's starting date and the years of proforma + commissioning_date (date): the date that construction work finished, saving starts at NEXT month + + Description: + manual_input_dict = { + 'electricity': True, + 'oil': False, + 'gas': False, + 'water': False} + + prior_annual_bill_table = { + 'electricity': {2014: 100, 2015:200, ...}, + 'oil': dict of oil_bill, + 'gas': dict of gas_bill, + 'water': dict of water_bill} + """ + # self.manual_input_dict = { + # 'electricity': bill_overview['electricity'][1], + # 'gas': bill_overview['gas'][1], + # 'oil': bill_overview['oil'][1], + # 'water': bill_overview['water'][1]} + self.manual_input_dict = manual_input_dict + self.prior_annual_bill_table = prior_annual_bill_table + self.proforma_date = form_bill_calendar(analysis_date['proforma_start'], analysis_date['proforma_duration'])[1] + self.commissioning_date = commissioning_date + self.utility_saving_dict = {'electricity': None, 'gas': None, 'oil': None, 'water': None} + self.saving_percent_charge = {'electricity': None, 'gas': None, 'oil': None, 'water': None} + self.total_first_year_saving = 0 # dollar + self.total_saving_percent = 0 # dollar percentage + + def put_saving(self, prior_month_bill, percent_saving_dict, full_saving_dict): + """ + Put inputs to generage saving data. + Also calculate overall saving on charge, and percentage saving + + Args: + prior_month_bill (dictionary): dict of dict of lists, projected energy bill for prior_saving + percent_saving_dict (dictionary): dict of float, percentage saving for 4 utility types + full_saving_dict (dictionary): dict of undefined saving, from engineering saving analysis. can be None + + Description: + prior_month_bill = { + 'electricity': electricity_prior_bill_rough, + 'gas': None, + 'oil': None, + 'water': None} + + electricity_prior_bill_rough = { + 'date_from': list, + 'date_to': list, + 'usage': list, + 'charge': list, + 'price': list} + """ + utility_type_list = ['electricity', 'gas', 'oil', 'water'] + + total_first_year_saving = 0 + total_first_year_prior_charge = 0 + for utility in utility_type_list: + is_manual_input = self.manual_input_dict[utility] + + utility_saving = Saving(is_manual_input, self.commissioning_date, self.proforma_date) + + if utility_saving.is_manual_input is True: # bill is from manual input, monthly bill not available + utility_saving.put_annual_proforma(self.prior_annual_bill_table[utility], percent_saving_dict[utility]) + + if utility_saving.is_manual_input is False: # bill is from scraper, monthly bill is available + if full_saving_dict[utility] is None: # engineering saving is not available, use percentage saving + post_month_bill = bill_post_proj_rough(prior_month_bill[utility], percent_saving_dict[utility]) + # else: # engineering saving is available. Project monthly_bill with regression. not finished yet + # post_month_bill = bill_proj_reg(prior_utility, full_saving_dict[utility], HDD, CDD, occupancy) + + utility_saving.put_monthly_proforma( + prior_month_bill[utility]['usage'], + post_month_bill['usage'], + prior_month_bill[utility]['charge'], + post_month_bill['charge']) + + total_first_year_saving += utility_saving.get_first_year_saving_charge() + total_first_year_prior_charge += utility_saving.get_first_year_prior_charge() + self.saving_percent_charge[utility] = utility_saving.get_percent_saving() + self.utility_saving_dict[utility] = utility_saving + + self.total_first_year_saving = total_first_year_saving + self.total_saving_percent = ( + total_first_year_saving / total_first_year_prior_charge if total_first_year_prior_charge != 0 else 0) + + def get_total_first_year_saving(self): + """ + Get first year total dollar saving + This is used for: loan allocation, simple_payback calculation + Retrun: + float: a dollar number + """ + return self.total_first_year_saving + + def get_simple_payback(self, cost): + """ + Get the simple payback for a given project cost. cost / first year dollar saving + Args: + cost (float): project cost, estimated or quoted + Return: + float: simple paback, in year + """ + return float(cost / self.total_first_year_saving if self.total_first_year_saving != 0 else 0) + + def get_total_saving_percent(self): + """ + Get the total saving percentage. First dollar saving / First year prior_saving charge + Return: + float: total dollar saving percentage + """ + return self.total_saving_percent + + def get_post_annual_bill_table(self): + """ + Generate annual bill table for pro-forma, consiering commission date. + Return: + dictionary: dict of dict of annual charges, for 4 utility types + Description: + output = {'electricity': electricity_bill, 'oil': oil_bill, 'gas': gas_bill, 'water': water_bill} + electricity_bill = {2014: 100, 2015:200, ...} + } + """ + post_annual_bill_table = {} + utility_type_list = ['electricity', 'gas', 'oil', 'water'] + for utility_type in utility_type_list: + post_annual_bill_table[utility_type] = copy.deepcopy( + self.utility_saving_dict[utility_type].get_annual_proforma_charge()) + return post_annual_bill_table + + def get_utility_annual_saving_charge(self, utility_type): + """ + Get the proforma annual saving on charge for a utility_type + Args: + utility_type (string): 'electricity', 'gas', 'oil', 'water' + Return: + dictionary: {year: saving on charge} + """ + prior_charge_dict = copy.deepcopy(self.prior_annual_bill_table[utility_type]) + post_charge_dict = copy.deepcopy(self.utility_saving_dict[utility_type].get_annual_proforma_charge()) + saving_dict = {} + for year in prior_charge_dict: + saving_dict[year] = prior_charge_dict[year] - post_charge_dict[year] + return saving_dict + + + + + +# **** ugly test **** +# so = Saving_Overview(db.bill_overview, db.bill_overview_organized, db.analysis_date, datetime.date(2017, 3, 14)) +# so.put_saving(db.prior_month_bill, db.percent_saving_dict, db.full_saving_dict) + +# print('\n first_year_dollar_saving =', so.get_total_first_year_saving()) +# print('\n simple payback =', so.get_simple_payback(50000)) +# print('\n total saving percent =', so.get_total_saving_percent()) +# print('\n electricity_annual_saving_charge', so.get_utility_annual_saving_charge('electricity')) +# print(so.get_post_annual_bill_table()) -# UTILITY_TYPE_LIST = ['electricity', 'gas', 'oil', 'water'] - - -# class Saving(): -# """ -# Calculate savings and project bills with commissioning date considered. For one utility type -# Attributes: -# is_manual_input (boolean): label indicating is bill input by scraper or manual. Yes == manual input -# commission_date (date): the date that construction work finished, saving starts at NEXT month -# proforma_date (list): list of dates, months of pro-forma time period -# proforma_usage (list) : list of monthly usage, for pro-forma period -# calculated by put_monthly_proforma() -# Data before commissioning date == historical -# Data after commissioning date == post saving data -# proforma_charge (list) : list of monthly charge, for pro-forma period -# calculated by put_monthly_proforma() -# Data before commissioning date == historical -# Data after commissioning date == post saving data -# proforma_saving_usage (list) : monthly savings on usage, for pro-forma period -# calculated by put_monthly_proforma() -# Data before commissioning date == historical -# Data after commissioning date == post saving data -# proforma_saving_charge (list) : monthly savings on usage, for pro-forma period -# calculated by put_monthly_proforma() -# Data before commissioning date == historical -# Data after commissioning date == post saving data -# first_year_saving_usage (float) : first 12 months saving on usage. -# first_year_saving_charge (float) : first 12 months saving on charge. If data is annual, saving is on NEXT year -# annual_proforma_usage (dictionary) : key is year, value is float, annual usage -# annual_proforma_charge (dictionary) : key is year, value is float, annual charge -# first_year_prior_charge (float): first 12 months prior_saving charge. If data is annual, charge is for NEXT year -# percent_saving (float): percentage saving on first year charge. 0.2 == 20% -# """ -# def __init__(self, is_manual_input, commission_date, proforma_date): -# """ -# Initiate Saving object. -# Args: -# is_manual_input (boolean): label indicating is bill input by scraper or manual. Yes == manual input -# commission_date (date): the date that construction work finished, saving starts at NEXT month -# proforma_date (list): list of dates, months of pro-forma time period -# """ -# self.is_manual_input = is_manual_input -# self.commission_date = commission_date -# self.proforma_date = proforma_date -# self.proforma_usage = None -# self.proforma_charge = None -# self.proforma_saving_usage = None -# self.proforma_saving_charge = None -# self.first_year_saving_charge = None -# self.first_year_saving_usage = None -# self.annual_proforma_usage = None -# self.annual_proforma_charge = None -# self.first_year_prior_charge = None -# self.percent_saving = 0 - -# def put_monthly_proforma(self, prior_saving_usage, post_saving_usage, prior_saving_charge, post_saving_charge): -# """ -# Put monthly prior_saving and post_saving, generate: monthly usage and charge for pro-forma purpose. -# Also generate first year savings, and annual usage and annual charge - -# Args: -# prior_saving_usage (list): list of float, usage without (prior to) savings -# post_saving_usage (list): list of float, usage with (post to) savings -# prior_saving_charge (list): list of float, charge without (prior to) savings -# post_saving_charge (list): list of float, charge with (post to) savings -# """ -# if not self.is_manual_input: -# saving_start_date = datetime.date( -# self.commission_date.year, -# self.commission_date.month, -# cal_last_day(self.commission_date.year, self.commission_date.month)) - -# saving_usage_dict = {} -# saving_charge_dict = {} -# proforma_usage_dict = {} -# proforma_charge_dict = {} -# first_year_saving_usage = 0 -# first_year_saving_charge = 0 -# first_yr_counter = 0 -# first_year_prior_charge = 0 -# for date, prior_usage, post_usage, prior_charge, post_charge in zip( -# self.proforma_date, -# prior_saving_usage, -# post_saving_usage, -# prior_saving_charge, -# post_saving_charge): -# if date > saving_start_date: -# saving_usage_dict[date] = prior_usage - post_usage -# saving_charge_dict[date] = prior_charge - post_charge -# proforma_usage_dict[date] = post_usage -# proforma_charge_dict[date] = post_charge -# if first_yr_counter <= 12: -# first_year_saving_usage += prior_usage - post_usage -# first_year_saving_charge += prior_charge - post_charge -# first_year_prior_charge += prior_charge -# first_yr_counter += 1 -# else: -# saving_usage_dict[date] = 0 -# saving_charge_dict[date] = 0 -# proforma_usage_dict[date] = prior_usage -# proforma_charge_dict[date] = prior_charge - -# self.proforma_usage = list(proforma_usage_dict.values()) -# self.proforma_charge = list(proforma_charge_dict.values()) -# self.proforma_saving_usage = list(saving_usage_dict.values()) -# self.proforma_saving_charge = list(saving_charge_dict.values()) -# self.first_year_saving_usage = first_year_saving_usage -# self.first_year_saving_charge = first_year_saving_charge -# self.annual_proforma_usage = annualizing_projection(self.proforma_date, self.proforma_charge) -# self.annual_proforma_charge = annualizing_projection(self.proforma_date, self.proforma_charge) -# self.first_year_prior_charge = first_year_prior_charge -# self.percent_saving = first_year_saving_charge / first_year_prior_charge -# else: -# raise ValueError('Put_monthly_saving, please check: manual_input ==', self.is_manual_input) - -# def put_annual_proforma(self, annual_charge, percent_saving): -# """ -# Put annual prior_saving charge, calculate saving on charge and overall percentage saving - -# Args: -# annual_charge (dictionary): dict of annual prior saving charge, {2014: 100, ...}, with future estimated -# percent_saving (float): percent of saving, 0.030 == 3.0% -# """ -# if self.is_manual_input: -# annual_saving_dict = {} -# annual_charge_dict = {} -# proforma_year = form_year_calendar(self.proforma_date[0], self.proforma_date[-1]) -# for year in proforma_year: -# if year < self.commission_date.year: -# annual_saving_dict[year] = 0 -# annual_charge_dict[year] = annual_charge[year] -# if year > self.commission_date.year: -# annual_saving_dict[year] = annual_charge[year] * percent_saving -# annual_charge_dict[year] = annual_charge[year] * (1 - percent_saving) -# if year == self.commission_date.year: -# effective_saving = (12 - self.commission_date.month) / 12 * percent_saving # partial year saving -# annual_saving_dict[year] = annual_charge[year] * effective_saving -# annual_charge_dict[year] = annual_charge[year] * (1 - effective_saving) - -# first_year = self.commission_date.year + 1 -# self.first_year_saving_charge = annual_saving_dict[first_year] -# self.annual_proforma_charge = annual_charge_dict -# self.first_year_prior_charge = annual_charge[first_year] -# self.percent_saving = ( -# annual_saving_dict[first_year] / annual_charge[first_year] if annual_charge[first_year] != 0 else 0) -# else: -# raise ValueError('Put_annual_saving, please check: manual_input ==', self.is_manual_input) - -# def get_proforma_charge(self): -# """ -# Get proforma_charge, for monthly pro-forma, not availabel for annual -# Return: -# list: proforma_charge -# """ -# return self.proforma_charge - -# def get_proforma_saving_charge(self): -# """ -# Get proforma_saving_charge, for monthly pro-forma, not availabel for annual -# Return: -# list: proforma_saving_charge -# """ -# return self.proforma_saving_charge - -# def get_percent_saving(self): -# """ -# Get percentage saving on charge -# Return: -# float: overall percentage saving on charge -# """ -# return self.percent_saving - -# def get_first_year_saving_charge(self): -# """ -# Get first year saving -# Return: -# float: sum of first 12 months of savings -# """ -# return self.first_year_saving_charge - -# def get_first_year_prior_charge(self): -# """ -# Get prior charge for first year after commissioning -# Return: -# float: prior charge for first year after commissioning -# """ -# return self.first_year_prior_charge - -# def get_annual_proforma_charge(self): -# """ -# Calculate and return annual pro-forma charge -# Return: -# dictionary: dict of annual item, {year: annual charge} -# """ -# return self.annual_proforma_charge - - -# class Saving_Overview(): -# """ -# Generate saving schedule, annual usages and charges for 4 utility types -# Also calculate percentage saving on usages and charges. -# If rate plan applies, usage % saving can be different from charge % saving -# Saving_Overview should be scenario based, it is an "attribute" of a scenario - -# Attributes: -# bill_list (list): list of Bill objects, each element is a Bill class object. Contains 4 utilities -# # manual_input_dict(dictionary): key is utility type, value is boolean. True == mannual_input -# prior_annual_bill_table (dictionary): annual bill, for 4 utility_types. See description for detail -# proforma_date (list): list of dates, months of pro-forma time period -# commission_date (date): the date that construction work finished, saving starts at NEXT month -# utility_saving_dict (dictionary): dict of objects, each element is a Saving class object. Contains 4 utilities -# saving_percent_charge (dictionary): key is utility type, value is float {'electricity': float} -# total_first_year_saving (float): dollar saving for the first 12 month after commissioning -# total_saving_percent (float): percentage saving on charge for the first 12 month after commissioning - -# Description: -# prior_annual_bill_table = {'electricity': electricity_bill, 'oil': oil_bill, ...} -# electricity_bill = {2014: 100, 2015:200, ...} -# """ - -# def __init__( -# self, -# bill_list, -# analysis_date, # consider to replace it with proforma_date -# commission_date): -# """ -# Initiate Saving_Overview. -# Take in manual_input_dict, annual and monthly bills, commission_date and percentage savings -# Generate Saving objects, pro-forma date period - -# Args: -# bill_list (list): list of Bill objects -# analysis_date (dictionary): proforma's starting date and the years of proforma -# commission_date (date): the date that construction work finished, saving starts at NEXT month - -# To Do: validate bill_list -# """ -# self.prior_annual_bill_table = {} -# self.utility_saving_dict = {'electricity': None, 'gas': None, 'oil': None, 'water': None} -# self.saving_percent_charge = {'electricity': None, 'gas': None, 'oil': None, 'water': None} - -# self.bill_list = bill_list -# for bill in bill_list: -# self.prior_annual_bill_table[bill.utility_type] = bill.get_annual_bill() -# self.proforma_date = form_bill_calendar(analysis_date['proforma_start'], analysis_date['proforma_duration'])[1] -# self.commission_date = commission_date -# self.total_first_year_saving = 0 # dollar -# self.total_saving_percent = 0 # dollar percentage - -# def put_saving(self, percent_saving_dict, full_saving_dict): -# """ -# Put inputs to generage saving data. -# Also calculate overall saving on charge, and percentage saving - -# Args: -# percent_saving_dict (dictionary): dict of float, percentage saving for 4 utility types -# full_saving_dict (dictionary): dict of undefined saving, from engineering saving analysis. can be None -# """ -# total_first_year_saving = 0 -# total_first_year_prior_charge = 0 -# for bill in self.bill_list: -# utility = bill.utility_type -# is_manual_input = bill.is_manual_input - -# prior_month_bill = bill.get_prior_proj_rough() -# utility_saving = Saving(is_manual_input, self.commission_date, self.proforma_date) - -# if utility_saving.is_manual_input: # bill is from manual input, monthly bill not availabel -# utility_saving.put_annual_proforma(bill.get_annual_bill(), percent_saving_dict[utility]) - -# if not utility_saving.is_manual_input: # bill is from scraper, monthly bill is availabel -# if full_saving_dict[utility] is None: # engineering saving is not availabel, use percentage saving -# post_month_bill = bill_post_proj_rough(prior_month_bill, percent_saving_dict[utility]) -# # else: # engineering saving is availabel. Project monthly_bill with regression. not finished yet -# # post_month_bill = bill_proj_reg(prior_utility, full_saving_dict[utility], HDD, CDD, occupancy) - -# utility_saving.put_monthly_proforma( -# prior_month_bill['usage'], -# post_month_bill['usage'], -# prior_month_bill['charge'], -# post_month_bill['charge']) - -# total_first_year_saving += utility_saving.get_first_year_saving_charge() -# total_first_year_prior_charge += utility_saving.get_first_year_prior_charge() -# self.saving_percent_charge[utility] = utility_saving.get_percent_saving() -# self.utility_saving_dict[utility] = utility_saving - -# self.total_first_year_saving = total_first_year_saving -# self.total_saving_percent = ( -# total_first_year_saving / total_first_year_prior_charge if total_first_year_prior_charge != 0 else 0) - -# def get_total_first_year_saving(self): -# """ -# Get first year total dollar saving -# This is used for: loan allocation, simple_payback calculation -# Retrun: -# float: a dollar number -# """ -# return self.total_first_year_saving - -# def get_simple_payback(self, cost): -# """ -# Get the simple payback for a given project cost. cost / first year dollar saving -# Args: -# cost (float): project cost, estimated or quoted -# Return: -# float: simple paback, in year -# """ -# return float(cost / self.total_first_year_saving if self.total_first_year_saving != 0 else 0) - -# def get_total_saving_percent(self): -# """ -# Get the total saving percentage. First dollar saving / First year prior_saving charge -# Return: -# float: total dollar saving percentage -# """ -# return self.total_saving_percent - -# def get_post_annual_bill_table(self): -# """ -# Generate annual bill table for pro-forma, consiering commission date. -# Return: -# dictionary: dict of dict of annual charges, for 4 utility types -# Description: -# output = {'electricity': electricity_bill, 'oil': oil_bill, 'gas': gas_bill, 'water': water_bill} -# electricity_bill = {2014: 100, 2015:200, ...} -# } -# """ -# post_annual_bill_table = {} -# for utility_type in UTILITY_TYPE_LIST: -# post_annual_bill_table[utility_type] = copy.deepcopy( -# self.utility_saving_dict[utility_type].get_annual_proforma_charge()) -# return post_annual_bill_table - -# def get_utility_annual_saving_charge(self, utility_type): -# """ -# Get the proforma annual saving on charge for a utility_type -# Args: -# utility_type (string): 'electricity', 'gas', 'oil', 'water' -# Return: -# dictionary: {year: saving on charge} -# """ -# prior_charge_dict = copy.deepcopy(self.prior_annual_bill_table[utility_type]) -# post_charge_dict = copy.deepcopy(self.utility_saving_dict[utility_type].get_annual_proforma_charge()) -# saving_dict = {} -# for year in prior_charge_dict: -# saving_dict[year] = prior_charge_dict[year] - post_charge_dict[year] -# return saving_dict # # **** ugly test **** diff --git a/bpfin/lib/back_end_call.py b/bpfin/lib/back_end_call.py index 5a87e54..8235d3b 100644 --- a/bpfin/lib/back_end_call.py +++ b/bpfin/lib/back_end_call.py @@ -51,6 +51,8 @@ def monthly_bill(raw_bill_table, analysis_date): 'oil': dict of oil_bill, 'gas': dict of gas_bill, 'water': dict of water_bill} + + To Do: from utilbills.bill.py merge form_prior_month_bill(), and delete that one """ if not raw_bill_table: raise ValueError('Bill_Overview - monthly_bill has empty raw_bill_table') diff --git a/bpfin/utilbills/bill.py b/bpfin/utilbills/bill.py index 8179015..a172581 100644 --- a/bpfin/utilbills/bill.py +++ b/bpfin/utilbills/bill.py @@ -10,7 +10,7 @@ from bpfin.utilbills.bill_month_normalize_rough import bill_month_normalize_roug from bpfin.utilbills.bill_prior_proj_rough import bill_prior_proj_rough from bpfin.utilbills.inflation_sample_data import inflation_coeff_dict from bpfin.lib.other import UTILITY_TYPE_LIST -# from bpfin.tests.testdata import feature_data as db +from bpfin.tests.testdata import feature_data as db # UTILITY_TYPE_LIST = ['electricity', 'gas', 'oil', 'water'] @@ -204,6 +204,63 @@ class Bill(): return self.is_manual_input +def form_prior_month_bill(raw_bill_table, analysis_date, is_rough): + """ + Calculate and generate monthly energy bill for utilities that has available bills + + Args: + raw_bill_table (dictionary): dict of dict of raw_bill. Keys are utility types + analysis_date (dictionary): proforma's starting date and the years of proforma + is_rough (boolean): True == apply rough daily estimation, False == apply regression estimation + + Return: + prior_month_bill: dictionary, dict of dict of lists, projected energy bill for prior_saving + + Description: + raw_bill_table contains 4 utilities raw bill data. Each utility is a dictionary with 4 keys. + Each utility can be None. See below for detail + raw_bill_table = { + 'electricity': { + 'date_from': list of date, + 'date_to', list of date, + 'usage', list of float, + 'charge', list of float}, + 'gas': None, + 'oil': None, + 'water': None + } + + prior_month_bill = { + 'electricity': { + 'date_from': list, + 'date_to': list, + 'usage': list, + 'charge': list, + 'price': list}, + 'gas': None, + 'oil': None, + 'water': None} + """ + if not raw_bill_table: + raise ValueError('form_prior_month_bill - has empty raw_bill_table') + if not analysis_date: + raise ValueError('form_prior_month_bill - has empty analysis_date') + + prior_month_bill_dict = {} + for utility in UTILITY_TYPE_LIST: + if is_rough: + current_bill = Bill(utility, analysis_date) + if utility in raw_bill_table: + current_bill.put_month_bill(raw_bill_table[utility]) + else: + current_bill.put_month_bill(None) + prior_month_bill_dict[utility] = current_bill.get_prior_proj_rough() + else: + pass + if len(prior_month_bill_dict.keys()) != len(UTILITY_TYPE_LIST): + raise ValueError('form_prior_month_bill - has incomplete result') + return prior_month_bill_dict + # class Bill_Table(): # """ # """ @@ -276,7 +333,6 @@ class Bill(): # return bill_list - # **** ugly test **** # e_bill = Bill('electricity', db.analysis_date) # e_bill.put_month_bill(db.raw_bill_table['electricity']) @@ -291,3 +347,6 @@ class Bill(): # print(bill_table.utility_bill_dict['oil'].get_annual_bill()) # print(bill_table.get_bill_overview()) # print(bill_table.get_annual_bill_table()) + + +print(form_prior_month_bill(db.raw_bill_table, db.analysis_date, True)) -- GitLab From bcc6d5380d1e7e4dbef66b2c3cfaae1968edcb6a Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Tue, 23 May 2017 17:12:27 -0400 Subject: [PATCH 11/37] minor clean up on description --- bpfin/utilbills/bill.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bpfin/utilbills/bill.py b/bpfin/utilbills/bill.py index a172581..1ec2043 100644 --- a/bpfin/utilbills/bill.py +++ b/bpfin/utilbills/bill.py @@ -207,6 +207,7 @@ class Bill(): def form_prior_month_bill(raw_bill_table, analysis_date, is_rough): """ Calculate and generate monthly energy bill for utilities that has available bills + !!! Should be merged to back_end_call.monthly_bill() !! Args: raw_bill_table (dictionary): dict of dict of raw_bill. Keys are utility types -- GitLab From 2aaf664b29099627e7e01ddfbbefd96df1b21d89 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Thu, 25 May 2017 13:29:53 -0400 Subject: [PATCH 12/37] Minor Clean Up --- bpfin/lib/back_end_call.py | 22 +++++++++++----------- bpfin/utilbills/bill.py | 3 --- data_generation.py | 1 - 3 files changed, 11 insertions(+), 15 deletions(-) delete mode 100644 data_generation.py diff --git a/bpfin/lib/back_end_call.py b/bpfin/lib/back_end_call.py index e039de9..79d67c8 100644 --- a/bpfin/lib/back_end_call.py +++ b/bpfin/lib/back_end_call.py @@ -196,14 +196,14 @@ def prior_income_statement_table( # pp = pprint.PrettyPrinter(width=120, indent=4, compact=True) # pp.pprint(prior_income_statement_result) -result = prior_income_statement_table( - db.raw_income_input, - db.raw_bill_table, - db.raw_annual_bill_table, - db.analysis_date, - -2.0) - -writein = str(result) -f = open('data_generation.py', 'w') -f.write(writein) -f.close() +# result = prior_income_statement_table( +# db.raw_income_input, +# db.raw_bill_table, +# db.raw_annual_bill_table, +# db.analysis_date, +# -2.0) + +# writein = str(result) +# f = open('data_generation.py', 'w') +# f.write(writein) +# f.close() diff --git a/bpfin/utilbills/bill.py b/bpfin/utilbills/bill.py index 2371809..71716ff 100644 --- a/bpfin/utilbills/bill.py +++ b/bpfin/utilbills/bill.py @@ -15,9 +15,6 @@ from bpfin.lib.other import average_list_with_none # from bpfin.tests.testdata import feature_data as db -# UTILITY_TYPE_LIST = ['electricity', 'gas', 'oil', 'water'] - - def validate_raw_bill(raw_bill): """ Raw bill validation. A valid raw_bill is not None, and it covers at least 12 months diff --git a/data_generation.py b/data_generation.py deleted file mode 100644 index 70b6433..0000000 --- a/data_generation.py +++ /dev/null @@ -1 +0,0 @@ -({2014: {'year': 2014, 'revenue': 200000, 'utility_expense': 77000, 'energy_opex': 55660.176408612344, 'electricity_opex': 819.06930386346062, 'gas_opex': 4625.0674743716318, 'oil_opex': 30216.03963037725, 'water_opex': 20000, 'other_utility': 21339.823591387656, 'non_utility_expense': 105000, 'net_non_energy_opex': 126339.82359138766, 'total_opex': 182000.0, 'noi': 18000.0}, 2015: {'year': 2015, 'revenue': 196000, 'utility_expense': 77400, 'energy_opex': 56462.176198804002, 'electricity_opex': 825.90552345154924, 'gas_opex': 4661.2913287497577, 'oil_opex': 30474.979346602693, 'water_opex': 20500, 'other_utility': 20937.823801195998, 'non_utility_expense': 104000, 'net_non_energy_opex': 124937.82380119601, 'total_opex': 181400.0, 'noi': 14600.0}, 2016: {'year': 2016, 'revenue': 205000, 'utility_expense': 78100, 'energy_opex': 57253.29633563089, 'electricity_opex': 832.68423357284746, 'gas_opex': 4701.7495360589701, 'oil_opex': 30718.862565999072, 'water_opex': 21000, 'other_utility': 20846.70366436911, 'non_utility_expense': 130000, 'net_non_energy_opex': 150846.70366436912, 'total_opex': 208100.0, 'noi': -3100.0}, 2017: {'year': 2017, 'revenue': 207546.681495995, 'utility_expense': 79261.074976421922, 'energy_opex': 57461.990810933145, 'electricity_opex': 849.02230670593224, 'gas_opex': 4795.4503391884955, 'oil_opex': 31317.518165038713, 'water_opex': 20500.0, 'other_utility': 21799.08416548877, 'non_utility_expense': 117068.76044449637, 'net_non_energy_opex': 138867.84460998513, 'total_opex': 196329.83542091827, 'noi': 11216.846075076726}, 2018: {'year': 2018, 'revenue': 210124.99999999994, 'utility_expense': 80450.873180044437, 'energy_opex': 58380.98255468304, 'electricity_opex': 870.14337868170207, 'gas_opex': 4915.0282767633271, 'oil_opex': 32095.810899238011, 'water_opex': 20500.0, 'other_utility': 22069.890625361393, 'non_utility_expense': 118523.08652246254, 'net_non_energy_opex': 140592.97714782393, 'total_opex': 198973.95970250695, 'noi': 11151.040297492989}, 2019: {'year': 2019, 'revenue': 212735.3485333948, 'utility_expense': 81657.272114136751, 'energy_opex': 59313.210844510766, 'electricity_opex': 891.54208077704823, 'gas_opex': 5035.5379855566225, 'oil_opex': 32886.130778177096, 'water_opex': 20500.0, 'other_utility': 22344.061269625981, 'non_utility_expense': 119995.47945560873, 'net_non_energy_opex': 142339.54072523472, 'total_opex': 201652.75156974548, 'noi': 11082.596963649325}, 2020: {'year': 2020, 'revenue': 215378.12499999988, 'utility_expense': 82844.084329901569, 'energy_opex': 60222.446438906147, 'electricity_opex': 912.4254645897646, 'gas_opex': 5153.4461029776512, 'oil_opex': 33656.574871338729, 'water_opex': 20500.0, 'other_utility': 22621.637890995422, 'non_utility_expense': 121486.16368552408, 'net_non_energy_opex': 144107.8015765195, 'total_opex': 204330.24801542563, 'noi': 11047.87698457425}, 2021: {'year': 2021, 'revenue': 218053.7322467296, 'utility_expense': 83975.856179475901, 'energy_opex': 61073.193378109274, 'electricity_opex': 931.94007239274924, 'gas_opex': 5263.0160958060724, 'oil_opex': 34378.237209910454, 'water_opex': 20500.0, 'other_utility': 22902.662801366623, 'non_utility_expense': 122995.3664419989, 'net_non_energy_opex': 145898.02924336554, 'total_opex': 206971.22262147482, 'noi': 11082.509625254781}, 2022: {'year': 2022, 'revenue': 220762.5781249998, 'utility_expense': 85030.647337560615, 'energy_opex': 61843.468499290313, 'electricity_opex': 949.62365204805212, 'gas_opex': 5362.6629176416373, 'oil_opex': 35031.181929600622, 'water_opex': 20500.0, 'other_utility': 23187.178838270298, 'non_utility_expense': 124523.31777766213, 'net_non_energy_opex': 147710.49661593244, 'total_opex': 209553.96511522276, 'noi': 11208.613009777036}, 2023: {'year': 2023, 'revenue': 223505.07555289776, 'utility_expense': 86073.429092948703, 'energy_opex': 62598.19972154792, 'electricity_opex': 966.95721096995919, 'gas_opex': 5460.5010514877649, 'oil_opex': 35670.741459090197, 'water_opex': 20500.0, 'other_utility': 23475.229371400783, 'non_utility_expense': 126070.25060304883, 'net_non_energy_opex': 149545.47997444961, 'total_opex': 212143.67969599753, 'noi': 11361.395856900228}, 2024: {'year': 2024, 'revenue': 226281.6425781247, 'utility_expense': 87135.528503000809, 'energy_opex': 63368.670193773767, 'electricity_opex': 984.65685227063227, 'gas_opex': 5560.5157868837869, 'oil_opex': 36323.497554619345, 'water_opex': 20500.0, 'other_utility': 23766.858309227046, 'non_utility_expense': 127636.40072210363, 'net_non_energy_opex': 151403.25903133067, 'total_opex': 214771.92922510445, 'noi': 11509.713353020255}, 2025: {'year': 2025, 'revenue': 229092.70244172015, 'utility_expense': 88227.412086838711, 'energy_opex': 64165.301981152908, 'electricity_opex': 1002.9565908187957, 'gas_opex': 5663.9000896622329, 'oil_opex': 36998.445300671876, 'water_opex': 20500.0, 'other_utility': 24062.110105685795, 'non_utility_expense': 129222.00686812503, 'net_non_energy_opex': 153284.11697381083, 'total_opex': 217449.41895496374, 'noi': 11643.283486756409}, 2026: {'year': 2026, 'revenue': 231938.6836425778, 'utility_expense': 89382.192302985874, 'energy_opex': 65021.162536028154, 'electricity_opex': 1022.6293693938102, 'gas_opex': 5775.3403422790016, 'oil_opex': 37723.192824355341, 'water_opex': 20500.0, 'other_utility': 24361.029766957719, 'non_utility_expense': 130827.3107401562, 'net_non_energy_opex': 155188.34050711393, 'total_opex': 220209.50304314209, 'noi': 11729.180599435698}, 2027: {'year': 2027, 'revenue': 234820.0200027631, 'utility_expense': 90608.923300079943, 'energy_opex': 65945.260441752005, 'electricity_opex': 1043.8599889408579, 'gas_opex': 5895.3500983195381, 'oil_opex': 38506.050354491614, 'water_opex': 20500.0, 'other_utility': 24663.662858327934, 'non_utility_expense': 132452.55703982813, 'net_non_energy_opex': 157116.21989815607, 'total_opex': 223061.48033990807, 'noi': 11758.539662855037}, 2028: {'year': 2028, 'revenue': 237737.1507336422, 'utility_expense': 91864.080349168915, 'energy_opex': 66894.02483803725, 'electricity_opex': 1065.650260619291, 'gas_opex': 6018.354334038997, 'oil_opex': 39310.02024337896, 'water_opex': 20500.0, 'other_utility': 24970.055511131657, 'non_utility_expense': 134097.9935086601, 'net_non_energy_opex': 159068.04901979174, 'total_opex': 225962.07385782897, 'noi': 11775.076875813218}, 2029: {'year': 2029, 'revenue': 240690.52050283214, 'utility_expense': 93124.396893137426, 'energy_opex': 67844.142463351294, 'electricity_opex': 1087.4697953564814, 'gas_opex': 6141.4801983648376, 'oil_opex': 40115.192469629976, 'water_opex': 20500.0, 'other_utility': 25280.254429786128, 'non_utility_expense': 135763.8709658238, 'net_non_energy_opex': 161044.12539560991, 'total_opex': 228888.26785896119, 'noi': 11802.252643870946}, 2030: {'year': 2030, 'revenue': 243680.5795019832, 'utility_expense': 94388.508463277947, 'energy_opex': 68794.201564368006, 'electricity_opex': 1109.2892523473229, 'gas_opex': 6264.6360349883253, 'oil_opex': 40920.276277032368, 'water_opex': 20500.0, 'other_utility': 25594.306898909941, 'non_utility_expense': 137450.44334637656, 'net_non_energy_opex': 163044.7502452865, 'total_opex': 231838.95180965451, 'noi': 11841.627692328679}, 2031: {'year': 2031, 'revenue': 246707.78351540287, 'utility_expense': 95659.392077519587, 'energy_opex': 69747.131286988821, 'electricity_opex': 1131.1744618622365, 'gas_opex': 6388.1588176948035, 'oil_opex': 41727.798007431789, 'water_opex': 20500.0, 'other_utility': 25912.260790530774, 'non_utility_expense': 139157.96773996935, 'net_non_energy_opex': 165070.22853050011, 'total_opex': 234817.35981748893, 'noi': 11890.423697913939}, 2032: {'year': 2032, 'revenue': 249772.5939895327, 'utility_expense': 96944.732064533484, 'energy_opex': 70710.567493150797, 'electricity_opex': 1153.3039252083101, 'gas_opex': 6513.1311498178793, 'oil_opex': 42544.132418124602, 'water_opex': 20500.0, 'other_utility': 26234.164571382684, 'non_utility_expense': 140886.70443003593, 'net_non_energy_opex': 167120.86900141861, 'total_opex': 237831.43649456941, 'noi': 11941.157494963292}, 2033: {'year': 2033, 'revenue': 252875.4781032879, 'utility_expense': 98255.82451699338, 'energy_opex': 71695.757206699345, 'electricity_opex': 1175.9341789481377, 'gas_opex': 6640.9586307853224, 'oil_opex': 43378.864396965881, 'water_opex': 20500.0, 'other_utility': 26560.067310294038, 'non_utility_expense': 142636.91693346857, 'net_non_energy_opex': 169196.98424376262, 'total_opex': 240892.74145046197, 'noi': 11982.73665282593}, 2034: {'year': 2034, 'revenue': 256016.90883927097, 'utility_expense': 99597.294490472937, 'energy_opex': 72707.2758048057, 'electricity_opex': 1199.1695873801598, 'gas_opex': 6772.2131729990733, 'oil_opex': 44235.89304442647, 'water_opex': 20500.0, 'other_utility': 26890.018685667244, 'non_utility_expense': 144408.8720407868, 'net_non_energy_opex': 171298.89072645406, 'total_opex': 244006.16653125978, 'noi': 12010.742308011191}, 2035: {'year': 2035, 'revenue': 259197.36505587003, 'utility_expense': 100970.45619606454, 'energy_opex': 73746.387203013161, 'electricity_opex': 1223.0386652944458, 'gas_opex': 6907.0434291160136, 'oil_opex': 45116.305108602697, 'water_opex': 20500.0, 'other_utility': 27224.068993051384, 'non_utility_expense': 146202.83985680525, 'net_non_energy_opex': 173426.90884985664, 'total_opex': 247173.29605286982, 'noi': 12024.069003000215}, 2036: {'year': 2036, 'revenue': 262417.3315602527, 'utility_expense': 102375.48550524657, 'energy_opex': 74813.216352437652, 'electricity_opex': 1247.5443683668141, 'gas_opex': 7045.4681428808135, 'oil_opex': 46020.203841190028, 'water_opex': 20500.0, 'other_utility': 27562.269152808924, 'non_utility_expense': 148019.09384180643, 'net_non_energy_opex': 175581.36299461537, 'total_opex': 250394.57934705302, 'noi': 12022.752213199681}}, {'year': 2017, 'revenue': 207546.681495995, 'utility_expense': 79261.074976421922, 'energy_opex': 57461.990810933145, 'electricity_opex': 849.02230670593224, 'gas_opex': 4795.4503391884955, 'oil_opex': 31317.518165038713, 'water_opex': 20500.0, 'other_utility': 21799.08416548877, 'non_utility_expense': 117068.76044449637, 'net_non_energy_opex': 138867.84460998513, 'total_opex': 196329.83542091827, 'noi': 11216.846075076726}, {'year': None, 'revenue': 200333.33333333334, 'utility_expense': 77500.0, 'energy_opex': 56458.549647682405, 'electricity_opex': 825.88635362928574, 'gas_opex': 4662.7027797267865, 'oil_opex': 30469.960514326336, 'water_opex': 20500.0, 'other_utility': 21041.450352317588, 'non_utility_expense': 113000.00000000001, 'net_non_energy_opex': 134041.4503523176, 'total_opex': 190500.0, 'noi': 9833.333333333343}, 0.01242283656582921) \ No newline at end of file -- GitLab From f0bfb85706fd0bcfe7eb30dc38c34bb552847c68 Mon Sep 17 00:00:00 2001 From: Sarey Hamarneh Date: Thu, 25 May 2017 14:00:37 -0400 Subject: [PATCH 13/37] Replace and add raw liability --- bpfin/financials/scenario.py | 76 ++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 24 deletions(-) diff --git a/bpfin/financials/scenario.py b/bpfin/financials/scenario.py index e733cae..a0ac98a 100644 --- a/bpfin/financials/scenario.py +++ b/bpfin/financials/scenario.py @@ -3,6 +3,8 @@ from bpfin.financials.saving import Saving_Overview from bpfin.financials.loan import Loan_List from bpfin.lib.other import add_year_dictionary, divide_dscr_dict, min_none_list from bpfin.utilbills.bill_lib import form_bill_year, annualizing_projection +from bpfin.financials.liability import final_liability_dict + # may delete from here after sample built # from bpfin.financials.financial_lib import Income_Statement_Table, Balance_Sheet_Table # from bpfin.tests.testdata import sample_data as db @@ -31,8 +33,9 @@ class Scenario(): scheduled_loan_list (list): list of Loan objects. Store financing plans for each loan option """ + def __init__(self, analysis_date, commission_date, construction_cost, - bill_overview, prior_annual_bill_table, other_debt_service, + bill_overview, prior_annual_bill_table, raw_liability_dict, prior_income_statement_table, prior_balance_sheet_table, loan_input_list): """ @@ -48,7 +51,7 @@ class Scenario(): construction_cost (float): project cost, estimated or quoted bill_overview (dictionary): original annual bill input, with blank cells, for 4 utility_types prior_annual_bill_table (dictionary): annual bill, for 4 utility_types, proir to saving - other_debt_service (dict): dictionary of debt service values per year + raw_liability_dict (dict): dictionary of liability values per year prior_income_statement_table (object): complete Income_Statement_Table, with prior_saving projection prior_balance_sheet_table (object): complete Balance_Sheet_Table, with prior_saving projection loan_input_list (list): list of dictionary of loan basic terms. @@ -60,7 +63,6 @@ class Scenario(): To Do: bill_overview -> raw_bill_table prior_annual_bill_table -> raw_annual_bill_table - other_debt_service -> raw_liability prior_income_statement_table -> raw_income_table prior_balance_sheet_table -> raw_cash_input loan_input_list -> loan_input_list @@ -70,10 +72,14 @@ class Scenario(): self.construction_cost = copy.deepcopy(construction_cost) self.prior_annual_bill_table = copy.deepcopy(prior_annual_bill_table) - self.other_debt_service = copy.deepcopy(other_debt_service) - - self.prior_income_statement_table = copy.deepcopy(prior_income_statement_table) - self.prior_balance_sheet_table = copy.deepcopy(prior_balance_sheet_table) + self.other_debt_service = final_liability_dict( + analysis_date['proforma_start'], raw_liability_dict, + analysis_date['proforma_duration']) + + self.prior_income_statement_table = copy.deepcopy( + prior_income_statement_table) + self.prior_balance_sheet_table = copy.deepcopy( + prior_balance_sheet_table) self.post_income_statement_table = None self.post_balance_sheet_table = None @@ -129,9 +135,12 @@ class Scenario(): full_saving_dict=full_saving_dict) # generate post_saving income_statement_table object - post_annual_bill_table = copy.deepcopy(self.saving_overview.get_post_annual_bill_table()) - post_income_statement_table = copy.deepcopy(self.prior_income_statement_table) - post_income_statement_table.project(growth_rate_flag, self.analysis_date, post_annual_bill_table) + post_annual_bill_table = copy.deepcopy( + self.saving_overview.get_post_annual_bill_table()) + post_income_statement_table = copy.deepcopy( + self.prior_income_statement_table) + post_income_statement_table.project( + growth_rate_flag, self.analysis_date, post_annual_bill_table) self.post_income_statement_table = post_income_statement_table # generate post_saving balance_sheet_table object @@ -174,14 +183,16 @@ class Scenario(): """ proforma_year = form_bill_year(self.analysis_date['proforma_start'], self.analysis_date['proforma_duration']) - post_annual_bill_table = copy.deepcopy(self.saving_overview.get_post_annual_bill_table()) + post_annual_bill_table = copy.deepcopy( + self.saving_overview.get_post_annual_bill_table()) utility_type_list = ['electricity', 'gas', 'oil', 'water'] post_energy_bill = {} for year in proforma_year: current_total_energy_bill = 0 for utility_type in utility_type_list: - current_total_energy_bill += post_annual_bill_table[utility_type][year] + current_total_energy_bill += post_annual_bill_table[ + utility_type][year] post_energy_bill[year] = current_total_energy_bill return post_energy_bill @@ -198,7 +209,8 @@ class Scenario(): annual_debt_service_dict[year] = 0 for current_loan in copy.deepcopy(self.scheduled_loan_list): - current_loan_annual = annualizing_projection(current_loan.terms, current_loan.debt_service_due) + current_loan_annual = annualizing_projection( + current_loan.terms, current_loan.debt_service_due) for year in proforma_year: if year in current_loan_annual: annual_debt_service_dict[year] += current_loan_annual[year] @@ -218,10 +230,12 @@ class Scenario(): graph_dict = {} proforma_bill = copy.deepcopy(self.get_post_energy_bill()) annual_debt_service = copy.deepcopy(self.get_annual_debt_service()) - prior_annual_bill = copy.deepcopy(self.prior_income_statement_table.get_total_energy_dict()) + prior_annual_bill = copy.deepcopy( + self.prior_income_statement_table.get_total_energy_dict()) net_saving_dict = {} for year in prior_annual_bill: - net_saving_dict[year] = prior_annual_bill[year] - proforma_bill[year] - annual_debt_service[year] + net_saving_dict[ + year] = prior_annual_bill[year] - proforma_bill[year] - annual_debt_service[year] graph_dict = { 'energy_expenses': proforma_bill, 'total_loan': annual_debt_service, @@ -238,15 +252,20 @@ class Scenario(): dscr_dict = {'noi_dscr': noi_dscr, 'cash_dscr': cash_dscr, 'saving_dscr': saving_dscr} noi_dscr = {2017: 1.17, 2018: 1.98, ...} """ - noi_dict = copy.deepcopy(self.post_income_statement_table.get_noi_dict()) - cash_dict = copy.deepcopy(self.post_balance_sheet_table.get_cash_dict()) + noi_dict = copy.deepcopy( + self.post_income_statement_table.get_noi_dict()) + cash_dict = copy.deepcopy( + self.post_balance_sheet_table.get_cash_dict()) debt_dict = copy.deepcopy(self.get_annual_debt_service()) savings_dict = {} utility_type_list = ['electricity', 'gas', 'oil', 'water'] for utility_type in utility_type_list: savings_dict = add_year_dictionary( - savings_dict, copy.deepcopy(self.saving_overview.get_utility_annual_saving_charge(utility_type))) + savings_dict, + copy.deepcopy( + self.saving_overview.get_utility_annual_saving_charge( + utility_type))) dscr_dict = {} dscr_dict['noi_dscr'] = divide_dscr_dict(noi_dict, debt_dict) @@ -271,12 +290,21 @@ class Scenario(): dscr_dict = self.get_dscr() economics_overview = {} economics_overview['estimated_cost'] = self.construction_cost - economics_overview['overall_saving'] = self.saving_overview.get_total_saving_percent() - economics_overview['first_year_saving'] = self.saving_overview.get_total_first_year_saving() - economics_overview['simple_payback'] = self.saving_overview.get_simple_payback(self.construction_cost) - economics_overview['min_saving_dscr'] = min_none_list(dscr_dict['saving_dscr'].values()) - economics_overview['min_noi_dscr'] = min_none_list(dscr_dict['noi_dscr'].values()) - economics_overview['min_cash_dscr'] = min_none_list(dscr_dict['cash_dscr'].values()) + economics_overview[ + 'overall_saving'] = self.saving_overview.get_total_saving_percent( + ) + economics_overview[ + 'first_year_saving'] = self.saving_overview.get_total_first_year_saving( + ) + economics_overview[ + 'simple_payback'] = self.saving_overview.get_simple_payback( + self.construction_cost) + economics_overview['min_saving_dscr'] = min_none_list( + dscr_dict['saving_dscr'].values()) + economics_overview['min_noi_dscr'] = min_none_list( + dscr_dict['noi_dscr'].values()) + economics_overview['min_cash_dscr'] = min_none_list( + dscr_dict['cash_dscr'].values()) return economics_overview -- GitLab From d01f0f6de85286ba0dc4dafd00baa224223bf4d2 Mon Sep 17 00:00:00 2001 From: Sarey Hamarneh Date: Thu, 25 May 2017 14:24:24 -0400 Subject: [PATCH 14/37] Replace prior_income_statement_table --- bpfin/financials/scenario.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/bpfin/financials/scenario.py b/bpfin/financials/scenario.py index a0ac98a..db38494 100644 --- a/bpfin/financials/scenario.py +++ b/bpfin/financials/scenario.py @@ -4,6 +4,7 @@ from bpfin.financials.loan import Loan_List from bpfin.lib.other import add_year_dictionary, divide_dscr_dict, min_none_list from bpfin.utilbills.bill_lib import form_bill_year, annualizing_projection from bpfin.financials.liability import final_liability_dict +from bpfin.financials.financial_income import prior_income_statement_table # may delete from here after sample built # from bpfin.financials.financial_lib import Income_Statement_Table, Balance_Sheet_Table @@ -36,8 +37,9 @@ class Scenario(): def __init__(self, analysis_date, commission_date, construction_cost, bill_overview, prior_annual_bill_table, raw_liability_dict, - prior_income_statement_table, prior_balance_sheet_table, - loan_input_list): + prior_income_statement_table, raw_income_input, + raw_bill_table, raw_annual_bill_table, growth_rate_flag, + prior_balance_sheet_table, loan_input_list): """ Initiate Scenario object. Pass in historical bill, income statement and balance sheet data @@ -75,9 +77,9 @@ class Scenario(): self.other_debt_service = final_liability_dict( analysis_date['proforma_start'], raw_liability_dict, analysis_date['proforma_duration']) - - self.prior_income_statement_table = copy.deepcopy( - prior_income_statement_table) + self.prior_income_statement_table = prior_income_statement_table( + raw_income_input, raw_bill_table, raw_annual_bill_table, + analysis_date, growth_rate_flag) self.prior_balance_sheet_table = copy.deepcopy( prior_balance_sheet_table) self.post_income_statement_table = None -- GitLab From 8751b3ad7bb57ca48b4459816bd0ceb20be33d0b Mon Sep 17 00:00:00 2001 From: Sarey Hamarneh Date: Thu, 25 May 2017 14:30:48 -0400 Subject: [PATCH 15/37] Space --- bpfin/financials/scenario.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bpfin/financials/scenario.py b/bpfin/financials/scenario.py index db38494..88ffebd 100644 --- a/bpfin/financials/scenario.py +++ b/bpfin/financials/scenario.py @@ -74,14 +74,18 @@ class Scenario(): self.construction_cost = copy.deepcopy(construction_cost) self.prior_annual_bill_table = copy.deepcopy(prior_annual_bill_table) + self.other_debt_service = final_liability_dict( analysis_date['proforma_start'], raw_liability_dict, analysis_date['proforma_duration']) + self.prior_income_statement_table = prior_income_statement_table( raw_income_input, raw_bill_table, raw_annual_bill_table, analysis_date, growth_rate_flag) + self.prior_balance_sheet_table = copy.deepcopy( prior_balance_sheet_table) + self.post_income_statement_table = None self.post_balance_sheet_table = None -- GitLab From f50bb405351915fd89283f979b0170bddda9e5f7 Mon Sep 17 00:00:00 2001 From: Sarey Hamarneh Date: Fri, 26 May 2017 11:28:58 -0400 Subject: [PATCH 16/37] Balance sheet fix for intermediate variable reference --- bpfin/financials/scenario.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/bpfin/financials/scenario.py b/bpfin/financials/scenario.py index 88ffebd..6947f63 100644 --- a/bpfin/financials/scenario.py +++ b/bpfin/financials/scenario.py @@ -4,7 +4,8 @@ from bpfin.financials.loan import Loan_List from bpfin.lib.other import add_year_dictionary, divide_dscr_dict, min_none_list from bpfin.utilbills.bill_lib import form_bill_year, annualizing_projection from bpfin.financials.liability import final_liability_dict -from bpfin.financials.financial_income import prior_income_statement_table +from bpfin.financials.balance_sheet_projection import balance_sheet_projection +from bpfin.lib.back_end_call import prior_income_statement_table # may delete from here after sample built # from bpfin.financials.financial_lib import Income_Statement_Table, Balance_Sheet_Table @@ -39,7 +40,8 @@ class Scenario(): bill_overview, prior_annual_bill_table, raw_liability_dict, prior_income_statement_table, raw_income_input, raw_bill_table, raw_annual_bill_table, growth_rate_flag, - prior_balance_sheet_table, loan_input_list): + cash_balance, liability, noi, prior_balance_sheet_table, + loan_input_list): """ Initiate Scenario object. Pass in historical bill, income statement and balance sheet data @@ -83,8 +85,11 @@ class Scenario(): raw_income_input, raw_bill_table, raw_annual_bill_table, analysis_date, growth_rate_flag) - self.prior_balance_sheet_table = copy.deepcopy( - prior_balance_sheet_table) + self.prior_balance_sheet_table = balance_sheet_projection( + cash_balance, liability, noi, analysis_date) + + # self.prior_balance_sheet_table = copy.deepcopy( + # prior_balance_sheet_table) self.post_income_statement_table = None self.post_balance_sheet_table = None -- GitLab From ac5b8f85172fda4ccf8493857d4d7654e0c3d3ab Mon Sep 17 00:00:00 2001 From: Sarey Hamarneh Date: Fri, 26 May 2017 12:29:06 -0400 Subject: [PATCH 17/37] Add old stuff back as comments --- bpfin/financials/scenario.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bpfin/financials/scenario.py b/bpfin/financials/scenario.py index 6947f63..00a1c0a 100644 --- a/bpfin/financials/scenario.py +++ b/bpfin/financials/scenario.py @@ -81,15 +81,18 @@ class Scenario(): analysis_date['proforma_start'], raw_liability_dict, analysis_date['proforma_duration']) + # self.other_debt_service = copy.deepcopy(other_debt_service) + self.prior_income_statement_table = prior_income_statement_table( raw_income_input, raw_bill_table, raw_annual_bill_table, analysis_date, growth_rate_flag) + # self.prior_income_statement_table = copy.deepcopy(prior_income_statement_table) + self.prior_balance_sheet_table = balance_sheet_projection( cash_balance, liability, noi, analysis_date) - # self.prior_balance_sheet_table = copy.deepcopy( - # prior_balance_sheet_table) + # self.prior_balance_sheet_table = copy.deepcopy(prior_balance_sheet_table) self.post_income_statement_table = None self.post_balance_sheet_table = None -- GitLab From bad5f255735fe06312bf0961b53205f1d5d340fa Mon Sep 17 00:00:00 2001 From: Sarey Hamarneh Date: Fri, 26 May 2017 13:10:19 -0400 Subject: [PATCH 18/37] Fix prior_balance_sheet --- bpfin/financials/scenario.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bpfin/financials/scenario.py b/bpfin/financials/scenario.py index 00a1c0a..fc35146 100644 --- a/bpfin/financials/scenario.py +++ b/bpfin/financials/scenario.py @@ -6,6 +6,7 @@ from bpfin.utilbills.bill_lib import form_bill_year, annualizing_projection from bpfin.financials.liability import final_liability_dict from bpfin.financials.balance_sheet_projection import balance_sheet_projection from bpfin.lib.back_end_call import prior_income_statement_table +from bpfin.financials.financial_income import Income_Statement_Table # may delete from here after sample built # from bpfin.financials.financial_lib import Income_Statement_Table, Balance_Sheet_Table @@ -90,7 +91,7 @@ class Scenario(): # self.prior_income_statement_table = copy.deepcopy(prior_income_statement_table) self.prior_balance_sheet_table = balance_sheet_projection( - cash_balance, liability, noi, analysis_date) + cash_balance, liability, Income_Statement_Table.get_noi_dict, analysis_date) # self.prior_balance_sheet_table = copy.deepcopy(prior_balance_sheet_table) -- GitLab From 7849aeb8fdd6483d8b0a3610512c6e9bd56f83fb Mon Sep 17 00:00:00 2001 From: Sarey Hamarneh Date: Fri, 26 May 2017 13:12:12 -0400 Subject: [PATCH 19/37] Edits --- bpfin/financials/scenario.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bpfin/financials/scenario.py b/bpfin/financials/scenario.py index fc35146..c8974f7 100644 --- a/bpfin/financials/scenario.py +++ b/bpfin/financials/scenario.py @@ -68,14 +68,14 @@ class Scenario(): To Do: bill_overview -> raw_bill_table prior_annual_bill_table -> raw_annual_bill_table - prior_income_statement_table -> raw_income_table - prior_balance_sheet_table -> raw_cash_input loan_input_list -> loan_input_list """ self.analysis_date = analysis_date self.commission_date = copy.deepcopy(commission_date) self.construction_cost = copy.deepcopy(construction_cost) + # self.bill_overview = [...] + self.prior_annual_bill_table = copy.deepcopy(prior_annual_bill_table) self.other_debt_service = final_liability_dict( -- GitLab From 6c296aa0c1d5a84b06f31e9685527b2df8ae3da3 Mon Sep 17 00:00:00 2001 From: Sarey Hamarneh Date: Wed, 31 May 2017 10:45:31 -0400 Subject: [PATCH 20/37] Changes --- bpfin/financials/financial_income.py | 153 ++++++++++++++++++--------- bpfin/financials/scenario.py | 41 +++---- bpfin/lib/back_end_call.py | 85 ++++++++++++--- 3 files changed, 188 insertions(+), 91 deletions(-) diff --git a/bpfin/financials/financial_income.py b/bpfin/financials/financial_income.py index 572cf4f..5340d33 100644 --- a/bpfin/financials/financial_income.py +++ b/bpfin/financials/financial_income.py @@ -130,7 +130,8 @@ class Income_Statement_Next(): with input of last year data, income statement characters, and projected annual bill """ - def __init__(self, year, last_revenue, growth_rate_flag, characters, annual_bill_table): + def __init__(self, year, last_revenue, growth_rate_flag, characters, + annual_bill_table): """ Calculation is done in initiation. Args: @@ -171,7 +172,8 @@ class Income_Statement_Next(): self.water_opex = annual_bill_table['water'][self.year] self.energy_opex = self.electricity_opex + self.gas_opex + self.oil_opex + self.water_opex self.other_utility = self.revenue * characters['other_utility_percent'] - self.non_utility_expense = self.revenue * characters['non_utility_expense_percent'] + self.non_utility_expense = self.revenue * characters[ + 'non_utility_expense_percent'] self.utility_expense = self.energy_opex + self.other_utility self.net_non_energy_opex = self.other_utility + self.non_utility_expense self.total_opex = self.energy_opex + self.net_non_energy_opex @@ -224,12 +226,15 @@ class Income_Statement_Table(): annual_bill_table years should cover proforma years """ if not validate_empty(raw_income_input): - raise ValueError('Income_Statement_Table-init() raw_income_input is empty') + raise ValueError( + 'Income_Statement_Table-init() raw_income_input is empty') if not validate_empty(analysis_date): - raise ValueError('Income_Statement_Table-init() analysis_date is empty') + raise ValueError( + 'Income_Statement_Table-init() analysis_date is empty') # validate annual_bill_table if not validate_annual_bill_table(annual_bill_table): - raise ValueError('Income_Statement_Table-init() annual_bill_table is invalid') + raise ValueError( + 'Income_Statement_Table-init() annual_bill_table is invalid') # validate raw_income_input self.hist_start_year = None @@ -245,7 +250,8 @@ class Income_Statement_Table(): for year in raw_income_input.keys(): current_income_statement = Income_Statement() - current_income_statement.put_hist(year, raw_income_input[year], annual_bill_table) + current_income_statement.put_hist(year, raw_income_input[year], + annual_bill_table) self.hist_table.append(current_income_statement) sorted_income_hist_year = sorted(raw_income_input) @@ -266,7 +272,8 @@ class Income_Statement_Table(): self.other_utility_percent = other_utility_sum / revenue_sum self.non_utility_expense_percent = non_utility_expense_sum / revenue_sum - self.revenue_average = revenue_sum / (self.hist_end_year - self.hist_start_year + 1) + self.revenue_average = revenue_sum / ( + self.hist_end_year - self.hist_start_year + 1) self.table = self.hist_table self.characters = { @@ -316,19 +323,32 @@ class Income_Statement_Table(): hist_table_dict = {} for current_income_statement in self.hist_table: hist_table_dict[current_income_statement.year] = { - 'year': current_income_statement.year, - 'revenue': current_income_statement.revenue, - 'utility_expense': current_income_statement.utility_expense, - 'energy_opex': current_income_statement.energy_opex, - 'electricity_opex': current_income_statement.electricity_opex, - 'gas_opex': current_income_statement.gas_opex, - 'oil_opex': current_income_statement.oil_opex, - 'water_opex': current_income_statement.water_opex, - 'other_utility': current_income_statement.other_utility, - 'non_utility_expense': current_income_statement.non_utility_expense, - 'net_non_energy_opex': current_income_statement.net_non_energy_opex, - 'total_opex': current_income_statement.total_opex, - 'noi': current_income_statement.noi + 'year': + current_income_statement.year, + 'revenue': + current_income_statement.revenue, + 'utility_expense': + current_income_statement.utility_expense, + 'energy_opex': + current_income_statement.energy_opex, + 'electricity_opex': + current_income_statement.electricity_opex, + 'gas_opex': + current_income_statement.gas_opex, + 'oil_opex': + current_income_statement.oil_opex, + 'water_opex': + current_income_statement.water_opex, + 'other_utility': + current_income_statement.other_utility, + 'non_utility_expense': + current_income_statement.non_utility_expense, + 'net_non_energy_opex': + current_income_statement.net_non_energy_opex, + 'total_opex': + current_income_statement.total_opex, + 'noi': + current_income_statement.noi } return hist_table_dict @@ -361,7 +381,8 @@ class Income_Statement_Table(): 'water': mean(list(i_s.water_opex for i_s in self.hist_table)) } - current_income_statement.put_average(average_revenue, annual_bills, self.characters) + current_income_statement.put_average(average_revenue, annual_bills, + self.characters) return convert_income_statement_class(current_income_statement) def get_single_year(self, year): @@ -377,19 +398,32 @@ class Income_Statement_Table(): for current_income_statement in self.table: if current_income_statement.year == year: return { - 'year': current_income_statement.year, - 'revenue': current_income_statement.revenue, - 'utility_expense': current_income_statement.utility_expense, - 'energy_opex': current_income_statement.energy_opex, - 'electricity_opex': current_income_statement.electricity_opex, - 'gas_opex': current_income_statement.gas_opex, - 'oil_opex': current_income_statement.oil_opex, - 'water_opex': current_income_statement.water_opex, - 'other_utility': current_income_statement.other_utility, - 'non_utility_expense': current_income_statement.non_utility_expense, - 'net_non_energy_opex': current_income_statement.net_non_energy_opex, - 'total_opex': current_income_statement.total_opex, - 'noi': current_income_statement.noi + 'year': + current_income_statement.year, + 'revenue': + current_income_statement.revenue, + 'utility_expense': + current_income_statement.utility_expense, + 'energy_opex': + current_income_statement.energy_opex, + 'electricity_opex': + current_income_statement.electricity_opex, + 'gas_opex': + current_income_statement.gas_opex, + 'oil_opex': + current_income_statement.oil_opex, + 'water_opex': + current_income_statement.water_opex, + 'other_utility': + current_income_statement.other_utility, + 'non_utility_expense': + current_income_statement.non_utility_expense, + 'net_non_energy_opex': + current_income_statement.net_non_energy_opex, + 'total_opex': + current_income_statement.total_opex, + 'noi': + current_income_statement.noi } return None @@ -430,29 +464,50 @@ class Income_Statement_Table(): table_dict = {} for current_income_statement in self.table: table_dict[current_income_statement.year] = { - 'year': current_income_statement.year, - 'revenue': current_income_statement.revenue, - 'utility_expense': current_income_statement.utility_expense, - 'energy_opex': current_income_statement.energy_opex, - 'electricity_opex': current_income_statement.electricity_opex, - 'gas_opex': current_income_statement.gas_opex, - 'oil_opex': current_income_statement.oil_opex, - 'water_opex': current_income_statement.water_opex, - 'other_utility': current_income_statement.other_utility, - 'non_utility_expense': current_income_statement.non_utility_expense, - 'net_non_energy_opex': current_income_statement.net_non_energy_opex, - 'total_opex': current_income_statement.total_opex, - 'noi': current_income_statement.noi + 'year': + current_income_statement.year, + 'revenue': + current_income_statement.revenue, + 'utility_expense': + current_income_statement.utility_expense, + 'energy_opex': + current_income_statement.energy_opex, + 'electricity_opex': + current_income_statement.electricity_opex, + 'gas_opex': + current_income_statement.gas_opex, + 'oil_opex': + current_income_statement.oil_opex, + 'water_opex': + current_income_statement.water_opex, + 'other_utility': + current_income_statement.other_utility, + 'non_utility_expense': + current_income_statement.non_utility_expense, + 'net_non_energy_opex': + current_income_statement.net_non_energy_opex, + 'total_opex': + current_income_statement.total_opex, + 'noi': + current_income_statement.noi } return table_dict def get_total_energy_dict(self): total_energy_dict = {} for current_income_statement in self.table: - total_energy_dict[ - current_income_statement.year] = current_income_statement.energy_opex + total_energy_dict[current_income_statement. + year] = current_income_statement.energy_opex return total_energy_dict + def get_utility_opex_dict(self, energy_utility_opex): + bill_dict = {} + for current_income_statement in self.table: + bill_dict[current_income_statement. + year] = current_income_statement.energy_utility_opex + + return bill_dict + def validate_growth_rate_flag(growth_rate_flag): """ diff --git a/bpfin/financials/scenario.py b/bpfin/financials/scenario.py index c8974f7..2a41fe0 100644 --- a/bpfin/financials/scenario.py +++ b/bpfin/financials/scenario.py @@ -38,11 +38,9 @@ class Scenario(): """ def __init__(self, analysis_date, commission_date, construction_cost, - bill_overview, prior_annual_bill_table, raw_liability_dict, - prior_income_statement_table, raw_income_input, - raw_bill_table, raw_annual_bill_table, growth_rate_flag, - cash_balance, liability, noi, prior_balance_sheet_table, - loan_input_list): + bill_overview, prior_income_statement_table, + other_debt_service, raw_annual_bill_table, growth_rate_flag, + prior_balance_sheet_table, loan_input_list): """ Initiate Scenario object. Pass in historical bill, income statement and balance sheet data @@ -56,7 +54,6 @@ class Scenario(): construction_cost (float): project cost, estimated or quoted bill_overview (dictionary): original annual bill input, with blank cells, for 4 utility_types prior_annual_bill_table (dictionary): annual bill, for 4 utility_types, proir to saving - raw_liability_dict (dict): dictionary of liability values per year prior_income_statement_table (object): complete Income_Statement_Table, with prior_saving projection prior_balance_sheet_table (object): complete Balance_Sheet_Table, with prior_saving projection loan_input_list (list): list of dictionary of loan basic terms. @@ -67,46 +64,38 @@ class Scenario(): list[1] = boolean value, False == from manual input, True == from scraper To Do: bill_overview -> raw_bill_table - prior_annual_bill_table -> raw_annual_bill_table + # prior_annual_bill_table -> raw_annual_bill_table loan_input_list -> loan_input_list """ self.analysis_date = analysis_date self.commission_date = copy.deepcopy(commission_date) self.construction_cost = copy.deepcopy(construction_cost) - # self.bill_overview = [...] + self.other_debt_service = copy.deepcopy(other_debt_service) - self.prior_annual_bill_table = copy.deepcopy(prior_annual_bill_table) + self.bill_overview = copy.deepcopy(bill_overview) - self.other_debt_service = final_liability_dict( - analysis_date['proforma_start'], raw_liability_dict, - analysis_date['proforma_duration']) + # self.prior_annual_bill_table = copy.deepcopy(prior_annual_bill_table) + self.raw_annual_bill_table = copy.deepcopy(raw_annual_bill_table) - # self.other_debt_service = copy.deepcopy(other_debt_service) - - self.prior_income_statement_table = prior_income_statement_table( - raw_income_input, raw_bill_table, raw_annual_bill_table, - analysis_date, growth_rate_flag) - - # self.prior_income_statement_table = copy.deepcopy(prior_income_statement_table) - - self.prior_balance_sheet_table = balance_sheet_projection( - cash_balance, liability, Income_Statement_Table.get_noi_dict, analysis_date) - - # self.prior_balance_sheet_table = copy.deepcopy(prior_balance_sheet_table) + self.prior_income_statement_table = copy.deepcopy( + prior_income_statement_table) + self.prior_balance_sheet_table = copy.deepcopy( + prior_balance_sheet_table) self.post_income_statement_table = None self.post_balance_sheet_table = None self.loan_list = Loan_List(loan_input_list) + self.saving_overview = Saving_Overview( bill_overview=copy.deepcopy(bill_overview), - prior_annual_bill_table=copy.deepcopy(prior_annual_bill_table), + prior_annual_bill_table=copy.deepcopy(raw_annual_bill_table), analysis_date=copy.deepcopy(analysis_date), commissioning_date=copy.deepcopy(commission_date)) self.scheduled_loan_list = None - def prelim_anlaysis(self, prior_month_bill, percent_saving_dict, + def prelim_analysis(self, prior_month_bill, percent_saving_dict, full_saving_dict, growth_rate_flag, req_dscr, customer_preference): """ diff --git a/bpfin/lib/back_end_call.py b/bpfin/lib/back_end_call.py index 79d67c8..057b928 100644 --- a/bpfin/lib/back_end_call.py +++ b/bpfin/lib/back_end_call.py @@ -2,7 +2,10 @@ from bpfin.lib.other import UTILITY_TYPE_LIST from bpfin.utilbills.bill import Bill # from bpfin.financials.financial_lib import Income_Statement_Table from bpfin.financials.financial_income import Income_Statement_Table +from bpfin.financials.financial_lib import Balance_Sheet_Table +from bpfin.financials.scenario import Scenario from bpfin.tests.testdata import feature_data as db +from bpfin.financials.liability import final_liability_dict import pprint @@ -55,9 +58,11 @@ def monthly_bill(raw_bill_table, analysis_date): To Do: from utilbills.bill.py merge form_prior_month_bill(), and delete that one """ if not raw_bill_table: - raise ValueError('Bill_Overview - monthly_bill has empty raw_bill_table') + raise ValueError( + 'Bill_Overview - monthly_bill has empty raw_bill_table') if not analysis_date: - raise ValueError('Bill_Overview - monthly_bill has empty analysis_date') + raise ValueError( + 'Bill_Overview - monthly_bill has empty analysis_date') bill_overview_dict = {} manual_input_dict = {} for utility in UTILITY_TYPE_LIST: @@ -69,9 +74,11 @@ def monthly_bill(raw_bill_table, analysis_date): bill_overview_dict[utility] = current_bill.get_annual_bill() manual_input_dict[utility] = current_bill.get_manual_input() if len(bill_overview_dict.keys()) != len(UTILITY_TYPE_LIST): - raise ValueError('Bill_Overview - monthly_bill has incomplete result in bill_overview_dict') + raise ValueError( + 'Bill_Overview - monthly_bill has incomplete result in bill_overview_dict' + ) # if len(manual_input_dict.keys()) != len(UTILITY_TYPE_LIST): - # raise ValueError('Bill_Overview - monthly_bill has incomplete result in manual_input_dict') + # raise ValueError('Bill_Overview - monthly_bill has incomplete result in manual_input_dict') # return bill_overview_dict, manual_input_dict return bill_overview_dict @@ -102,9 +109,11 @@ def annual_bill(raw_bill_table, raw_annual_bill_table, analysis_date): 'water': dict of water_bill} """ if not raw_bill_table: - raise ValueError('Bill_Overview - annual_bill has empty raw_bill_table') + raise ValueError( + 'Bill_Overview - annual_bill has empty raw_bill_table') if not raw_annual_bill_table: - raise ValueError('Bill_Overview - annual_bill has empty raw_annual_bill_table') + raise ValueError( + 'Bill_Overview - annual_bill has empty raw_annual_bill_table') if not analysis_date: raise ValueError('Bill_Overview - annual_bill has empty analysis_date') @@ -119,16 +128,15 @@ def annual_bill(raw_bill_table, raw_annual_bill_table, analysis_date): current_bill.put_annual_bill(raw_annual_bill_table[utility]) annual_bill_table[utility] = current_bill.get_annual_bill() if len(annual_bill_table.keys()) != len(UTILITY_TYPE_LIST): - raise ValueError('Bill_Overview - annual_bill has incomplete result in annual_bill_table') + raise ValueError( + 'Bill_Overview - annual_bill has incomplete result in annual_bill_table' + ) return annual_bill_table -def prior_income_statement_table( - raw_income_input, - raw_bill_table, - raw_annual_bill_table, - analysis_date, - growth_rate_flag): +def prior_income_statement_table(raw_income_input, raw_bill_table, + raw_annual_bill_table, analysis_date, + growth_rate_flag): """ Take in prior-annual_bill_table, and raw inputs of income statements Generate historical income statement, calculate its characters including CAGR and other percent ratios @@ -171,17 +179,62 @@ def prior_income_statement_table( prior_income = {2014: {'year': 2014, 'revenue': 100.0, ..., 'not': 5.0}, ... , 2016:{}} """ - annual_bill_table = annual_bill(raw_bill_table, raw_annual_bill_table, analysis_date) - income_table = Income_Statement_Table(raw_income_input, annual_bill_table, analysis_date) + annual_bill_table = annual_bill(raw_bill_table, raw_annual_bill_table, + analysis_date) + income_table = Income_Statement_Table(raw_income_input, annual_bill_table, + analysis_date) income_table.project(growth_rate_flag, annual_bill_table) prior_income = income_table.get_full_income_table() - next_year_income = income_table.get_single_year(income_table.hist_end_year + 1) + next_year_income = income_table.get_single_year(income_table.hist_end_year + + 1) average_income = income_table.get_average() historical_cagr = income_table.get_cagr() return prior_income, next_year_income, average_income, historical_cagr +def prelim_scenario(analysis_date, commission_date, construction_cost, + growth_rate_flag, bill_overview, raw_liability_dictionary, + balance_sheet_input, raw_income_input, + raw_annual_bill_table, loan_input_list, prior_month_bill, + percent_saving_dict, full_saving_dict, growth_rate_flag, + req_dscr, customer_preference): + + liability = final_liability_dict(analysis_date['proforma_start'], + raw_liability_dictionary, + analysis_date['proforma_duration']) + + prior_bs = Balance_Sheet_Table(balance_sheet_input) + + prior_is = Income_Statement_Table(raw_income_input, annual_bill_table, + analysis_date) + + scenario_ob = Scenario(analysis_date, commission_date, construction_cost, + bill_overview, prior_income_statement_table, + raw_annual_bill_table, growth_rate_flag, prior_bs, + loan_input_list) + + savings_scenario_ob = scenario_ob.prelim_analysis( + prior_month_bill, percent_saving_dict, full_saving_dict, + growth_rate_flag, req_dscr, customer_preference) + + post_is = Income_Statement_Table( + raw_income_input, scenario_ob.get_post_energy_bill, analysis_date) + + # Define raw_annual_bill_table as a "get" of prior_bill + # Define raw_bill_table as a "get" of prior_bill + # Delete prior_annual_bill_table + + return { + 'prior_energy_bill': 'hello', + 'prior_income_statement': 'hello', + 'prior_balance_sheet': 'hello', + 'post_energy_bill': 'hello', + 'post_income_statement': 'hello', + 'post_balance_sheet': 'hello', + } + + # **** ugly test **** # print(db.raw_bill_table) # print('\nmonthly_bill =', monthly_bill(db.raw_bill_table, db.analysis_date)) -- GitLab From e03707663bdb7cdfb48ba5bae940b1ba2631a888 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Wed, 31 May 2017 12:49:27 -0400 Subject: [PATCH 21/37] Refactor saving and its test files. Refactor back_end_call funcs --- bpfin/financials/saving.py | 34 +-- bpfin/financials/scenario.py | 8 +- bpfin/lib/back_end_call.py | 105 ++++---- bpfin/tests/test_financials/test_saving.py | 289 +++++++++++---------- bpfin/tests/test_lib/test_back_end_call.py | 4 +- bpfin/tests/testdata/feature_data.py | 117 +++++++++ bpfin/utilbills/bill.py | 116 ++++----- 7 files changed, 402 insertions(+), 271 deletions(-) diff --git a/bpfin/financials/saving.py b/bpfin/financials/saving.py index 96d80c8..e42c4c5 100644 --- a/bpfin/financials/saving.py +++ b/bpfin/financials/saving.py @@ -5,7 +5,8 @@ from bpfin.utilbills.bill_lib import annualizing_projection from bpfin.utilbills.bill_lib import form_year_calendar from bpfin.utilbills.bill_lib import form_bill_calendar from bpfin.utilbills.bill_post_proj_rough import bill_post_proj_rough -from bpfin.tests.testdata import sample_data as db +from bpfin.tests.testdata import feature_data as db +from bpfin.lib.back_end_call import monthly_bill class Saving(): @@ -218,7 +219,7 @@ class Saving_Overview(): def __init__( self, - bill_overview, + manual_input_dict, prior_annual_bill_table, analysis_date, # consider to replace it with proforma_date commissioning_date): @@ -228,23 +229,26 @@ class Saving_Overview(): Generate Saving objects, pro-forma date period Args: - bill_overview (dictionary): original annual bill input, with blank cells, for 4 utility_types + # bill_overview (dictionary): original annual bill input, with blank cells, for 4 utility_types + manual_input_dict (dictionary): dict of boolean values, indicating manual_input status of each utility prior_annual_bill_table (dictionary): dict of dict of annual charge, for 4 utility_types analysis_date (dictionary): proforma's starting date and the years of proforma commissioning_date (date): the date that construction work finished, saving starts at NEXT month Description: - bill_overview (dictionary): dict of a list, - list[0] = dict of annual bill, allow some year missing, for 4 utility_types - list[1] = boolean value, False == from manual input, True == from scraper + # bill_overview (dictionary): dict of a list, + # list[0] = dict of annual bill, allow some year missing, for 4 utility_types + # list[1] = boolean value, False == from manual input, True == from scraper + manual_input_dict = { 'electricity': False, 'gas': False, 'oil': False, 'water': True} prior_annual_bill_table = {'electricity': electricity_bill, 'oil': oil_bill, ...} electricity_bill = {2014: 100, 2015:200, ...} """ - self.manual_input_dict = { - 'electricity': bill_overview['electricity'][1], - 'gas': bill_overview['gas'][1], - 'oil': bill_overview['oil'][1], - 'water': bill_overview['water'][1]} + # self.manual_input_dict = { + # 'electricity': bill_overview['electricity'][1], + # 'gas': bill_overview['gas'][1], + # 'oil': bill_overview['oil'][1], + # 'water': bill_overview['water'][1]} + self.manual_input_dict = manual_input_dict self.prior_annual_bill_table = prior_annual_bill_table self.proforma_date = form_bill_calendar(analysis_date['proforma_start'], analysis_date['proforma_duration'])[1] self.commissioning_date = commissioning_date @@ -370,12 +374,10 @@ class Saving_Overview(): return saving_dict - - - # **** ugly test **** -# so = Saving_Overview(db.bill_overview, db.bill_overview_organized, db.analysis_date, datetime.date(2017, 3, 14)) -# so.put_saving(db.prior_month_bill, db.percent_saving_dict, db.full_saving_dict) +# so = Saving_Overview(db.manual_input_dict, db.prior_annual_bill, db.analysis_date, datetime.date(2017, 3, 14)) +# prior_monthly_bill = monthly_bill(db.raw_bill_table, db.analysis_date)[2] +# so.put_saving(prior_monthly_bill, db.percent_saving_dict, db.full_saving_dict) # print('\n first_year_dollar_saving =', so.get_total_first_year_saving()) # print('\n simple payback =', so.get_simple_payback(50000)) diff --git a/bpfin/financials/scenario.py b/bpfin/financials/scenario.py index 2a41fe0..3ef60bd 100644 --- a/bpfin/financials/scenario.py +++ b/bpfin/financials/scenario.py @@ -38,7 +38,7 @@ class Scenario(): """ def __init__(self, analysis_date, commission_date, construction_cost, - bill_overview, prior_income_statement_table, + manual_input_dict, prior_income_statement_table, other_debt_service, raw_annual_bill_table, growth_rate_flag, prior_balance_sheet_table, loan_input_list): """ @@ -52,7 +52,7 @@ class Scenario(): analysis_date (dictionary): proforma's starting date and the years of proforma commission_date (date): the date that construction work finished, saving starts at NEXT month construction_cost (float): project cost, estimated or quoted - bill_overview (dictionary): original annual bill input, with blank cells, for 4 utility_types + manual_input_dict (dictionary): dict of boolean values, indicating manual_input status of each utility prior_annual_bill_table (dictionary): annual bill, for 4 utility_types, proir to saving prior_income_statement_table (object): complete Income_Statement_Table, with prior_saving projection prior_balance_sheet_table (object): complete Balance_Sheet_Table, with prior_saving projection @@ -73,7 +73,7 @@ class Scenario(): self.other_debt_service = copy.deepcopy(other_debt_service) - self.bill_overview = copy.deepcopy(bill_overview) + self.manual_input_dict = copy.deepcopy(manual_input_dict) # self.prior_annual_bill_table = copy.deepcopy(prior_annual_bill_table) self.raw_annual_bill_table = copy.deepcopy(raw_annual_bill_table) @@ -89,7 +89,7 @@ class Scenario(): self.loan_list = Loan_List(loan_input_list) self.saving_overview = Saving_Overview( - bill_overview=copy.deepcopy(bill_overview), + manual_input_dict=copy.deepcopy(manual_input_dict), prior_annual_bill_table=copy.deepcopy(raw_annual_bill_table), analysis_date=copy.deepcopy(analysis_date), commissioning_date=copy.deepcopy(commission_date)) diff --git a/bpfin/lib/back_end_call.py b/bpfin/lib/back_end_call.py index 057b928..2d10f52 100644 --- a/bpfin/lib/back_end_call.py +++ b/bpfin/lib/back_end_call.py @@ -3,7 +3,7 @@ from bpfin.utilbills.bill import Bill # from bpfin.financials.financial_lib import Income_Statement_Table from bpfin.financials.financial_income import Income_Statement_Table from bpfin.financials.financial_lib import Balance_Sheet_Table -from bpfin.financials.scenario import Scenario +# from bpfin.financials.scenario import Scenario from bpfin.tests.testdata import feature_data as db from bpfin.financials.liability import final_liability_dict import pprint @@ -57,14 +57,15 @@ def monthly_bill(raw_bill_table, analysis_date): To Do: from utilbills.bill.py merge form_prior_month_bill(), and delete that one """ - if not raw_bill_table: - raise ValueError( - 'Bill_Overview - monthly_bill has empty raw_bill_table') + # if not raw_bill_table: + # raise ValueError( + # 'Bill_Overview - monthly_bill has empty raw_bill_table') if not analysis_date: raise ValueError( 'Bill_Overview - monthly_bill has empty analysis_date') bill_overview_dict = {} manual_input_dict = {} + prior_month_bill_dict = {} for utility in UTILITY_TYPE_LIST: current_bill = Bill(utility, analysis_date) if utility in raw_bill_table: @@ -73,14 +74,17 @@ def monthly_bill(raw_bill_table, analysis_date): current_bill.put_month_bill(None) bill_overview_dict[utility] = current_bill.get_annual_bill() manual_input_dict[utility] = current_bill.get_manual_input() + prior_month_bill_dict[utility] = current_bill.get_prior_proj_rough() if len(bill_overview_dict.keys()) != len(UTILITY_TYPE_LIST): raise ValueError( 'Bill_Overview - monthly_bill has incomplete result in bill_overview_dict' ) - # if len(manual_input_dict.keys()) != len(UTILITY_TYPE_LIST): - # raise ValueError('Bill_Overview - monthly_bill has incomplete result in manual_input_dict') - # return bill_overview_dict, manual_input_dict - return bill_overview_dict + if len(manual_input_dict.keys()) != len(UTILITY_TYPE_LIST): + raise ValueError('Bill_Overview - monthly_bill has incomplete result in manual_input_dict') + if len(prior_month_bill_dict.keys()) != len(UTILITY_TYPE_LIST): + raise ValueError('Bill_Overview - monthly_bill has incomplete result of monthly_proj') + return bill_overview_dict, manual_input_dict, prior_month_bill_dict + # return bill_overview_dict def annual_bill(raw_bill_table, raw_annual_bill_table, analysis_date): @@ -108,16 +112,17 @@ def annual_bill(raw_bill_table, raw_annual_bill_table, analysis_date): 'gas': dict of gas_bill, 'water': dict of water_bill} """ - if not raw_bill_table: - raise ValueError( - 'Bill_Overview - annual_bill has empty raw_bill_table') - if not raw_annual_bill_table: - raise ValueError( - 'Bill_Overview - annual_bill has empty raw_annual_bill_table') + # if not raw_bill_table: + # raise ValueError( + # 'Bill_Overview - annual_bill has empty raw_bill_table') + # if not raw_annual_bill_table: + # raise ValueError( + # 'Bill_Overview - annual_bill has empty raw_annual_bill_table') if not analysis_date: raise ValueError('Bill_Overview - annual_bill has empty analysis_date') annual_bill_table = {} + manual_input_dict = {} for utility in UTILITY_TYPE_LIST: current_bill = Bill(utility, analysis_date) if utility in raw_bill_table: @@ -127,11 +132,15 @@ def annual_bill(raw_bill_table, raw_annual_bill_table, analysis_date): if utility in raw_annual_bill_table: current_bill.put_annual_bill(raw_annual_bill_table[utility]) annual_bill_table[utility] = current_bill.get_annual_bill() + manual_input_dict[utility] = current_bill.get_manual_input() if len(annual_bill_table.keys()) != len(UTILITY_TYPE_LIST): raise ValueError( 'Bill_Overview - annual_bill has incomplete result in annual_bill_table' ) - return annual_bill_table + if len(manual_input_dict.keys()) != len(UTILITY_TYPE_LIST): + raise ValueError('Bill_Overview - monthly_bill has incomplete result in manual_input_dict') + return annual_bill_table, manual_input_dict + # return annual_bill_table def prior_income_statement_table(raw_income_input, raw_bill_table, @@ -180,7 +189,7 @@ def prior_income_statement_table(raw_income_input, raw_bill_table, """ annual_bill_table = annual_bill(raw_bill_table, raw_annual_bill_table, - analysis_date) + analysis_date)[0] income_table = Income_Statement_Table(raw_income_input, annual_bill_table, analysis_date) income_table.project(growth_rate_flag, annual_bill_table) @@ -193,46 +202,46 @@ def prior_income_statement_table(raw_income_input, raw_bill_table, return prior_income, next_year_income, average_income, historical_cagr -def prelim_scenario(analysis_date, commission_date, construction_cost, - growth_rate_flag, bill_overview, raw_liability_dictionary, - balance_sheet_input, raw_income_input, - raw_annual_bill_table, loan_input_list, prior_month_bill, - percent_saving_dict, full_saving_dict, growth_rate_flag, - req_dscr, customer_preference): +# def prelim_scenario(analysis_date, commission_date, construction_cost, +# growth_rate_flag, bill_overview, raw_liability_dictionary, +# balance_sheet_input, raw_income_input, +# raw_annual_bill_table, loan_input_list, prior_month_bill, +# percent_saving_dict, full_saving_dict, growth_rate_flag, +# req_dscr, customer_preference): - liability = final_liability_dict(analysis_date['proforma_start'], - raw_liability_dictionary, - analysis_date['proforma_duration']) +# liability = final_liability_dict(analysis_date['proforma_start'], +# raw_liability_dictionary, +# analysis_date['proforma_duration']) - prior_bs = Balance_Sheet_Table(balance_sheet_input) +# prior_bs = Balance_Sheet_Table(balance_sheet_input) - prior_is = Income_Statement_Table(raw_income_input, annual_bill_table, - analysis_date) +# prior_is = Income_Statement_Table(raw_income_input, annual_bill_table, +# analysis_date) - scenario_ob = Scenario(analysis_date, commission_date, construction_cost, - bill_overview, prior_income_statement_table, - raw_annual_bill_table, growth_rate_flag, prior_bs, - loan_input_list) +# scenario_ob = Scenario(analysis_date, commission_date, construction_cost, +# bill_overview, prior_income_statement_table, +# raw_annual_bill_table, growth_rate_flag, prior_bs, +# loan_input_list) - savings_scenario_ob = scenario_ob.prelim_analysis( - prior_month_bill, percent_saving_dict, full_saving_dict, - growth_rate_flag, req_dscr, customer_preference) +# savings_scenario_ob = scenario_ob.prelim_analysis( +# prior_month_bill, percent_saving_dict, full_saving_dict, +# growth_rate_flag, req_dscr, customer_preference) - post_is = Income_Statement_Table( - raw_income_input, scenario_ob.get_post_energy_bill, analysis_date) +# post_is = Income_Statement_Table( +# raw_income_input, scenario_ob.get_post_energy_bill, analysis_date) - # Define raw_annual_bill_table as a "get" of prior_bill - # Define raw_bill_table as a "get" of prior_bill - # Delete prior_annual_bill_table +# # Define raw_annual_bill_table as a "get" of prior_bill +# # Define raw_bill_table as a "get" of prior_bill +# # Delete prior_annual_bill_table - return { - 'prior_energy_bill': 'hello', - 'prior_income_statement': 'hello', - 'prior_balance_sheet': 'hello', - 'post_energy_bill': 'hello', - 'post_income_statement': 'hello', - 'post_balance_sheet': 'hello', - } +# return { +# 'prior_energy_bill': 'hello', +# 'prior_income_statement': 'hello', +# 'prior_balance_sheet': 'hello', +# 'post_energy_bill': 'hello', +# 'post_income_statement': 'hello', +# 'post_balance_sheet': 'hello', +# } # **** ugly test **** diff --git a/bpfin/tests/test_financials/test_saving.py b/bpfin/tests/test_financials/test_saving.py index 1681c81..5c67b7b 100644 --- a/bpfin/tests/test_financials/test_saving.py +++ b/bpfin/tests/test_financials/test_saving.py @@ -1,143 +1,146 @@ -# import datetime -# from bpfin.financials.saving import Saving -# from bpfin.financials.saving import Saving_Overview -# from bpfin.tests.testdata import sample_data as db - - -# def test_Saving_put_monthly_proforma(): -# input_proforma_date = [ -# datetime.date(2017, 1, 31), -# datetime.date(2017, 2, 28), -# datetime.date(2017, 3, 31), -# datetime.date(2017, 4, 30), -# datetime.date(2017, 5, 31), -# datetime.date(2017, 6, 30), -# datetime.date(2017, 7, 31), -# datetime.date(2017, 8, 31), -# datetime.date(2017, 9, 30), -# datetime.date(2017, 10, 31), -# datetime.date(2017, 11, 30), -# datetime.date(2017, 12, 31)] -# input_commissioning_date = datetime.date(2017, 3, 14) -# input_prior_charge = [100] * 12 -# input_post_charge = [100, 90, 80, 70, 60, 50, 40, 30, 40, 50, 60, 70] -# input_prior_usage = [15] * 12 -# input_post_usage = [10, 9, 8, 7, 6, 5, 4, 3, 4, 5, 6, 7] -# output_saving = [0, 0, 0, 30, 40, 50, 60, 70, 60, 50, 40, 30] -# output_charge = [100, 100, 100, 70, 60, 50, 40, 30, 40, 50, 60, 70] -# output_overall_saving = 0.4777777777777778 - -# elec_saving = Saving(False, input_commissioning_date, input_proforma_date) -# elec_saving.put_monthly_proforma(input_prior_usage, input_post_usage, input_prior_charge, input_post_charge) -# result_saving = elec_saving.get_proforma_saving_charge() -# result_charge = elec_saving.get_proforma_charge() - -# assert output_saving == result_saving -# assert output_charge == result_charge -# assert elec_saving.get_first_year_saving_charge() == 430 -# assert elec_saving.get_annual_proforma_charge() == {2017: 770} -# assert elec_saving.get_percent_saving() == output_overall_saving - - -# def test_Saving_put_annual_proforma(): -# input_proforma_date = [ -# datetime.date(2017, 1, 31), -# datetime.date(2017, 2, 28), -# datetime.date(2017, 3, 31), -# datetime.date(2017, 4, 30), -# datetime.date(2017, 5, 31), -# datetime.date(2017, 6, 30), -# datetime.date(2017, 7, 31), -# datetime.date(2017, 8, 31), -# datetime.date(2017, 9, 30), -# datetime.date(2017, 10, 31), -# datetime.date(2017, 11, 30), -# datetime.date(2017, 12, 31), -# datetime.date(2018, 1, 31), -# datetime.date(2018, 2, 28), -# datetime.date(2018, 3, 31), -# datetime.date(2018, 4, 30), -# datetime.date(2018, 5, 31), -# datetime.date(2018, 6, 30), -# datetime.date(2018, 7, 31), -# datetime.date(2018, 8, 31), -# datetime.date(2018, 9, 30), -# datetime.date(2018, 10, 31), -# datetime.date(2018, 11, 30), -# datetime.date(2018, 12, 31)] -# input_commissioning_date = datetime.date(2017, 3, 14) -# input_annual_charge = {2017: 100, 2018: 100} -# input_percent_saving = 0.20 -# output_first_year_saving_charge = 20 -# output_annual_proforma_charge = {2017: 85, 2018: 80} -# output_overall_saving = 0.20 - -# elec_saving = Saving(True, input_commissioning_date, input_proforma_date) -# elec_saving.put_annual_proforma(input_annual_charge, input_percent_saving) - -# result_first_year_saving_charge = elec_saving.get_first_year_saving_charge() -# result_annual_proforma_charge = elec_saving.get_annual_proforma_charge() -# result_overall_saving = elec_saving.get_percent_saving() - -# assert result_first_year_saving_charge == output_first_year_saving_charge -# assert result_annual_proforma_charge == output_annual_proforma_charge -# assert result_overall_saving == output_overall_saving - - -# def test_Saving_Overview(): -# input_bill_overview = db.bill_overview -# input_prior_annual_bill_table = db.bill_overview_organized -# input_analysis_date = db.analysis_date -# input_commissioning_date = datetime.date(2017, 3, 14) - -# input_prior_month_bill = db.prior_month_bill -# input_percent_saving_dict = db.percent_saving_dict -# input_full_saving_dict = db.full_saving_dict - -# output_first_year_saving = 10479.289108609044 -# output_simple_payback = 4.771316019797902 -# output_total_saving_percent = 0.2624163752635955 -# output_electricity_annual_saving_charge = { -# 2012: 0.0, -# 2013: 0.0, -# 2014: 0.0, -# 2015: 0.0, -# 2016: 0.0, -# 2017: 6757.962319199603, -# 2018: 8846.241570765102, -# 2019: 9062.872690379008, -# 2020: 9275.049342309605, -# 2021: 9471.770503408214, -# 2022: 9650.941259401636, -# 2023: 9826.981304138018, -# 2024: 10007.019419843535, -# 2025: 10193.107315596935, -# 2026: 10393.916746353145, -# 2027: 10609.979647682601, -# 2028: 10831.30886589543, -# 2029: 11052.82469894908, -# 2030: 11274.416949194128, -# 2031: 11496.666332412671, -# 2032: 11721.576357170983, -# 2033: 11951.64472721766, -# 2034: 12187.887773507784, -# 2035: 12430.56386264111, -# 2036: 12679.70824604718 -# } -# output_post_annual_bill_table = db.bill_overview_post - -# saving_overview = Saving_Overview( -# input_bill_overview, input_prior_annual_bill_table, input_analysis_date, input_commissioning_date) -# saving_overview.put_saving(input_prior_month_bill, input_percent_saving_dict, input_full_saving_dict) - -# result_first_year_saving = saving_overview.get_total_first_year_saving() -# result_simple_payback = saving_overview.get_simple_payback(50000) -# result_total_saving_percent = saving_overview.get_total_saving_percent() -# result_electricity_annual_saving_charge = saving_overview.get_utility_annual_saving_charge('electricity') -# result_post_annual_bill_table = saving_overview.get_post_annual_bill_table() - -# assert result_first_year_saving == output_first_year_saving -# assert result_simple_payback == output_simple_payback -# assert result_total_saving_percent == output_total_saving_percent -# assert result_electricity_annual_saving_charge == output_electricity_annual_saving_charge -# assert result_post_annual_bill_table == output_post_annual_bill_table +import datetime +from bpfin.financials.saving import Saving +from bpfin.financials.saving import Saving_Overview +# from bpfin.lib.back_end_call import monthly_bill +from bpfin.tests.testdata import feature_data as db + + +def test_Saving_put_monthly_proforma(): + input_proforma_date = [ + datetime.date(2017, 1, 31), + datetime.date(2017, 2, 28), + datetime.date(2017, 3, 31), + datetime.date(2017, 4, 30), + datetime.date(2017, 5, 31), + datetime.date(2017, 6, 30), + datetime.date(2017, 7, 31), + datetime.date(2017, 8, 31), + datetime.date(2017, 9, 30), + datetime.date(2017, 10, 31), + datetime.date(2017, 11, 30), + datetime.date(2017, 12, 31)] + input_commissioning_date = datetime.date(2017, 3, 14) + input_prior_charge = [100] * 12 + input_post_charge = [100, 90, 80, 70, 60, 50, 40, 30, 40, 50, 60, 70] + input_prior_usage = [15] * 12 + input_post_usage = [10, 9, 8, 7, 6, 5, 4, 3, 4, 5, 6, 7] + output_saving = [0, 0, 0, 30, 40, 50, 60, 70, 60, 50, 40, 30] + output_charge = [100, 100, 100, 70, 60, 50, 40, 30, 40, 50, 60, 70] + output_overall_saving = 0.4777777777777778 + + elec_saving = Saving(False, input_commissioning_date, input_proforma_date) + elec_saving.put_monthly_proforma(input_prior_usage, input_post_usage, input_prior_charge, input_post_charge) + result_saving = elec_saving.get_proforma_saving_charge() + result_charge = elec_saving.get_proforma_charge() + + assert output_saving == result_saving + assert output_charge == result_charge + assert elec_saving.get_first_year_saving_charge() == 430 + assert elec_saving.get_annual_proforma_charge() == {2017: 770} + assert elec_saving.get_percent_saving() == output_overall_saving + + +def test_Saving_put_annual_proforma(): + input_proforma_date = [ + datetime.date(2017, 1, 31), + datetime.date(2017, 2, 28), + datetime.date(2017, 3, 31), + datetime.date(2017, 4, 30), + datetime.date(2017, 5, 31), + datetime.date(2017, 6, 30), + datetime.date(2017, 7, 31), + datetime.date(2017, 8, 31), + datetime.date(2017, 9, 30), + datetime.date(2017, 10, 31), + datetime.date(2017, 11, 30), + datetime.date(2017, 12, 31), + datetime.date(2018, 1, 31), + datetime.date(2018, 2, 28), + datetime.date(2018, 3, 31), + datetime.date(2018, 4, 30), + datetime.date(2018, 5, 31), + datetime.date(2018, 6, 30), + datetime.date(2018, 7, 31), + datetime.date(2018, 8, 31), + datetime.date(2018, 9, 30), + datetime.date(2018, 10, 31), + datetime.date(2018, 11, 30), + datetime.date(2018, 12, 31)] + input_commissioning_date = datetime.date(2017, 3, 14) + input_annual_charge = {2017: 100, 2018: 100} + input_percent_saving = 0.20 + output_first_year_saving_charge = 20 + output_annual_proforma_charge = {2017: 85, 2018: 80} + output_overall_saving = 0.20 + + elec_saving = Saving(True, input_commissioning_date, input_proforma_date) + elec_saving.put_annual_proforma(input_annual_charge, input_percent_saving) + + result_first_year_saving_charge = elec_saving.get_first_year_saving_charge() + result_annual_proforma_charge = elec_saving.get_annual_proforma_charge() + result_overall_saving = elec_saving.get_percent_saving() + + assert result_first_year_saving_charge == output_first_year_saving_charge + assert result_annual_proforma_charge == output_annual_proforma_charge + assert result_overall_saving == output_overall_saving + + +def test_Saving_Overview(): + from bpfin.lib.back_end_call import monthly_bill + input_manual_input_dict = db.manual_input_dict + input_prior_annual_bill_table = db.prior_annual_bill + input_analysis_date = db.analysis_date + input_commissioning_date = datetime.date(2017, 3, 14) + + prior_monthly_bill = monthly_bill(db.raw_bill_table, input_analysis_date)[2] + input_prior_month_bill = prior_monthly_bill + input_percent_saving_dict = db.percent_saving_dict + input_full_saving_dict = db.full_saving_dict + + output_first_year_saving = 28667.507248011731 + output_simple_payback = 1.744134903932668 + output_total_saving_percent = 0.46592312148565274 + output_electricity_annual_saving_charge = { + 2012: 0.0, + 2013: 0.0, + 2014: 0.0, + 2015: 0.0, + 2016: 0.0, + 2017: 162.81610514235683, + 2018: 217.5358446704256, + 2019: 222.88552019426197, + 2020: 228.10636614744124, + 2021: 232.98501809818731, + 2022: 237.40591301201312, + 2023: 241.73930274248983, + 2024: 246.16421306765812, + 2025: 250.73914770469878, + 2026: 255.65734234845252, + 2027: 260.96499723521435, + 2028: 266.41256515482269, + 2029: 271.86744883912024, + 2030: 277.3223130868306, + 2031: 282.79361546555913, + 2032: 288.32598130207771, + 2033: 293.98354473703466, + 2034: 299.79239684503989, + 2035: 305.75966632361155, + 2036: 311.88609209170363 + } + output_post_annual_bill_table = db.post_annual_bill + + saving_overview = Saving_Overview( + input_manual_input_dict, input_prior_annual_bill_table, input_analysis_date, input_commissioning_date) + saving_overview.put_saving(input_prior_month_bill, input_percent_saving_dict, input_full_saving_dict) + + result_first_year_saving = saving_overview.get_total_first_year_saving() + result_simple_payback = saving_overview.get_simple_payback(50000) + result_total_saving_percent = saving_overview.get_total_saving_percent() + result_electricity_annual_saving_charge = saving_overview.get_utility_annual_saving_charge('electricity') + result_post_annual_bill_table = saving_overview.get_post_annual_bill_table() + + assert result_first_year_saving == output_first_year_saving + assert result_simple_payback == output_simple_payback + assert result_total_saving_percent == output_total_saving_percent + assert result_electricity_annual_saving_charge == output_electricity_annual_saving_charge + assert result_post_annual_bill_table == output_post_annual_bill_table diff --git a/bpfin/tests/test_lib/test_back_end_call.py b/bpfin/tests/test_lib/test_back_end_call.py index 9fb324e..8e305d5 100644 --- a/bpfin/tests/test_lib/test_back_end_call.py +++ b/bpfin/tests/test_lib/test_back_end_call.py @@ -9,13 +9,13 @@ def test_monthly_bill(): 'gas': db.prior_annual_bill['gas'], 'oil': db.prior_annual_bill['oil'], 'water': None} - result_dict = monthly_bill(db.raw_bill_table, db.analysis_date) + result_dict = monthly_bill(db.raw_bill_table, db.analysis_date)[0] assert output_dict == result_dict def test_annual_bill(): output_dict = db.prior_annual_bill - result_dict = annual_bill(db.raw_bill_table, db.raw_annual_bill_table, db.analysis_date) + result_dict = annual_bill(db.raw_bill_table, db.raw_annual_bill_table, db.analysis_date)[0] assert output_dict == result_dict diff --git a/bpfin/tests/testdata/feature_data.py b/bpfin/tests/testdata/feature_data.py index d73d0e9..3d753f9 100644 --- a/bpfin/tests/testdata/feature_data.py +++ b/bpfin/tests/testdata/feature_data.py @@ -187,6 +187,13 @@ raw_annual_bill_table = { 'water': annual_bill_water } +manual_input_dict = { + 'electricity': False, + 'gas': False, + 'oil': False, + 'water': True +} + # raw income_statement # raw_income_input = { # 2014: { @@ -662,3 +669,113 @@ average_income = { historical_cagr = 0.01242283656582921 +post_annual_bill = { + 'electricity': { + 2012: 792.50603354980865, + 2013: 806.56436875723125, + 2014: 819.06930386346062, + 2015: 825.90552345154924, + 2016: 832.68423357284746, + 2017: 686.20620156357541, + 2018: 652.60753401127647, + 2019: 668.65656058278626, + 2020: 684.31909844232337, + 2021: 698.95505429456193, + 2022: 712.21773903603901, + 2023: 725.21790822746937, + 2024: 738.49263920297415, + 2025: 752.21744311409691, + 2026: 766.97202704535766, + 2027: 782.89499170564352, + 2028: 799.23769546446829, + 2029: 815.60234651736118, + 2030: 831.96693926049227, + 2031: 848.38084639667738, + 2032: 864.97794390623244, + 2033: 881.95063421110308, + 2034: 899.37719053511989, + 2035: 917.27899897083421, + 2036: 935.65827627511044 + }, + 'gas': { + 2012: 4475.7823032289816, + 2013: 4554.23035844273, + 2014: 4625.0674743716318, + 2015: 4661.2913287497577, + 2016: 4701.7495360589701, + 2017: 4432.0076232344945, + 2018: 4423.5254490869947, + 2019: 4531.9841870009604, + 2020: 4638.1014926798862, + 2021: 4736.7144862254645, + 2022: 4826.3966258774726, + 2023: 4914.4509463389886, + 2024: 5004.464208195408, + 2025: 5097.5100806960108, + 2026: 5197.806308051101, + 2027: 5305.815088487584, + 2028: 5416.5189006350965, + 2029: 5527.3321785283542, + 2030: 5638.1724314894936, + 2031: 5749.3429359253232, + 2032: 5861.8180348360929, + 2033: 5976.8627677067898, + 2034: 6094.9918556991643, + 2035: 6216.3390862044125, + 2036: 6340.9213285927335 + }, + 'oil': { + 2012: 29234.099384206329, + 2013: 29755.35937994433, + 2014: 30216.03963037725, + 2015: 30474.979346602693, + 2016: 30718.862565999072, + 2017: 12627.09017823708, + 2018: 6419.1621798475999, + 2019: 6577.2261556354169, + 2020: 6731.3149742677442, + 2021: 6875.647441982087, + 2022: 7006.2363859201232, + 2023: 7134.1482918180382, + 2024: 7264.6995109238669, + 2025: 7399.6890601343712, + 2026: 7544.6385648710675, + 2027: 7701.2100708983235, + 2028: 7862.0040486757889, + 2029: 8023.0384939259939, + 2030: 8184.0552554064707, + 2031: 8345.5596014863549, + 2032: 8508.8264836249164, + 2033: 8675.7728793931728, + 2034: 8847.1786088852914, + 2035: 9023.2610217205365, + 2036: 9204.0407682380028 + }, + 'water': { + 2012: 20500.0, + 2013: 20500.0, + 2014: 20000, + 2015: 20500, + 2016: 21000, + 2017: 20500.0, + 2018: 20500.0, + 2019: 20500.0, + 2020: 20500.0, + 2021: 20500.0, + 2022: 20500.0, + 2023: 20500.0, + 2024: 20500.0, + 2025: 20500.0, + 2026: 20500.0, + 2027: 20500.0, + 2028: 20500.0, + 2029: 20500.0, + 2030: 20500.0, + 2031: 20500.0, + 2032: 20500.0, + 2033: 20500.0, + 2034: 20500.0, + 2035: 20500.0, + 2036: 20500.0 + } +} diff --git a/bpfin/utilbills/bill.py b/bpfin/utilbills/bill.py index 71716ff..0f4593f 100644 --- a/bpfin/utilbills/bill.py +++ b/bpfin/utilbills/bill.py @@ -206,63 +206,63 @@ class Bill(): return self.is_manual_input -def form_prior_month_bill(raw_bill_table, analysis_date, is_rough): - """ - Calculate and generate monthly energy bill for utilities that has available bills - !!! Should be merged to back_end_call.monthly_bill() !! - - Args: - raw_bill_table (dictionary): dict of dict of raw_bill. Keys are utility types - analysis_date (dictionary): proforma's starting date and the years of proforma - is_rough (boolean): True == apply rough daily estimation, False == apply regression estimation - - Return: - prior_month_bill: dictionary, dict of dict of lists, projected energy bill for prior_saving - - Description: - raw_bill_table contains 4 utilities raw bill data. Each utility is a dictionary with 4 keys. - Each utility can be None. See below for detail - raw_bill_table = { - 'electricity': { - 'date_from': list of date, - 'date_to', list of date, - 'usage', list of float, - 'charge', list of float}, - 'gas': None, - 'oil': None, - 'water': None - } - - prior_month_bill = { - 'electricity': { - 'date_from': list, - 'date_to': list, - 'usage': list, - 'charge': list, - 'price': list}, - 'gas': None, - 'oil': None, - 'water': None} - """ - if not raw_bill_table: - raise ValueError('form_prior_month_bill - has empty raw_bill_table') - if not analysis_date: - raise ValueError('form_prior_month_bill - has empty analysis_date') - - prior_month_bill_dict = {} - for utility in UTILITY_TYPE_LIST: - if is_rough: - current_bill = Bill(utility, analysis_date) - if utility in raw_bill_table: - current_bill.put_month_bill(raw_bill_table[utility]) - else: - current_bill.put_month_bill(None) - prior_month_bill_dict[utility] = current_bill.get_prior_proj_rough() - else: - pass - if len(prior_month_bill_dict.keys()) != len(UTILITY_TYPE_LIST): - raise ValueError('form_prior_month_bill - has incomplete result') - return prior_month_bill_dict +# def form_prior_month_bill(raw_bill_table, analysis_date, is_rough): +# """ +# Calculate and generate monthly energy bill for utilities that has available bills +# !!! Should be merged to back_end_call.monthly_bill() !! + +# Args: +# raw_bill_table (dictionary): dict of dict of raw_bill. Keys are utility types +# analysis_date (dictionary): proforma's starting date and the years of proforma +# is_rough (boolean): True == apply rough daily estimation, False == apply regression estimation + +# Return: +# prior_month_bill: dictionary, dict of dict of lists, projected energy bill for prior_saving + +# Description: +# raw_bill_table contains 4 utilities raw bill data. Each utility is a dictionary with 4 keys. +# Each utility can be None. See below for detail +# raw_bill_table = { +# 'electricity': { +# 'date_from': list of date, +# 'date_to', list of date, +# 'usage', list of float, +# 'charge', list of float}, +# 'gas': None, +# 'oil': None, +# 'water': None +# } + +# prior_month_bill = { +# 'electricity': { +# 'date_from': list, +# 'date_to': list, +# 'usage': list, +# 'charge': list, +# 'price': list}, +# 'gas': None, +# 'oil': None, +# 'water': None} +# """ +# if not raw_bill_table: +# raise ValueError('form_prior_month_bill - has empty raw_bill_table') +# if not analysis_date: +# raise ValueError('form_prior_month_bill - has empty analysis_date') + +# prior_month_bill_dict = {} +# for utility in UTILITY_TYPE_LIST: +# if is_rough: +# current_bill = Bill(utility, analysis_date) +# if utility in raw_bill_table: +# current_bill.put_month_bill(raw_bill_table[utility]) +# else: +# current_bill.put_month_bill(None) +# prior_month_bill_dict[utility] = current_bill.get_prior_proj_rough() +# else: +# pass +# if len(prior_month_bill_dict.keys()) != len(UTILITY_TYPE_LIST): +# raise ValueError('form_prior_month_bill - has incomplete result') +# return prior_month_bill_dict # class Bill_Table(): # """ @@ -352,4 +352,4 @@ def form_prior_month_bill(raw_bill_table, analysis_date, is_rough): # print(bill_table.get_annual_bill_table()) -print(form_prior_month_bill(db.raw_bill_table, db.analysis_date, True)) +# print(form_prior_month_bill(db.raw_bill_table, db.analysis_date, True)) -- GitLab From 790a0defedf58a50474dabf47ee424ef85eda52d Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Wed, 31 May 2017 16:23:50 -0400 Subject: [PATCH 22/37] improve scenario and back_end_call --- bpfin/financials/scenario.py | 4 -- bpfin/lib/back_end_call.py | 81 ++++++++++++++++++------------------ 2 files changed, 41 insertions(+), 44 deletions(-) diff --git a/bpfin/financials/scenario.py b/bpfin/financials/scenario.py index 3ef60bd..70bbd11 100644 --- a/bpfin/financials/scenario.py +++ b/bpfin/financials/scenario.py @@ -62,10 +62,6 @@ class Scenario(): bill_overview (dictionary): dict of a list, list[0] = dict of annual bill, allow some year missing, for 4 utility_types list[1] = boolean value, False == from manual input, True == from scraper - To Do: - bill_overview -> raw_bill_table - # prior_annual_bill_table -> raw_annual_bill_table - loan_input_list -> loan_input_list """ self.analysis_date = analysis_date self.commission_date = copy.deepcopy(commission_date) diff --git a/bpfin/lib/back_end_call.py b/bpfin/lib/back_end_call.py index 2d10f52..3991e07 100644 --- a/bpfin/lib/back_end_call.py +++ b/bpfin/lib/back_end_call.py @@ -202,46 +202,47 @@ def prior_income_statement_table(raw_income_input, raw_bill_table, return prior_income, next_year_income, average_income, historical_cagr -# def prelim_scenario(analysis_date, commission_date, construction_cost, -# growth_rate_flag, bill_overview, raw_liability_dictionary, -# balance_sheet_input, raw_income_input, -# raw_annual_bill_table, loan_input_list, prior_month_bill, -# percent_saving_dict, full_saving_dict, growth_rate_flag, -# req_dscr, customer_preference): - -# liability = final_liability_dict(analysis_date['proforma_start'], -# raw_liability_dictionary, -# analysis_date['proforma_duration']) - -# prior_bs = Balance_Sheet_Table(balance_sheet_input) - -# prior_is = Income_Statement_Table(raw_income_input, annual_bill_table, -# analysis_date) - -# scenario_ob = Scenario(analysis_date, commission_date, construction_cost, -# bill_overview, prior_income_statement_table, -# raw_annual_bill_table, growth_rate_flag, prior_bs, -# loan_input_list) - -# savings_scenario_ob = scenario_ob.prelim_analysis( -# prior_month_bill, percent_saving_dict, full_saving_dict, -# growth_rate_flag, req_dscr, customer_preference) - -# post_is = Income_Statement_Table( -# raw_income_input, scenario_ob.get_post_energy_bill, analysis_date) - -# # Define raw_annual_bill_table as a "get" of prior_bill -# # Define raw_bill_table as a "get" of prior_bill -# # Delete prior_annual_bill_table - -# return { -# 'prior_energy_bill': 'hello', -# 'prior_income_statement': 'hello', -# 'prior_balance_sheet': 'hello', -# 'post_energy_bill': 'hello', -# 'post_income_statement': 'hello', -# 'post_balance_sheet': 'hello', -# } +def prelim_scenario(analysis_date, commission_date, construction_cost, + raw_bill_table, raw_annual_bill_table, + raw_income_input, growth_rate_flag, + raw_liability_input, raw_cash_balance, + raw_loan_input_list, + percent_saving_dict, full_saving_dict, + req_dscr, customer_preference): + + liability = final_liability_dict(analysis_date['proforma_start'], + raw_liability_dictionary, + analysis_date['proforma_duration']) + + prior_bs = Balance_Sheet_Table(balance_sheet_input) + + prior_is = Income_Statement_Table(raw_income_input, annual_bill_table, + analysis_date) + + scenario_ob = Scenario(analysis_date, commission_date, construction_cost, + bill_overview, prior_income_statement_table, + raw_annual_bill_table, growth_rate_flag, prior_bs, + loan_input_list) + + savings_scenario_ob = scenario_ob.prelim_analysis( + prior_month_bill, percent_saving_dict, full_saving_dict, + growth_rate_flag, req_dscr, customer_preference) + + post_is = Income_Statement_Table( + raw_income_input, scenario_ob.get_post_energy_bill, analysis_date) + + # Define raw_annual_bill_table as a "get" of prior_bill + # Define raw_bill_table as a "get" of prior_bill + # Delete prior_annual_bill_table + + return { + 'prior_energy_bill': 'hello', + 'prior_income_statement': 'hello', + 'prior_balance_sheet': 'hello', + 'post_energy_bill': 'hello', + 'post_income_statement': 'hello', + 'post_balance_sheet': 'hello', + } # **** ugly test **** -- GitLab From 090f59525b755854d564fc0f6be84001bf36a2c4 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Wed, 31 May 2017 16:39:37 -0400 Subject: [PATCH 23/37] improve back_end_call --- bpfin/lib/back_end_call.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/bpfin/lib/back_end_call.py b/bpfin/lib/back_end_call.py index 3991e07..c7917e8 100644 --- a/bpfin/lib/back_end_call.py +++ b/bpfin/lib/back_end_call.py @@ -202,16 +202,20 @@ def prior_income_statement_table(raw_income_input, raw_bill_table, return prior_income, next_year_income, average_income, historical_cagr -def prelim_scenario(analysis_date, commission_date, construction_cost, - raw_bill_table, raw_annual_bill_table, +def prelim_scenario(raw_bill_table, raw_annual_bill_table, raw_income_input, growth_rate_flag, raw_liability_input, raw_cash_balance, raw_loan_input_list, + analysis_date, commission_date, construction_cost, percent_saving_dict, full_saving_dict, req_dscr, customer_preference): + prior_annual_bill_table, manual_input_dict = annual_bill( + raw_bill_table, raw_annual_bill_table, analysis_date + ) + liability = final_liability_dict(analysis_date['proforma_start'], - raw_liability_dictionary, + raw_liability_input, analysis_date['proforma_duration']) prior_bs = Balance_Sheet_Table(balance_sheet_input) -- GitLab From 97c5e1aa648c57ba7b267999eb4bdf2a46afb699 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Wed, 31 May 2017 18:55:53 -0400 Subject: [PATCH 24/37] Create financial_saving file, modify scenario for new file. Update test files and data. --- bpfin/financials/financial_saving.py | 14 - bpfin/financials/saving.py | 386 ------------------ bpfin/financials/scenario.py | 93 +++-- bpfin/lib/back_end_call.py | 5 +- .../test_financials/test_cash_balance.py | 52 +-- .../test_financials/test_financial_saving.py | 287 ++++++------- bpfin/tests/test_financials/test_saving.py | 146 ------- bpfin/tests/testdata/feature_data.py | 48 +++ 8 files changed, 269 insertions(+), 762 deletions(-) delete mode 100644 bpfin/financials/saving.py delete mode 100644 bpfin/tests/test_financials/test_saving.py diff --git a/bpfin/financials/financial_saving.py b/bpfin/financials/financial_saving.py index ab91000..09a6644 100644 --- a/bpfin/financials/financial_saving.py +++ b/bpfin/financials/financial_saving.py @@ -1,17 +1,3 @@ -# """ -# this is replacement for saving.py -# The inputs would incorporate bill_list = [Bill objects] -# """ -# import datetime -# import copy -# from bpfin.utilbills.bill_lib import cal_last_day -# from bpfin.utilbills.bill_lib import annualizing_projection -# from bpfin.utilbills.bill_lib import form_year_calendar -# from bpfin.utilbills.bill_lib import form_bill_calendar -# from bpfin.utilbills.bill_post_proj_rough import bill_post_proj_rough -# from bpfin.tests.testdata import sample_data as db -# from bpfin.tests.testdata import feature_data as fdb - import datetime import copy from bpfin.utilbills.bill_lib import cal_last_day diff --git a/bpfin/financials/saving.py b/bpfin/financials/saving.py deleted file mode 100644 index e42c4c5..0000000 --- a/bpfin/financials/saving.py +++ /dev/null @@ -1,386 +0,0 @@ -import datetime -import copy -from bpfin.utilbills.bill_lib import cal_last_day -from bpfin.utilbills.bill_lib import annualizing_projection -from bpfin.utilbills.bill_lib import form_year_calendar -from bpfin.utilbills.bill_lib import form_bill_calendar -from bpfin.utilbills.bill_post_proj_rough import bill_post_proj_rough -from bpfin.tests.testdata import feature_data as db -from bpfin.lib.back_end_call import monthly_bill - - -class Saving(): - """ - Calculate savings and project bills with commissioning date considered. For one utility type - Attributes: - is_manual_input (boolean): lable indicating is bill input by scraper or manual. Yes == manual input - commissioning_date (date): the date that construction work finished, saving starts at NEXT month - proforma_date (list): list of dates, months of pro-forma time period - proforma_usage (list) : list of monthly usage, for pro-forma period - Data before commissioning date == historical - Data after commissioning date == post saving data - proforma_charge (list) : list of monthly charge, for pro-forma period - Data before commissioning date == historical - Data after commissioning date == post saving data - proforma_saving_usage (list) : monthly savings on usage, for pro-forma period - Data before commissioning date == historical - Data after commissioning date == post saving data - proforma_saving_charge (list) : monthly savings on usage, for pro-forma period - Data before commissioning date == historical - Data after commissioning date == post saving data - first_year_saving_usage (float) : first 12 months saving on usage. - first_year_saving_charge (float) : first 12 months saving on charge. If data is annual, saving is on NEXT year - annual_proforma_usage (dictionary) : key is year, value is float, annual usage - annual_proforma_charge (dictionary) : key is year, value is float, annual charge - first_year_prior_charge (float): first 12 months prior_saving charge. If data is annual, charge is for NEXT year - percent_saving (float): percentage saving on first year charge. 0.2 == 20% - """ - def __init__(self, is_manual_input, commissioning_date, proforma_date): - """ - Initiate Saving object. - Args: - is_manual_input (boolean): lable indicating is bill input by scraper or manual. Yes == manual input - commissioning_date (date): the date that construction work finished, saving starts at NEXT month - proforma_date (list): list of dates, months of pro-forma time period - """ - self.is_manual_input = is_manual_input - self.commissioning_date = commissioning_date - self.proforma_date = proforma_date - self.proforma_usage = None - self.proforma_charge = None - self.proforma_saving_usage = None - self.proforma_saving_charge = None - self.first_year_saving_charge = None - self.first_year_saving_usage = None - self.annual_proforma_usage = None - self.annual_proforma_charge = None - self.first_year_prior_charge = None - self.percent_saving = 0 - - def put_monthly_proforma(self, prior_saving_usage, post_saving_usage, prior_saving_charge, post_saving_charge): - """ - Put monthly prior_saving and post_saving, generate: monthly usage and charge for pro-forma purpose. - Also generate first year savings, and annual usage and annual charge - - Args: - prior_saving_usage (list): list of float, usage without (prior to) savings - post_saving_usage (list): list of float, usage with (post to) savings - prior_saving_charge (list): list of float, charge without (prior to) savings - post_saving_charge (list): list of float, charge with (post to) savings - """ - if self.is_manual_input is False: - saving_start_date = datetime.date( - self.commissioning_date.year, - self.commissioning_date.month, - cal_last_day(self.commissioning_date.year, self.commissioning_date.month)) - - saving_usage_dict = {} - saving_charge_dict = {} - proforma_usage_dict = {} - proforma_charge_dict = {} - first_year_saving_usage = 0 - first_year_saving_charge = 0 - first_yr_counter = 0 - first_year_prior_charge = 0 - for date, prior_usage, post_usage, prior_charge, post_charge in zip( - self.proforma_date, - prior_saving_usage, - post_saving_usage, - prior_saving_charge, - post_saving_charge): - if date > saving_start_date: - saving_usage_dict[date] = prior_usage - post_usage - saving_charge_dict[date] = prior_charge - post_charge - proforma_usage_dict[date] = post_usage - proforma_charge_dict[date] = post_charge - if first_yr_counter <= 12: - first_year_saving_usage += prior_usage - post_usage - first_year_saving_charge += prior_charge - post_charge - first_year_prior_charge += prior_charge - first_yr_counter += 1 - else: - saving_usage_dict[date] = 0 - saving_charge_dict[date] = 0 - proforma_usage_dict[date] = prior_usage - proforma_charge_dict[date] = prior_charge - - self.proforma_usage = list(proforma_usage_dict.values()) - self.proforma_charge = list(proforma_charge_dict.values()) - self.proforma_saving_usage = list(saving_usage_dict.values()) - self.proforma_saving_charge = list(saving_charge_dict.values()) - self.first_year_saving_usage = first_year_saving_usage - self.first_year_saving_charge = first_year_saving_charge - self.annual_proforma_usage = annualizing_projection(self.proforma_date, self.proforma_charge) - self.annual_proforma_charge = annualizing_projection(self.proforma_date, self.proforma_charge) - self.first_year_prior_charge = first_year_prior_charge - self.percent_saving = first_year_saving_charge / first_year_prior_charge - - def put_annual_proforma(self, annual_charge, percent_saving): - """ - Put annual prior_saving charge, calculate saving on charge and overall percentage saving - - Args: - annual_charge (dictionary): dict of annual prior saving charge, {2014: 100, ...}, with future estimated - percent_saving (float): percent of saving, 0.030 == 3.0% - """ - if self.is_manual_input is True: - annual_saving_dict = {} - annual_charge_dict = {} - proforma_year = form_year_calendar(self.proforma_date[0], self.proforma_date[-1]) - for year in proforma_year: - if year < self.commissioning_date.year: - annual_saving_dict[year] = 0 - annual_charge_dict[year] = annual_charge[year] - if year > self.commissioning_date.year: - annual_saving_dict[year] = annual_charge[year] * percent_saving - annual_charge_dict[year] = annual_charge[year] * (1 - percent_saving) - if year == self.commissioning_date.year: - effective_saving = (12 - self.commissioning_date.month) / 12 * percent_saving # partial year saving - annual_saving_dict[year] = annual_charge[year] * effective_saving - annual_charge_dict[year] = annual_charge[year] * (1 - effective_saving) - - first_year = self.commissioning_date.year + 1 - self.first_year_saving_charge = annual_saving_dict[first_year] - self.annual_proforma_charge = annual_charge_dict - self.first_year_prior_charge = annual_charge[first_year] - self.percent_saving = ( - annual_saving_dict[first_year] / annual_charge[first_year] if annual_charge[first_year] != 0 else 0) - - def get_proforma_charge(self): - """ - Get proforma_charge, for monthly pro-forma, not available for annual - Return: - list: proforma_charge - """ - return self.proforma_charge - - def get_proforma_saving_charge(self): - """ - Get proforma_saving_charge, for monthly pro-forma, not available for annual - Return: - list: proforma_saving_charge - """ - return self.proforma_saving_charge - - def get_percent_saving(self): - """ - Get percentage saving on charge - Return: - float: overall percentage saving on charge - """ - return self.percent_saving - - def get_first_year_saving_charge(self): - """ - Get first year saving - Return: - float: sum of first 12 months of savings - """ - return self.first_year_saving_charge - - def get_first_year_prior_charge(self): - """ - Get prior charge for first year after commissioning - Return: - float: prior charge for first year after commissioning - """ - return self.first_year_prior_charge - - def get_annual_proforma_charge(self): - """ - Calculate and return annual pro-forma charge - Return: - dictionary: dict of annual item, {year: annual charge} - """ - return self.annual_proforma_charge - - -class Saving_Overview(): - """ - Generate saving schedule, annual usages and charges for 4 utility types - Also calculate percentage saving on usages and charges. - If rate plan applies, usage % saving can be different from charge % saving - Saving_Overview should be scenario based, it is an "attribute" of a scenario - - Attributes: - manual_input_dict(dictionary): key is utility type, value is boolean. True == mannual_input - prior_annual_bill_table (dictionary): annual bill, for 4 utility_types - proforma_date (list): list of dates, months of pro-forma time period - commissioning_date (date): the date that construction work finished, saving starts at NEXT month - utility_saving_dict (dictionary): dict of Saving objects, for 4 utility types - saving_percent_charge (dictionary): key is utility type, value is float {'electricity': float} - total_first_year_saving (float): dollar saving for the first 12 month after commissioning - total_saving_percent (float): percentage saving on charge for the first 12 month after commissioning - - Description: - prior_annual_bill_table = {'electricity': electricity_bill, 'oil': oil_bill, ...} - electricity_bill = {2014: 100, 2015:200, ...} - """ - - def __init__( - self, - manual_input_dict, - prior_annual_bill_table, - analysis_date, # consider to replace it with proforma_date - commissioning_date): - """ - Initiate Saving_Overview. - Take in manual_input_dict, annual and monthly bills, commissioning_date and percentage savings - Generate Saving objects, pro-forma date period - - Args: - # bill_overview (dictionary): original annual bill input, with blank cells, for 4 utility_types - manual_input_dict (dictionary): dict of boolean values, indicating manual_input status of each utility - prior_annual_bill_table (dictionary): dict of dict of annual charge, for 4 utility_types - analysis_date (dictionary): proforma's starting date and the years of proforma - commissioning_date (date): the date that construction work finished, saving starts at NEXT month - - Description: - # bill_overview (dictionary): dict of a list, - # list[0] = dict of annual bill, allow some year missing, for 4 utility_types - # list[1] = boolean value, False == from manual input, True == from scraper - manual_input_dict = { 'electricity': False, 'gas': False, 'oil': False, 'water': True} - prior_annual_bill_table = {'electricity': electricity_bill, 'oil': oil_bill, ...} - electricity_bill = {2014: 100, 2015:200, ...} - """ - # self.manual_input_dict = { - # 'electricity': bill_overview['electricity'][1], - # 'gas': bill_overview['gas'][1], - # 'oil': bill_overview['oil'][1], - # 'water': bill_overview['water'][1]} - self.manual_input_dict = manual_input_dict - self.prior_annual_bill_table = prior_annual_bill_table - self.proforma_date = form_bill_calendar(analysis_date['proforma_start'], analysis_date['proforma_duration'])[1] - self.commissioning_date = commissioning_date - self.utility_saving_dict = {'electricity': None, 'gas': None, 'oil': None, 'water': None} - self.saving_percent_charge = {'electricity': None, 'gas': None, 'oil': None, 'water': None} - self.total_first_year_saving = 0 # dollar - self.total_saving_percent = 0 # dollar percentage - - def put_saving(self, prior_month_bill, percent_saving_dict, full_saving_dict): - """ - Put inputs to generage saving data. - Also calculate overall saving on charge, and percentage saving - - Args: - prior_month_bill (dictionary): dict of dict of lists, projected energy bill for prior_saving - percent_saving_dict (dictionary): dict of float, percentage saving for 4 utility types - full_saving_dict (dictionary): dict of undefined saving, from engineering saving analysis. can be None - - Description: - prior_month_bill = { - 'electricity': electricity_prior_bill_rough, - 'gas': None, - 'oil': None, - 'water': None} - - electricity_prior_bill_rough = { - 'date_from': list, - 'date_to': list, - 'usage': list, - 'charge': list, - 'price': list} - """ - utility_type_list = ['electricity', 'gas', 'oil', 'water'] - - total_first_year_saving = 0 - total_first_year_prior_charge = 0 - for utility in utility_type_list: - is_manual_input = self.manual_input_dict[utility] - - utility_saving = Saving(is_manual_input, self.commissioning_date, self.proforma_date) - - if utility_saving.is_manual_input is True: # bill is from manual input, monthly bill not available - utility_saving.put_annual_proforma(self.prior_annual_bill_table[utility], percent_saving_dict[utility]) - - if utility_saving.is_manual_input is False: # bill is from scraper, monthly bill is available - if full_saving_dict[utility] is None: # engineering saving is not available, use percentage saving - post_month_bill = bill_post_proj_rough(prior_month_bill[utility], percent_saving_dict[utility]) - # else: # engineering saving is available. Project monthly_bill with regression. not finished yet - # post_month_bill = bill_proj_reg(prior_utility, full_saving_dict[utility], HDD, CDD, occupancy) - - utility_saving.put_monthly_proforma( - prior_month_bill[utility]['usage'], - post_month_bill['usage'], - prior_month_bill[utility]['charge'], - post_month_bill['charge']) - - total_first_year_saving += utility_saving.get_first_year_saving_charge() - total_first_year_prior_charge += utility_saving.get_first_year_prior_charge() - self.saving_percent_charge[utility] = utility_saving.get_percent_saving() - self.utility_saving_dict[utility] = utility_saving - - self.total_first_year_saving = total_first_year_saving - self.total_saving_percent = ( - total_first_year_saving / total_first_year_prior_charge if total_first_year_prior_charge != 0 else 0) - - def get_total_first_year_saving(self): - """ - Get first year total dollar saving - This is used for: loan allocation, simple_payback calculation - Retrun: - float: a dollar number - """ - return self.total_first_year_saving - - def get_simple_payback(self, cost): - """ - Get the simple payback for a given project cost. cost / first year dollar saving - Args: - cost (float): project cost, estimated or quoted - Return: - float: simple paback, in year - """ - return float(cost / self.total_first_year_saving if self.total_first_year_saving != 0 else 0) - - def get_total_saving_percent(self): - """ - Get the total saving percentage. First dollar saving / First year prior_saving charge - Return: - float: total dollar saving percentage - """ - return self.total_saving_percent - - def get_post_annual_bill_table(self): - """ - Generate annual bill table for pro-forma, consiering commission date. - Return: - dictionary: dict of dict of annual charges, for 4 utility types - Description: - output = {'electricity': electricity_bill, 'oil': oil_bill, 'gas': gas_bill, 'water': water_bill} - electricity_bill = {2014: 100, 2015:200, ...} - } - """ - post_annual_bill_table = {} - utility_type_list = ['electricity', 'gas', 'oil', 'water'] - for utility_type in utility_type_list: - post_annual_bill_table[utility_type] = copy.deepcopy( - self.utility_saving_dict[utility_type].get_annual_proforma_charge()) - return post_annual_bill_table - - def get_utility_annual_saving_charge(self, utility_type): - """ - Get the proforma annual saving on charge for a utility_type - Args: - utility_type (string): 'electricity', 'gas', 'oil', 'water' - Return: - dictionary: {year: saving on charge} - """ - prior_charge_dict = copy.deepcopy(self.prior_annual_bill_table[utility_type]) - post_charge_dict = copy.deepcopy(self.utility_saving_dict[utility_type].get_annual_proforma_charge()) - saving_dict = {} - for year in prior_charge_dict: - saving_dict[year] = prior_charge_dict[year] - post_charge_dict[year] - return saving_dict - - -# **** ugly test **** -# so = Saving_Overview(db.manual_input_dict, db.prior_annual_bill, db.analysis_date, datetime.date(2017, 3, 14)) -# prior_monthly_bill = monthly_bill(db.raw_bill_table, db.analysis_date)[2] -# so.put_saving(prior_monthly_bill, db.percent_saving_dict, db.full_saving_dict) - -# print('\n first_year_dollar_saving =', so.get_total_first_year_saving()) -# print('\n simple payback =', so.get_simple_payback(50000)) -# print('\n total saving percent =', so.get_total_saving_percent()) -# print('\n electricity_annual_saving_charge', so.get_utility_annual_saving_charge('electricity')) -# print(so.get_post_annual_bill_table()) diff --git a/bpfin/financials/scenario.py b/bpfin/financials/scenario.py index 70bbd11..ca50967 100644 --- a/bpfin/financials/scenario.py +++ b/bpfin/financials/scenario.py @@ -1,5 +1,6 @@ import copy -from bpfin.financials.saving import Saving_Overview +# from bpfin.financials.saving import Saving_Overview +from bpfin.financials.financial_saving import Saving_Overview from bpfin.financials.loan import Loan_List from bpfin.lib.other import add_year_dictionary, divide_dscr_dict, min_none_list from bpfin.utilbills.bill_lib import form_bill_year, annualizing_projection @@ -7,10 +8,12 @@ from bpfin.financials.liability import final_liability_dict from bpfin.financials.balance_sheet_projection import balance_sheet_projection from bpfin.lib.back_end_call import prior_income_statement_table from bpfin.financials.financial_income import Income_Statement_Table +from bpfin.financials.financial_lib import Balance_Sheet_Table # may delete from here after sample built -# from bpfin.financials.financial_lib import Income_Statement_Table, Balance_Sheet_Table -# from bpfin.tests.testdata import sample_data as db +from bpfin.tests.testdata import feature_data as db +from bpfin.tests.testdata import sample_data as sdb +from bpfin.lib.back_end_call import monthly_bill class Scenario(): @@ -39,7 +42,7 @@ class Scenario(): def __init__(self, analysis_date, commission_date, construction_cost, manual_input_dict, prior_income_statement_table, - other_debt_service, raw_annual_bill_table, growth_rate_flag, + other_debt_service, prior_annual_bill_table, growth_rate_flag, prior_balance_sheet_table, loan_input_list): """ Initiate Scenario object. @@ -71,8 +74,7 @@ class Scenario(): self.manual_input_dict = copy.deepcopy(manual_input_dict) - # self.prior_annual_bill_table = copy.deepcopy(prior_annual_bill_table) - self.raw_annual_bill_table = copy.deepcopy(raw_annual_bill_table) + self.prior_annual_bill_table = copy.deepcopy(prior_annual_bill_table) self.prior_income_statement_table = copy.deepcopy( prior_income_statement_table) @@ -86,7 +88,7 @@ class Scenario(): self.saving_overview = Saving_Overview( manual_input_dict=copy.deepcopy(manual_input_dict), - prior_annual_bill_table=copy.deepcopy(raw_annual_bill_table), + prior_annual_bill_table=copy.deepcopy(prior_annual_bill_table), analysis_date=copy.deepcopy(analysis_date), commissioning_date=copy.deepcopy(commission_date)) self.scheduled_loan_list = None @@ -140,7 +142,7 @@ class Scenario(): post_income_statement_table = copy.deepcopy( self.prior_income_statement_table) post_income_statement_table.project( - growth_rate_flag, self.analysis_date, post_annual_bill_table) + growth_rate_flag, post_annual_bill_table) self.post_income_statement_table = post_income_statement_table # generate post_saving balance_sheet_table object @@ -309,40 +311,41 @@ class Scenario(): # # ***** ugly test that can be a guide for front end dev ***** - -# # liability_dictionary = cash_balance('dict of tuples, date: (float, boolean)') -# growth_toggle = 0.01 -# prior_IS_table = Income_Statement_Table( -# db.raw_income_input, -# db.bill_overview_organized) -# prior_IS_table.project(growth_toggle, db.analysis_date, db.bill_overview_organized) -# prior_BS_table = Balance_Sheet_Table(db.raw_balance_sheet) -# prior_BS_table.project_balance_sheet( -# db.analysis_date, -# db.liability_dictionary, -# prior_IS_table.get_noi_dict()) - -# scenario = Scenario( -# analysis_date=db.analysis_date, -# commission_date=db.commission_date, -# construction_cost=60000, -# bill_overview=db.bill_overview, -# prior_annual_bill_table=db.bill_overview_organized, -# other_debt_service=db.liability_dictionary, -# prior_income_statement_table=prior_IS_table, -# prior_balance_sheet_table=prior_BS_table, -# loan_input_list=db.loan_input_list -# ) - -# scenario.prelim_anlaysis( -# prior_month_bill=db.prior_month_bill, -# percent_saving_dict=db.percent_saving_dict, -# full_saving_dict=db.full_saving_dict, -# growth_rate_flag=growth_toggle, -# req_dscr=db.req_dscr, -# customer_preference=db.customer_preference) - -# print(scenario.get_annual_debt_service()) -# print(scenario.get_graph_dict()) -# print(scenario.get_dscr()) -# print(scenario.get_economics()) +growth_toggle = 0.01 +prior_IS_table = Income_Statement_Table( + db.raw_income_input, + db.prior_annual_bill, + db.analysis_date) +prior_IS_table.project(growth_toggle, db.prior_annual_bill) +prior_BS_table = Balance_Sheet_Table(sdb.raw_balance_sheet) +prior_BS_table.project_balance_sheet( + db.analysis_date, + db.liability_dictionary, + prior_IS_table.get_noi_dict()) + +scenario = Scenario( + analysis_date=db.analysis_date, + commission_date=db.commission_date, + construction_cost=db.cost_estimation, + manual_input_dict=db.manual_input_dict, + prior_annual_bill_table=db.prior_annual_bill, + prior_income_statement_table=prior_IS_table, + other_debt_service=db.liability_dictionary, + growth_rate_flag=growth_toggle, + prior_balance_sheet_table=prior_BS_table, + loan_input_list=db.raw_loan_input_list +) + +prior_month_bill=monthly_bill(db.raw_bill_table, db.analysis_date)[2] +scenario.prelim_analysis( + prior_month_bill=prior_month_bill, + percent_saving_dict=db.percent_saving_dict, + full_saving_dict=db.full_saving_dict, + growth_rate_flag=growth_toggle, + req_dscr=db.req_dscr, + customer_preference=db.customer_preference) + +print(scenario.get_annual_debt_service()) +print(scenario.get_graph_dict()) +print(scenario.get_dscr()) +print(scenario.get_economics()) diff --git a/bpfin/lib/back_end_call.py b/bpfin/lib/back_end_call.py index c7917e8..e3ef089 100644 --- a/bpfin/lib/back_end_call.py +++ b/bpfin/lib/back_end_call.py @@ -56,6 +56,7 @@ def monthly_bill(raw_bill_table, analysis_date): 'water': dict of water_bill} To Do: from utilbills.bill.py merge form_prior_month_bill(), and delete that one + * this work is done. need all units test and then can delete that """ # if not raw_bill_table: # raise ValueError( @@ -214,9 +215,7 @@ def prelim_scenario(raw_bill_table, raw_annual_bill_table, raw_bill_table, raw_annual_bill_table, analysis_date ) - liability = final_liability_dict(analysis_date['proforma_start'], - raw_liability_input, - analysis_date['proforma_duration']) + liability = final_liability_dict(analysis_date, raw_liability_input,) prior_bs = Balance_Sheet_Table(balance_sheet_input) diff --git a/bpfin/tests/test_financials/test_cash_balance.py b/bpfin/tests/test_financials/test_cash_balance.py index 2872226..2fffe1b 100644 --- a/bpfin/tests/test_financials/test_cash_balance.py +++ b/bpfin/tests/test_financials/test_cash_balance.py @@ -25,30 +25,30 @@ from datetime import date # assert result == output_cash_balance -# def test_cash_balance(): -# input_dictionary = { -# date(2014, 11, 1): (500, False), -# date(2015, 12, 31): (600, True), -# date(2016, 11, 11): (500, False), -# date(2016, 10, 10): (400, False) -# } -# input_analysis_date = { -# 'proforma_start': date(2006, 5, 3), -# 'proforma_duration': 12 -# } -# output_cash_balance = { -# 2006: 500, -# 2007: 500, -# 2008: 500, -# 2009: 500, -# 2010: 500, -# 2011: 500, -# 2012: 500, -# 2013: 500, -# 2014: 500.0, -# 2015: 600, -# 2016: 450.0 -# } -# result = cash_balance(input_analysis_date, input_dictionary) +def test_cash_balance(): + input_dictionary = { + date(2014, 11, 1): (500, False), + date(2015, 12, 31): (600, True), + date(2016, 11, 11): (500, False), + date(2016, 10, 10): (400, False) + } + input_analysis_date = { + 'proforma_start': date(2006, 5, 3), + 'proforma_duration': 12 + } + output_cash_balance = { + 2006: 500, + 2007: 500, + 2008: 500, + 2009: 500, + 2010: 500, + 2011: 500, + 2012: 500, + 2013: 500, + 2014: 500.0, + 2015: 600, + 2016: 450.0 + } + result = cash_balance(input_analysis_date, input_dictionary) -# assert result == output_cash_balance + assert result == output_cash_balance diff --git a/bpfin/tests/test_financials/test_financial_saving.py b/bpfin/tests/test_financials/test_financial_saving.py index 49e6fe1..8c6f469 100644 --- a/bpfin/tests/test_financials/test_financial_saving.py +++ b/bpfin/tests/test_financials/test_financial_saving.py @@ -1,142 +1,145 @@ -# from datetime import date -# from bpfin.financials.financial_saving import Saving -# from bpfin.financials.financial_saving import Saving_Overview -# from bpfin.tests.testdata import feature_data as db - - -# def test_Saving_put_monthly_proforma(): -# input_proforma_date = [ -# date(2017, 1, 31), -# date(2017, 2, 28), -# date(2017, 3, 31), -# date(2017, 4, 30), -# date(2017, 5, 31), -# date(2017, 6, 30), -# date(2017, 7, 31), -# date(2017, 8, 31), -# date(2017, 9, 30), -# date(2017, 10, 31), -# date(2017, 11, 30), -# date(2017, 12, 31)] -# input_commissioning_date = date(2017, 3, 14) -# input_prior_charge = [100] * 12 -# input_post_charge = [100, 90, 80, 70, 60, 50, 40, 30, 40, 50, 60, 70] -# input_prior_usage = [15] * 12 -# input_post_usage = [10, 9, 8, 7, 6, 5, 4, 3, 4, 5, 6, 7] -# output_saving = [0, 0, 0, 30, 40, 50, 60, 70, 60, 50, 40, 30] -# output_charge = [100, 100, 100, 70, 60, 50, 40, 30, 40, 50, 60, 70] -# output_overall_saving = 0.4777777777777778 - -# elec_saving = Saving(False, input_commissioning_date, input_proforma_date) -# elec_saving.put_monthly_proforma(input_prior_usage, input_post_usage, input_prior_charge, input_post_charge) -# result_saving = elec_saving.get_proforma_saving_charge() -# result_charge = elec_saving.get_proforma_charge() - -# assert output_saving == result_saving -# assert output_charge == result_charge -# assert elec_saving.get_first_year_saving_charge() == 430 -# assert elec_saving.get_annual_proforma_charge() == {2017: 770} -# assert elec_saving.get_percent_saving() == output_overall_saving - - -# def test_Saving_put_annual_proforma(): -# input_proforma_date = [ -# date(2017, 1, 31), -# date(2017, 2, 28), -# date(2017, 3, 31), -# date(2017, 4, 30), -# date(2017, 5, 31), -# date(2017, 6, 30), -# date(2017, 7, 31), -# date(2017, 8, 31), -# date(2017, 9, 30), -# date(2017, 10, 31), -# date(2017, 11, 30), -# date(2017, 12, 31), -# date(2018, 1, 31), -# date(2018, 2, 28), -# date(2018, 3, 31), -# date(2018, 4, 30), -# date(2018, 5, 31), -# date(2018, 6, 30), -# date(2018, 7, 31), -# date(2018, 8, 31), -# date(2018, 9, 30), -# date(2018, 10, 31), -# date(2018, 11, 30), -# date(2018, 12, 31)] -# input_commissioning_date = date(2017, 3, 14) -# input_annual_charge = {2017: 100, 2018: 100} -# input_percent_saving = 0.20 -# output_first_year_saving_charge = 20 -# output_annual_proforma_charge = {2017: 85, 2018: 80} -# output_overall_saving = 0.20 - -# elec_saving = Saving(True, input_commissioning_date, input_proforma_date) -# elec_saving.put_annual_proforma(input_annual_charge, input_percent_saving) - -# result_first_year_saving_charge = elec_saving.get_first_year_saving_charge() -# result_annual_proforma_charge = elec_saving.get_annual_proforma_charge() -# result_overall_saving = elec_saving.get_percent_saving() - -# assert result_first_year_saving_charge == output_first_year_saving_charge -# assert result_annual_proforma_charge == output_annual_proforma_charge -# assert result_overall_saving == output_overall_saving - - -# def test_Saving_Overview(): -# input_bill_list = db.bill_list -# input_analysis_date = db.analysis_date -# input_commissioning_date = db.commission_date - -# input_percent_saving_dict = db.percent_saving_dict -# input_full_saving_dict = db.full_saving_dict - -# output_first_year_saving = 1502.6386560837202 -# output_simple_payback = 33.274799498579 -# output_total_saving_percent = 0.37312045887352324 -# output_electricity_annual_saving_charge = { -# 2012: 0.0, -# 2013: 0.0, -# 2014: 0.0, -# 2015: 0.0, -# 2016: 0.0, -# 2017: 251.64464541815892, -# 2018: 357.48478459061994, -# 2019: 366.28049606569721, -# 2020: 374.86074424735079, -# 2021: 382.88611271044329, -# 2022: 390.15410099072778, -# 2023: 397.27620075339473, -# 2024: 404.54734630353755, -# 2025: 412.06528286992216, -# 2026: 420.14359538042595, -# 2027: 428.86477571357136, -# 2028: 437.81793503683912, -# 2029: 446.78365645196686, -# 2030: 455.7489720441697, -# 2031: 464.74135726047848, -# 2032: 473.83322571714552, -# 2033: 483.13050892569618, -# 2034: 492.67630130304224, -# 2035: 502.48247134137955, -# 2036: 512.55020795318637 -# } -# output_post_annual_bill_table = db.post_annual_bill_table -# saving_overview = Saving_Overview( -# input_bill_list, -# input_analysis_date, -# input_commissioning_date) - -# saving_overview.put_saving(input_percent_saving_dict, input_full_saving_dict) -# result_first_year_saving = saving_overview.get_total_first_year_saving() -# result_simple_payback = saving_overview.get_simple_payback(50000) -# result_total_saving_percent = saving_overview.get_total_saving_percent() -# result_electricity_annual_saving_charge = saving_overview.get_utility_annual_saving_charge('electricity') -# result_post_annual_bill_table = saving_overview.get_post_annual_bill_table() - -# assert result_first_year_saving == output_first_year_saving -# assert result_simple_payback == output_simple_payback -# assert result_total_saving_percent == output_total_saving_percent -# assert result_electricity_annual_saving_charge == output_electricity_annual_saving_charge -# assert result_post_annual_bill_table == output_post_annual_bill_table +import datetime +from bpfin.financials.financial_saving import Saving +from bpfin.financials.financial_saving import Saving_Overview +from bpfin.tests.testdata import feature_data as db + + +def test_Saving_put_monthly_proforma(): + input_proforma_date = [ + datetime.date(2017, 1, 31), + datetime.date(2017, 2, 28), + datetime.date(2017, 3, 31), + datetime.date(2017, 4, 30), + datetime.date(2017, 5, 31), + datetime.date(2017, 6, 30), + datetime.date(2017, 7, 31), + datetime.date(2017, 8, 31), + datetime.date(2017, 9, 30), + datetime.date(2017, 10, 31), + datetime.date(2017, 11, 30), + datetime.date(2017, 12, 31)] + input_commissioning_date = datetime.date(2017, 3, 14) + input_prior_charge = [100] * 12 + input_post_charge = [100, 90, 80, 70, 60, 50, 40, 30, 40, 50, 60, 70] + input_prior_usage = [15] * 12 + input_post_usage = [10, 9, 8, 7, 6, 5, 4, 3, 4, 5, 6, 7] + output_saving = [0, 0, 0, 30, 40, 50, 60, 70, 60, 50, 40, 30] + output_charge = [100, 100, 100, 70, 60, 50, 40, 30, 40, 50, 60, 70] + output_overall_saving = 0.4777777777777778 + + elec_saving = Saving(False, input_commissioning_date, input_proforma_date) + elec_saving.put_monthly_proforma(input_prior_usage, input_post_usage, input_prior_charge, input_post_charge) + result_saving = elec_saving.get_proforma_saving_charge() + result_charge = elec_saving.get_proforma_charge() + + assert output_saving == result_saving + assert output_charge == result_charge + assert elec_saving.get_first_year_saving_charge() == 430 + assert elec_saving.get_annual_proforma_charge() == {2017: 770} + assert elec_saving.get_percent_saving() == output_overall_saving + + +def test_Saving_put_annual_proforma(): + input_proforma_date = [ + datetime.date(2017, 1, 31), + datetime.date(2017, 2, 28), + datetime.date(2017, 3, 31), + datetime.date(2017, 4, 30), + datetime.date(2017, 5, 31), + datetime.date(2017, 6, 30), + datetime.date(2017, 7, 31), + datetime.date(2017, 8, 31), + datetime.date(2017, 9, 30), + datetime.date(2017, 10, 31), + datetime.date(2017, 11, 30), + datetime.date(2017, 12, 31), + datetime.date(2018, 1, 31), + datetime.date(2018, 2, 28), + datetime.date(2018, 3, 31), + datetime.date(2018, 4, 30), + datetime.date(2018, 5, 31), + datetime.date(2018, 6, 30), + datetime.date(2018, 7, 31), + datetime.date(2018, 8, 31), + datetime.date(2018, 9, 30), + datetime.date(2018, 10, 31), + datetime.date(2018, 11, 30), + datetime.date(2018, 12, 31)] + input_commissioning_date = datetime.date(2017, 3, 14) + input_annual_charge = {2017: 100, 2018: 100} + input_percent_saving = 0.20 + output_first_year_saving_charge = 20 + output_annual_proforma_charge = {2017: 85, 2018: 80} + output_overall_saving = 0.20 + + elec_saving = Saving(True, input_commissioning_date, input_proforma_date) + elec_saving.put_annual_proforma(input_annual_charge, input_percent_saving) + + result_first_year_saving_charge = elec_saving.get_first_year_saving_charge() + result_annual_proforma_charge = elec_saving.get_annual_proforma_charge() + result_overall_saving = elec_saving.get_percent_saving() + + assert result_first_year_saving_charge == output_first_year_saving_charge + assert result_annual_proforma_charge == output_annual_proforma_charge + assert result_overall_saving == output_overall_saving + + +def test_Saving_Overview(): + from bpfin.lib.back_end_call import monthly_bill + input_manual_input_dict = db.manual_input_dict + input_prior_annual_bill_table = db.prior_annual_bill + input_analysis_date = db.analysis_date + input_commissioning_date = datetime.date(2017, 3, 14) + + prior_monthly_bill = monthly_bill(db.raw_bill_table, input_analysis_date)[2] + input_prior_month_bill = prior_monthly_bill + input_percent_saving_dict = db.percent_saving_dict + input_full_saving_dict = db.full_saving_dict + + output_first_year_saving = 28667.507248011731 + output_simple_payback = 1.744134903932668 + output_total_saving_percent = 0.46592312148565274 + output_electricity_annual_saving_charge = { + 2012: 0.0, + 2013: 0.0, + 2014: 0.0, + 2015: 0.0, + 2016: 0.0, + 2017: 162.81610514235683, + 2018: 217.5358446704256, + 2019: 222.88552019426197, + 2020: 228.10636614744124, + 2021: 232.98501809818731, + 2022: 237.40591301201312, + 2023: 241.73930274248983, + 2024: 246.16421306765812, + 2025: 250.73914770469878, + 2026: 255.65734234845252, + 2027: 260.96499723521435, + 2028: 266.41256515482269, + 2029: 271.86744883912024, + 2030: 277.3223130868306, + 2031: 282.79361546555913, + 2032: 288.32598130207771, + 2033: 293.98354473703466, + 2034: 299.79239684503989, + 2035: 305.75966632361155, + 2036: 311.88609209170363 + } + output_post_annual_bill_table = db.post_annual_bill + + saving_overview = Saving_Overview( + input_manual_input_dict, input_prior_annual_bill_table, input_analysis_date, input_commissioning_date) + saving_overview.put_saving(input_prior_month_bill, input_percent_saving_dict, input_full_saving_dict) + + result_first_year_saving = saving_overview.get_total_first_year_saving() + result_simple_payback = saving_overview.get_simple_payback(50000) + result_total_saving_percent = saving_overview.get_total_saving_percent() + result_electricity_annual_saving_charge = saving_overview.get_utility_annual_saving_charge('electricity') + result_post_annual_bill_table = saving_overview.get_post_annual_bill_table() + + assert result_first_year_saving == output_first_year_saving + assert result_simple_payback == output_simple_payback + assert result_total_saving_percent == output_total_saving_percent + assert result_electricity_annual_saving_charge == output_electricity_annual_saving_charge + assert result_post_annual_bill_table == output_post_annual_bill_table diff --git a/bpfin/tests/test_financials/test_saving.py b/bpfin/tests/test_financials/test_saving.py deleted file mode 100644 index 5c67b7b..0000000 --- a/bpfin/tests/test_financials/test_saving.py +++ /dev/null @@ -1,146 +0,0 @@ -import datetime -from bpfin.financials.saving import Saving -from bpfin.financials.saving import Saving_Overview -# from bpfin.lib.back_end_call import monthly_bill -from bpfin.tests.testdata import feature_data as db - - -def test_Saving_put_monthly_proforma(): - input_proforma_date = [ - datetime.date(2017, 1, 31), - datetime.date(2017, 2, 28), - datetime.date(2017, 3, 31), - datetime.date(2017, 4, 30), - datetime.date(2017, 5, 31), - datetime.date(2017, 6, 30), - datetime.date(2017, 7, 31), - datetime.date(2017, 8, 31), - datetime.date(2017, 9, 30), - datetime.date(2017, 10, 31), - datetime.date(2017, 11, 30), - datetime.date(2017, 12, 31)] - input_commissioning_date = datetime.date(2017, 3, 14) - input_prior_charge = [100] * 12 - input_post_charge = [100, 90, 80, 70, 60, 50, 40, 30, 40, 50, 60, 70] - input_prior_usage = [15] * 12 - input_post_usage = [10, 9, 8, 7, 6, 5, 4, 3, 4, 5, 6, 7] - output_saving = [0, 0, 0, 30, 40, 50, 60, 70, 60, 50, 40, 30] - output_charge = [100, 100, 100, 70, 60, 50, 40, 30, 40, 50, 60, 70] - output_overall_saving = 0.4777777777777778 - - elec_saving = Saving(False, input_commissioning_date, input_proforma_date) - elec_saving.put_monthly_proforma(input_prior_usage, input_post_usage, input_prior_charge, input_post_charge) - result_saving = elec_saving.get_proforma_saving_charge() - result_charge = elec_saving.get_proforma_charge() - - assert output_saving == result_saving - assert output_charge == result_charge - assert elec_saving.get_first_year_saving_charge() == 430 - assert elec_saving.get_annual_proforma_charge() == {2017: 770} - assert elec_saving.get_percent_saving() == output_overall_saving - - -def test_Saving_put_annual_proforma(): - input_proforma_date = [ - datetime.date(2017, 1, 31), - datetime.date(2017, 2, 28), - datetime.date(2017, 3, 31), - datetime.date(2017, 4, 30), - datetime.date(2017, 5, 31), - datetime.date(2017, 6, 30), - datetime.date(2017, 7, 31), - datetime.date(2017, 8, 31), - datetime.date(2017, 9, 30), - datetime.date(2017, 10, 31), - datetime.date(2017, 11, 30), - datetime.date(2017, 12, 31), - datetime.date(2018, 1, 31), - datetime.date(2018, 2, 28), - datetime.date(2018, 3, 31), - datetime.date(2018, 4, 30), - datetime.date(2018, 5, 31), - datetime.date(2018, 6, 30), - datetime.date(2018, 7, 31), - datetime.date(2018, 8, 31), - datetime.date(2018, 9, 30), - datetime.date(2018, 10, 31), - datetime.date(2018, 11, 30), - datetime.date(2018, 12, 31)] - input_commissioning_date = datetime.date(2017, 3, 14) - input_annual_charge = {2017: 100, 2018: 100} - input_percent_saving = 0.20 - output_first_year_saving_charge = 20 - output_annual_proforma_charge = {2017: 85, 2018: 80} - output_overall_saving = 0.20 - - elec_saving = Saving(True, input_commissioning_date, input_proforma_date) - elec_saving.put_annual_proforma(input_annual_charge, input_percent_saving) - - result_first_year_saving_charge = elec_saving.get_first_year_saving_charge() - result_annual_proforma_charge = elec_saving.get_annual_proforma_charge() - result_overall_saving = elec_saving.get_percent_saving() - - assert result_first_year_saving_charge == output_first_year_saving_charge - assert result_annual_proforma_charge == output_annual_proforma_charge - assert result_overall_saving == output_overall_saving - - -def test_Saving_Overview(): - from bpfin.lib.back_end_call import monthly_bill - input_manual_input_dict = db.manual_input_dict - input_prior_annual_bill_table = db.prior_annual_bill - input_analysis_date = db.analysis_date - input_commissioning_date = datetime.date(2017, 3, 14) - - prior_monthly_bill = monthly_bill(db.raw_bill_table, input_analysis_date)[2] - input_prior_month_bill = prior_monthly_bill - input_percent_saving_dict = db.percent_saving_dict - input_full_saving_dict = db.full_saving_dict - - output_first_year_saving = 28667.507248011731 - output_simple_payback = 1.744134903932668 - output_total_saving_percent = 0.46592312148565274 - output_electricity_annual_saving_charge = { - 2012: 0.0, - 2013: 0.0, - 2014: 0.0, - 2015: 0.0, - 2016: 0.0, - 2017: 162.81610514235683, - 2018: 217.5358446704256, - 2019: 222.88552019426197, - 2020: 228.10636614744124, - 2021: 232.98501809818731, - 2022: 237.40591301201312, - 2023: 241.73930274248983, - 2024: 246.16421306765812, - 2025: 250.73914770469878, - 2026: 255.65734234845252, - 2027: 260.96499723521435, - 2028: 266.41256515482269, - 2029: 271.86744883912024, - 2030: 277.3223130868306, - 2031: 282.79361546555913, - 2032: 288.32598130207771, - 2033: 293.98354473703466, - 2034: 299.79239684503989, - 2035: 305.75966632361155, - 2036: 311.88609209170363 - } - output_post_annual_bill_table = db.post_annual_bill - - saving_overview = Saving_Overview( - input_manual_input_dict, input_prior_annual_bill_table, input_analysis_date, input_commissioning_date) - saving_overview.put_saving(input_prior_month_bill, input_percent_saving_dict, input_full_saving_dict) - - result_first_year_saving = saving_overview.get_total_first_year_saving() - result_simple_payback = saving_overview.get_simple_payback(50000) - result_total_saving_percent = saving_overview.get_total_saving_percent() - result_electricity_annual_saving_charge = saving_overview.get_utility_annual_saving_charge('electricity') - result_post_annual_bill_table = saving_overview.get_post_annual_bill_table() - - assert result_first_year_saving == output_first_year_saving - assert result_simple_payback == output_simple_payback - assert result_total_saving_percent == output_total_saving_percent - assert result_electricity_annual_saving_charge == output_electricity_annual_saving_charge - assert result_post_annual_bill_table == output_post_annual_bill_table diff --git a/bpfin/tests/testdata/feature_data.py b/bpfin/tests/testdata/feature_data.py index 3d753f9..3ca96fb 100644 --- a/bpfin/tests/testdata/feature_data.py +++ b/bpfin/tests/testdata/feature_data.py @@ -249,7 +249,26 @@ full_saving_dict = { } # dict of engineering analysis, {'date_from': [], 'date_to': [], 'heating': [], 'cooling': [], 'other': []} +raw_liability_input = { + 'debt1': (150, 'NYSERDA', 10, date(2012, 12, 31)), + 'debt2': (100, 'NYCEEC', 20, date(2012, 8, 31)) + } + +raw_cash_balance = { + date(2014, 3, 14): (60000, False), + date(2015, 12, 31): (62000, True), + date(2016, 12, 31): (52000, True) +} + + +loan_term_1 = {'institute': 'NYSERDA', 'max_amount': 500000, 'interest': 0.08, 'duration': 120} +loan_term_2 = {'institute': 'Joe Fund', 'max_amount': 50000, 'interest': 0.05, 'duration': 108} +loan_term_3 = {'institute': 'Tooraj Capital', 'max_amount': 75000, 'interest': 0.07, 'duration': 114} +loan_term_dict = {1: loan_term_1, 2: loan_term_2, 3: loan_term_3} +raw_loan_input_list = [loan_term_1, loan_term_2, loan_term_3] + +# ****** result ***** prior_annual_bill = { 'electricity': { 2012: 792.50603354980865, 2013: 806.56436875723125, 2014: 819.06930386346062, 2015: 825.90552345154924, @@ -779,3 +798,32 @@ post_annual_bill = { 2036: 20500.0 } } + + +liability_dictionary = { + 2012: 650, + 2013: 2550, + 2014: 300, + 2015: 0, + 2016: 0, + 2017: 0, + 2018: 0, + 2019: 0, + 2020: 0, + 2021: 0, + 2022: 0, + 2023: 0, + 2024: 0, + 2025: 0, + 2026: 0, + 2027: 0, + 2028: 0, + 2029: 0, + 2030: 0, + 2031: 0, + 2032: 0, + 2033: 0, + 2034: 0, + 2035: 0, + 2036: 0, + } -- GitLab From e937c5c02ceb85c109bc72365c98c44346cc3fef Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Wed, 31 May 2017 19:03:27 -0400 Subject: [PATCH 25/37] Remove income_statement_table test file from test files --- bpfin/financials/financial_lib.py | 870 +++++++++--------- .../test_financials/test_financial_income.py | 27 + .../test_financials/test_financial_lib.py | 28 +- 3 files changed, 463 insertions(+), 462 deletions(-) diff --git a/bpfin/financials/financial_lib.py b/bpfin/financials/financial_lib.py index df7f34f..43a218f 100644 --- a/bpfin/financials/financial_lib.py +++ b/bpfin/financials/financial_lib.py @@ -64,441 +64,441 @@ def organize_bill_overview(bill_overview, analysis_date): return bill_overview_organized -class Income_Statement(): - def __init__(self): - self.year = None - self.revenue = None - self.utility_expense = None - self.non_utility_expense = None - self.electricity_opex = None - self.gas_opex = None - self.oil_opex = None - self.water_opex = None - self.energy_opex = None - self.other_utility = None - self.net_non_energy_opex = None - self.total_opex = None - self.noi = None - # energy_debt_service = - # other_debt_service = - # total_debt_service = - # bill_saving = - # energy_DSCR = - # total_DSCR = - - def put_hist(self, year, income_input, annual_bill_table): - """ - Put historical income statement data and generate a single year income statement - Inputs are incomplete income statement items, and energy bill overview - Final output is an single year income_statement objectvie with standarized items filled - - Args: - year (int): the year of this income statement - income_input (dictionary): 3 elements of inputs - annual_bill_table (dictionary): annual bill, for 4 utility_types - - Description Sample: - income_input = {revenue': 100000, 'utility_expense': 60000,'non_utility_expense': 3000} - annual_bill_table = {'electricity': electricity_bill, 'oil': oil_bill, 'gas': gas_bill, 'water': water_bill} - """ - self.year = year - self.revenue = income_input['revenue'] - self.utility_expense = income_input['utility_expense'] - self.non_utility_expense = income_input['non_utility_expense'] - self.electricity_opex = annual_bill_table['electricity'][self.year] - self.gas_opex = annual_bill_table['gas'][self.year] - self.oil_opex = annual_bill_table['oil'][self.year] - self.water_opex = annual_bill_table['water'][self.year] - self.energy_opex = self.electricity_opex + self.oil_opex + self.gas_opex + self.water_opex - self.other_utility = self.utility_expense - self.energy_opex - self.net_non_energy_opex = self.other_utility + self.non_utility_expense - self.total_opex = self.energy_opex + self.net_non_energy_opex - self.noi = self.revenue - self.total_opex # net operating income - - def put_average(self, average_revenue, annual_bills, characters): - """ - Calculate and create average income statement. - Revenue, energy bills are average of historical data. - Other items are calculated by historical characters. - Args: - average_revenue (float): average revenue calculated from historical income statements - annual_bills (dictionary): dictionary of float value of average annual bills, for 4 utility_types - characters (dictionary): 6 characters calculated from historical income statements - Final instance is a single year income statement without named year - - Description: - characters = { - 'start_year': (int) 2014, - 'end_year': (int) 2016, - 'cagr': (float) 0.054, - 'other_utility_percent': (float) 0.020 == 2.0% - 'non_utility_expense_percent': (float) 0.030 == 3.0% - 'revenue_average': (float) 3000.00 - } - annual_bills = {'electricity': 100.0, 'oil': 200.0, 'gas': 300.0, 'water': 400.0} - """ - self.revenue = average_revenue - self.electricity_opex = annual_bills['electricity'] - self.gas_opex = annual_bills['gas'] - self.oil_opex = annual_bills['oil'] - self.water_opex = annual_bills['water'] - self.energy_opex = self.electricity_opex + self.gas_opex + self.oil_opex + self.water_opex - self.other_utility = self.revenue * characters['other_utility_percent'] - self.non_utility_expense = self.revenue * characters[ - 'non_utility_expense_percent'] - self.utility_expense = self.energy_opex + self.other_utility - self.net_non_energy_opex = self.other_utility + self.non_utility_expense - self.total_opex = self.energy_opex + self.net_non_energy_opex - self.noi = self.revenue - self.total_opex - - -def convert_income_statement_class(income_statement_class): - """ - Convert single year income statement object into a dictionary format - Args: - income_statement_class (object): single year income statement object - Return: - income_statement_dict (dictionary) - """ - income_statement_dict = { - 'year': income_statement_class.year, - 'revenue': income_statement_class.revenue, - 'utility_expense': income_statement_class.utility_expense, - 'energy_opex': income_statement_class.energy_opex, - 'electricity_opex': income_statement_class.electricity_opex, - 'gas_opex': income_statement_class.gas_opex, - 'oil_opex': income_statement_class.oil_opex, - 'water_opex': income_statement_class.water_opex, - 'other_utility': income_statement_class.other_utility, - 'non_utility_expense': income_statement_class.non_utility_expense, - 'net_non_energy_opex': income_statement_class.net_non_energy_opex, - 'total_opex': income_statement_class.total_opex, - 'noi': income_statement_class.noi - } - return income_statement_dict - - -class Income_Statement_Next(): - """ - Create single year income_statement object, - with input of last year data, income statement characters, and projected annual bill - """ - - def __init__(self, year, last_revenue, growth_rate_flag, characters, annual_bill_table): - """ - Calculation is done in initiation. - Args: - year (int): the year that will be projected on - last_revenue (float): last year revenue - growth_rate_flag (float): indicating assumed growth rate, -2.0 == cagr, -1.0 == historical average - characters (dictionary): 6 characters calculated from historical income statements - annual_bill_table (dictionary): dictionary of dictionary of annual bills, for 4 utility_types - Final instance is a single year income_statement object - - Description: - characters = { - 'start_year': (int) 2014, - 'end_year': (int) 2016, - 'cagr': (float) 0.054, - 'other_utility_percent': (float) 0.020 == 2.0% - 'non_utility_expense_percent': (float) 0.035 == 3.5% - 'revenue_average': (float) 3000.00 - } - annual_bill_table = {'electricity': electricity_bill, 'oil': oil_bill, 'gas': gas_bill, 'water': water_bill} - electricity_bill = {2014: 100, 2015:200, ...} - """ - self.year = year - - if growth_rate_flag == -1.0: # growth_rate_flag == average - current_revenue = characters['revenue_average'] - else: - if growth_rate_flag == -2.0: # growth_rate_flag == cagr - growth_rate = characters['cagr'] - else: - growth_rate = growth_rate_flag # growth_rate_flag == 0.00, 0.01, ... - current_revenue = last_revenue * (1 + growth_rate) - self.revenue = current_revenue - self.electricity_opex = annual_bill_table['electricity'][self.year] - self.gas_opex = annual_bill_table['gas'][self.year] - self.oil_opex = annual_bill_table['oil'][self.year] - self.water_opex = annual_bill_table['water'][self.year] - self.energy_opex = self.electricity_opex + self.gas_opex + self.oil_opex + self.water_opex - self.other_utility = self.revenue * characters['other_utility_percent'] - self.non_utility_expense = self.revenue * characters[ - 'non_utility_expense_percent'] - self.utility_expense = self.energy_opex + self.other_utility - self.net_non_energy_opex = self.other_utility + self.non_utility_expense - self.total_opex = self.energy_opex + self.net_non_energy_opex - self.noi = self.revenue - self.total_opex - - -class Income_Statement_Table(): - """ - Create a income statement table, containing multiple years, including historical and projected data - Key Attributes are: - hist_table (list): list of single year income_statement objects, containing historical data - table(list): list of single year income_statement objects, containing historical and projected data - """ - - def __init__(self, raw_income_input, annual_bill_table, analysis_date): - """ - Create hist_table to store historical income statement data, and calculate some key characters. - Args: - raw_income_input (dictionary): dict of dict of incomplete income statement, for historical years. Key = year - annual_bill_table (dictionary): dictionary of dictionary of annual bills, for 4 utility_types - analysis_date (dictionary): proforma's starting date and the years of proforma - - Key Attributes: - cagr (float): compound annual growth rate - other_utility_percent (float): percentage, (average other_utility / average revenue) - non_utility_expense_percent (float): percentage, (average non_utility_expense_percent / average revenue) - hist_table (list): list of single year income_statement objects, containing historical data - table(list): list of single year income_statement objects, containing historical and projected data - characters (dictionary): contains key characters determined from historical data. Is used to project - - Description: - raw_income_input = {2014: {'revenue': 90.0, 'utility_expense': 55.0, 'non_utility_expense': 35.0}, 2015:{},} - annual_bill_table = {'electricity': electricity_bill, 'oil': oil_bill, 'gas': gas_bill, 'water': water_bill} - electricity_bill = {2014: 100, 2015:200, ...} - characters = { - 'start_year': (int) 2014, - 'end_year': (int) 2016, - 'cagr': (float) 0.054, - 'other_utility_percent': (float) 0.02, - 'non_utility_expense_percent': (float) 0.03, - 'revenue_average': (float) 3000.00 - } - - Error Validation: - raw_income_input: - year should not be empty. - year should be covered by analysis date. Raise: change analysis date - any year should contain 4 raw inputs. - annual_bill_table: - annual_bill_table years should cover proforma years - """ - self.hist_start_year = None - self.hist_end_year = None - self.cagr = 0.00 - self.other_utility_percent = 0.00 - self.non_utility_expense_percent = 0.00 - self.revenue_average = 0.00 # average revenue - self.hist_table = [] - self.table = [] - self.characters = {} - self.analysis_date = analysis_date - - for year in raw_income_input: - current_income_statement = Income_Statement() - current_income_statement.put_hist(year, raw_income_input[year], - annual_bill_table) - self.hist_table.append(current_income_statement) - - sorted_income_hist_year = sorted(raw_income_input) - self.hist_start_year = sorted_income_hist_year[0] - self.hist_end_year = sorted_income_hist_year[-1] - # if start_year == None: return None - self.cagr = lib.cal_cagr( - raw_income_input[self.hist_start_year]['revenue'], - raw_income_input[self.hist_end_year]['revenue'], - self.hist_end_year - self.hist_start_year) - - revenue_sum = 0 - other_utility_sum = 0 - non_utility_expense_sum = 0 - for current_income_statement in self.hist_table: - revenue_sum += current_income_statement.revenue - other_utility_sum += current_income_statement.other_utility - non_utility_expense_sum += current_income_statement.non_utility_expense - - self.other_utility_percent = other_utility_sum / revenue_sum - self.non_utility_expense_percent = non_utility_expense_sum / revenue_sum - self.revenue_average = revenue_sum / ( - self.hist_end_year - self.hist_start_year + 1) - - self.table = self.hist_table - self.characters = { - 'start_year': self.hist_start_year, - 'end_year': self.hist_end_year, - 'cagr': self.cagr, - 'other_utility_percent': self.other_utility_percent, - 'non_utility_expense_percent': self.non_utility_expense_percent, - 'revenue_average': self.revenue_average - } - - def project(self, growth_rate_flag, annual_bill_table): - """ - Project future income statement. Append multiple single year income_statement objects to self.table - Args: - growth_rate_flag (float): indicating assumed growth rate, -2.0 == cagr, -1.0 == historical average - annual_bill_table (dictionary): dictionary of dictionary of annual bills, for 4 utility_types - Return: - list: list of single year income_statement objects, containing historical and projection - Note: - project() overwrites existing projection data - """ - # characters = copy.deepcopy(self.characters) - proforma_year = form_bill_year(self.analysis_date['proforma_start'], - self.analysis_date['proforma_duration']) - current_table = copy.deepcopy(self.hist_table) - for year in proforma_year: - last_revenue = current_table[-1].revenue - if year <= current_table[-1].year: - continue - current_income_statement = Income_Statement_Next( - year, last_revenue, growth_rate_flag, self.characters, - annual_bill_table) - current_table.append(current_income_statement) - self.table = current_table - # return current_table - - def get_hist_table(self): - """ - Get historical table, in dictionary formatting - Return: - dictionary: dict of dict of income statement. Key is year - Description: - hist_table_dict = {2014: {'year': 2014, 'revenue': 100.0, ..., 'not': 5.0}, ... , 2016:{}} - """ - hist_table_dict = {} - for current_income_statement in self.hist_table: - hist_table_dict[current_income_statement.year] = { - 'year': current_income_statement.year, - 'revenue': current_income_statement.revenue, - 'utility_expense': current_income_statement.utility_expense, - 'energy_opex': current_income_statement.energy_opex, - 'electricity_opex': current_income_statement.electricity_opex, - 'gas_opex': current_income_statement.gas_opex, - 'oil_opex': current_income_statement.oil_opex, - 'water_opex': current_income_statement.water_opex, - 'other_utility': current_income_statement.other_utility, - 'non_utility_expense': current_income_statement.non_utility_expense, - 'net_non_energy_opex': current_income_statement.net_non_energy_opex, - 'total_opex': current_income_statement.total_opex, - 'noi': current_income_statement.noi - } - return hist_table_dict - - def get_cagr(self): - """ - Get compound annual growth rate - Return: - float: compound annual growth rate - """ - return copy.deepcopy(self.cagr) - - def get_average(self): - """ - Get average income statement. Only need initialized Income_Statement_Table - Return: - dictionary: dict of average income statement, Keys are income statement items. - Description: - output_dict = {'year': None, 'revenue': 95000.0, ... ,'noi': 35166.666666666657} - """ - # current_year = 'Average' - current_income_statement = Income_Statement() - average_revenue = mean(list(i_s.revenue for i_s in self.hist_table)) - annual_bills = { - 'electricity': - mean(list(i_s.electricity_opex for i_s in self.hist_table)), - 'gas': - mean(list(i_s.gas_opex for i_s in self.hist_table)), - 'oil': - mean(list(i_s.oil_opex for i_s in self.hist_table)), - 'water': - mean(list(i_s.water_opex for i_s in self.hist_table)) - } - current_income_statement.put_average(average_revenue, annual_bills, self.characters) - return convert_income_statement_class(current_income_statement) - - def get_single_year(self, year): - """ - Get single year income statement from self.table. Table can either contain or not contain projection - Args: - year (int): the year that need to be extracted - Return: - dict: single year income statement. Keys are income statement items. - Note: - if the target year is not in self.table, then return None. - """ - for current_income_statement in self.table: - if current_income_statement.year == year: - return { - 'year': current_income_statement.year, - 'revenue': current_income_statement.revenue, - 'utility_expense': current_income_statement.utility_expense, - 'energy_opex': current_income_statement.energy_opex, - 'electricity_opex': current_income_statement.electricity_opex, - 'gas_opex': current_income_statement.gas_opex, - 'oil_opex': current_income_statement.oil_opex, - 'water_opex': current_income_statement.water_opex, - 'other_utility': current_income_statement.other_utility, - 'non_utility_expense': current_income_statement.non_utility_expense, - 'net_non_energy_opex': current_income_statement.net_non_energy_opex, - 'total_opex': current_income_statement.total_opex, - 'noi': current_income_statement.noi - } - return None - - def get_noi_dict(self): - """ - Get a dictionary of net operating income. - Return: - dictionary: net operating income for each year in income statement table. Key is year - """ - noi_dict = {} - for current_income_statement in self.table: - noi_dict[ - current_income_statement.year] = current_income_statement.noi - return noi_dict - - def get_first_year_noi(self, commission_date): - """ - Get first year noi after commissioning year, from post_saving income statement - Args: - commission_date (date): construction finishing date. Saving starts NEXT month/year - Return: - float: noi of the next year after commission date - """ - first_year = commission_date.year + 1 - for current_income_statement in self.table: - if current_income_statement.year == first_year: - return current_income_statement.noi - - def get_full_income_table(self): - """ - Get full projected income statement table - Return: - dictionary: dict of dict of income statement. Key is year - """ - # validate projection availability - if self.table[-1].year <= self.hist_end_year: - raise ValueError('income statement is not projected properly') - table_dict = {} - for current_income_statement in self.table: - table_dict[current_income_statement.year] = { - 'year': current_income_statement.year, - 'revenue': current_income_statement.revenue, - 'utility_expense': current_income_statement.utility_expense, - 'energy_opex': current_income_statement.energy_opex, - 'electricity_opex': current_income_statement.electricity_opex, - 'gas_opex': current_income_statement.gas_opex, - 'oil_opex': current_income_statement.oil_opex, - 'water_opex': current_income_statement.water_opex, - 'other_utility': current_income_statement.other_utility, - 'non_utility_expense': current_income_statement.non_utility_expense, - 'net_non_energy_opex': current_income_statement.net_non_energy_opex, - 'total_opex': current_income_statement.total_opex, - 'noi': current_income_statement.noi - } - return table_dict - - def get_total_energy_dict(self): - total_energy_dict = {} - for current_income_statement in self.table: - total_energy_dict[ - current_income_statement.year] = current_income_statement.energy_opex - return total_energy_dict +# class Income_Statement(): +# def __init__(self): +# self.year = None +# self.revenue = None +# self.utility_expense = None +# self.non_utility_expense = None +# self.electricity_opex = None +# self.gas_opex = None +# self.oil_opex = None +# self.water_opex = None +# self.energy_opex = None +# self.other_utility = None +# self.net_non_energy_opex = None +# self.total_opex = None +# self.noi = None +# # energy_debt_service = +# # other_debt_service = +# # total_debt_service = +# # bill_saving = +# # energy_DSCR = +# # total_DSCR = + +# def put_hist(self, year, income_input, annual_bill_table): +# """ +# Put historical income statement data and generate a single year income statement +# Inputs are incomplete income statement items, and energy bill overview +# Final output is an single year income_statement objectvie with standarized items filled + +# Args: +# year (int): the year of this income statement +# income_input (dictionary): 3 elements of inputs +# annual_bill_table (dictionary): annual bill, for 4 utility_types + +# Description Sample: +# income_input = {revenue': 100000, 'utility_expense': 60000,'non_utility_expense': 3000} +# annual_bill_table = {'electricity': electricity_bill, 'oil': oil_bill, 'gas': gas_bill, 'water': water_bill} +# """ +# self.year = year +# self.revenue = income_input['revenue'] +# self.utility_expense = income_input['utility_expense'] +# self.non_utility_expense = income_input['non_utility_expense'] +# self.electricity_opex = annual_bill_table['electricity'][self.year] +# self.gas_opex = annual_bill_table['gas'][self.year] +# self.oil_opex = annual_bill_table['oil'][self.year] +# self.water_opex = annual_bill_table['water'][self.year] +# self.energy_opex = self.electricity_opex + self.oil_opex + self.gas_opex + self.water_opex +# self.other_utility = self.utility_expense - self.energy_opex +# self.net_non_energy_opex = self.other_utility + self.non_utility_expense +# self.total_opex = self.energy_opex + self.net_non_energy_opex +# self.noi = self.revenue - self.total_opex # net operating income + +# def put_average(self, average_revenue, annual_bills, characters): +# """ +# Calculate and create average income statement. +# Revenue, energy bills are average of historical data. +# Other items are calculated by historical characters. +# Args: +# average_revenue (float): average revenue calculated from historical income statements +# annual_bills (dictionary): dictionary of float value of average annual bills, for 4 utility_types +# characters (dictionary): 6 characters calculated from historical income statements +# Final instance is a single year income statement without named year + +# Description: +# characters = { +# 'start_year': (int) 2014, +# 'end_year': (int) 2016, +# 'cagr': (float) 0.054, +# 'other_utility_percent': (float) 0.020 == 2.0% +# 'non_utility_expense_percent': (float) 0.030 == 3.0% +# 'revenue_average': (float) 3000.00 +# } +# annual_bills = {'electricity': 100.0, 'oil': 200.0, 'gas': 300.0, 'water': 400.0} +# """ +# self.revenue = average_revenue +# self.electricity_opex = annual_bills['electricity'] +# self.gas_opex = annual_bills['gas'] +# self.oil_opex = annual_bills['oil'] +# self.water_opex = annual_bills['water'] +# self.energy_opex = self.electricity_opex + self.gas_opex + self.oil_opex + self.water_opex +# self.other_utility = self.revenue * characters['other_utility_percent'] +# self.non_utility_expense = self.revenue * characters[ +# 'non_utility_expense_percent'] +# self.utility_expense = self.energy_opex + self.other_utility +# self.net_non_energy_opex = self.other_utility + self.non_utility_expense +# self.total_opex = self.energy_opex + self.net_non_energy_opex +# self.noi = self.revenue - self.total_opex + + +# def convert_income_statement_class(income_statement_class): +# """ +# Convert single year income statement object into a dictionary format +# Args: +# income_statement_class (object): single year income statement object +# Return: +# income_statement_dict (dictionary) +# """ +# income_statement_dict = { +# 'year': income_statement_class.year, +# 'revenue': income_statement_class.revenue, +# 'utility_expense': income_statement_class.utility_expense, +# 'energy_opex': income_statement_class.energy_opex, +# 'electricity_opex': income_statement_class.electricity_opex, +# 'gas_opex': income_statement_class.gas_opex, +# 'oil_opex': income_statement_class.oil_opex, +# 'water_opex': income_statement_class.water_opex, +# 'other_utility': income_statement_class.other_utility, +# 'non_utility_expense': income_statement_class.non_utility_expense, +# 'net_non_energy_opex': income_statement_class.net_non_energy_opex, +# 'total_opex': income_statement_class.total_opex, +# 'noi': income_statement_class.noi +# } +# return income_statement_dict + + +# class Income_Statement_Next(): +# """ +# Create single year income_statement object, +# with input of last year data, income statement characters, and projected annual bill +# """ + +# def __init__(self, year, last_revenue, growth_rate_flag, characters, annual_bill_table): +# """ +# Calculation is done in initiation. +# Args: +# year (int): the year that will be projected on +# last_revenue (float): last year revenue +# growth_rate_flag (float): indicating assumed growth rate, -2.0 == cagr, -1.0 == historical average +# characters (dictionary): 6 characters calculated from historical income statements +# annual_bill_table (dictionary): dictionary of dictionary of annual bills, for 4 utility_types +# Final instance is a single year income_statement object + +# Description: +# characters = { +# 'start_year': (int) 2014, +# 'end_year': (int) 2016, +# 'cagr': (float) 0.054, +# 'other_utility_percent': (float) 0.020 == 2.0% +# 'non_utility_expense_percent': (float) 0.035 == 3.5% +# 'revenue_average': (float) 3000.00 +# } +# annual_bill_table = {'electricity': electricity_bill, 'oil': oil_bill, 'gas': gas_bill, 'water': water_bill} +# electricity_bill = {2014: 100, 2015:200, ...} +# """ +# self.year = year + +# if growth_rate_flag == -1.0: # growth_rate_flag == average +# current_revenue = characters['revenue_average'] +# else: +# if growth_rate_flag == -2.0: # growth_rate_flag == cagr +# growth_rate = characters['cagr'] +# else: +# growth_rate = growth_rate_flag # growth_rate_flag == 0.00, 0.01, ... +# current_revenue = last_revenue * (1 + growth_rate) +# self.revenue = current_revenue +# self.electricity_opex = annual_bill_table['electricity'][self.year] +# self.gas_opex = annual_bill_table['gas'][self.year] +# self.oil_opex = annual_bill_table['oil'][self.year] +# self.water_opex = annual_bill_table['water'][self.year] +# self.energy_opex = self.electricity_opex + self.gas_opex + self.oil_opex + self.water_opex +# self.other_utility = self.revenue * characters['other_utility_percent'] +# self.non_utility_expense = self.revenue * characters[ +# 'non_utility_expense_percent'] +# self.utility_expense = self.energy_opex + self.other_utility +# self.net_non_energy_opex = self.other_utility + self.non_utility_expense +# self.total_opex = self.energy_opex + self.net_non_energy_opex +# self.noi = self.revenue - self.total_opex + + +# class Income_Statement_Table(): +# """ +# Create a income statement table, containing multiple years, including historical and projected data +# Key Attributes are: +# hist_table (list): list of single year income_statement objects, containing historical data +# table(list): list of single year income_statement objects, containing historical and projected data +# """ + +# def __init__(self, raw_income_input, annual_bill_table, analysis_date): +# """ +# Create hist_table to store historical income statement data, and calculate some key characters. +# Args: +# raw_income_input (dictionary): dict of dict of incomplete income statement, for historical years. Key = year +# annual_bill_table (dictionary): dictionary of dictionary of annual bills, for 4 utility_types +# analysis_date (dictionary): proforma's starting date and the years of proforma + +# Key Attributes: +# cagr (float): compound annual growth rate +# other_utility_percent (float): percentage, (average other_utility / average revenue) +# non_utility_expense_percent (float): percentage, (average non_utility_expense_percent / average revenue) +# hist_table (list): list of single year income_statement objects, containing historical data +# table(list): list of single year income_statement objects, containing historical and projected data +# characters (dictionary): contains key characters determined from historical data. Is used to project + +# Description: +# raw_income_input = {2014: {'revenue': 90.0, 'utility_expense': 55.0, 'non_utility_expense': 35.0}, 2015:{},} +# annual_bill_table = {'electricity': electricity_bill, 'oil': oil_bill, 'gas': gas_bill, 'water': water_bill} +# electricity_bill = {2014: 100, 2015:200, ...} +# characters = { +# 'start_year': (int) 2014, +# 'end_year': (int) 2016, +# 'cagr': (float) 0.054, +# 'other_utility_percent': (float) 0.02, +# 'non_utility_expense_percent': (float) 0.03, +# 'revenue_average': (float) 3000.00 +# } + +# Error Validation: +# raw_income_input: +# year should not be empty. +# year should be covered by analysis date. Raise: change analysis date +# any year should contain 4 raw inputs. +# annual_bill_table: +# annual_bill_table years should cover proforma years +# """ +# self.hist_start_year = None +# self.hist_end_year = None +# self.cagr = 0.00 +# self.other_utility_percent = 0.00 +# self.non_utility_expense_percent = 0.00 +# self.revenue_average = 0.00 # average revenue +# self.hist_table = [] +# self.table = [] +# self.characters = {} +# self.analysis_date = analysis_date + +# for year in raw_income_input: +# current_income_statement = Income_Statement() +# current_income_statement.put_hist(year, raw_income_input[year], +# annual_bill_table) +# self.hist_table.append(current_income_statement) + +# sorted_income_hist_year = sorted(raw_income_input) +# self.hist_start_year = sorted_income_hist_year[0] +# self.hist_end_year = sorted_income_hist_year[-1] +# # if start_year == None: return None +# self.cagr = lib.cal_cagr( +# raw_income_input[self.hist_start_year]['revenue'], +# raw_income_input[self.hist_end_year]['revenue'], +# self.hist_end_year - self.hist_start_year) + +# revenue_sum = 0 +# other_utility_sum = 0 +# non_utility_expense_sum = 0 +# for current_income_statement in self.hist_table: +# revenue_sum += current_income_statement.revenue +# other_utility_sum += current_income_statement.other_utility +# non_utility_expense_sum += current_income_statement.non_utility_expense + +# self.other_utility_percent = other_utility_sum / revenue_sum +# self.non_utility_expense_percent = non_utility_expense_sum / revenue_sum +# self.revenue_average = revenue_sum / ( +# self.hist_end_year - self.hist_start_year + 1) + +# self.table = self.hist_table +# self.characters = { +# 'start_year': self.hist_start_year, +# 'end_year': self.hist_end_year, +# 'cagr': self.cagr, +# 'other_utility_percent': self.other_utility_percent, +# 'non_utility_expense_percent': self.non_utility_expense_percent, +# 'revenue_average': self.revenue_average +# } + +# def project(self, growth_rate_flag, annual_bill_table): +# """ +# Project future income statement. Append multiple single year income_statement objects to self.table +# Args: +# growth_rate_flag (float): indicating assumed growth rate, -2.0 == cagr, -1.0 == historical average +# annual_bill_table (dictionary): dictionary of dictionary of annual bills, for 4 utility_types +# Return: +# list: list of single year income_statement objects, containing historical and projection +# Note: +# project() overwrites existing projection data +# """ +# # characters = copy.deepcopy(self.characters) +# proforma_year = form_bill_year(self.analysis_date['proforma_start'], +# self.analysis_date['proforma_duration']) +# current_table = copy.deepcopy(self.hist_table) +# for year in proforma_year: +# last_revenue = current_table[-1].revenue +# if year <= current_table[-1].year: +# continue +# current_income_statement = Income_Statement_Next( +# year, last_revenue, growth_rate_flag, self.characters, +# annual_bill_table) +# current_table.append(current_income_statement) +# self.table = current_table +# # return current_table + +# def get_hist_table(self): +# """ +# Get historical table, in dictionary formatting +# Return: +# dictionary: dict of dict of income statement. Key is year +# Description: +# hist_table_dict = {2014: {'year': 2014, 'revenue': 100.0, ..., 'not': 5.0}, ... , 2016:{}} +# """ +# hist_table_dict = {} +# for current_income_statement in self.hist_table: +# hist_table_dict[current_income_statement.year] = { +# 'year': current_income_statement.year, +# 'revenue': current_income_statement.revenue, +# 'utility_expense': current_income_statement.utility_expense, +# 'energy_opex': current_income_statement.energy_opex, +# 'electricity_opex': current_income_statement.electricity_opex, +# 'gas_opex': current_income_statement.gas_opex, +# 'oil_opex': current_income_statement.oil_opex, +# 'water_opex': current_income_statement.water_opex, +# 'other_utility': current_income_statement.other_utility, +# 'non_utility_expense': current_income_statement.non_utility_expense, +# 'net_non_energy_opex': current_income_statement.net_non_energy_opex, +# 'total_opex': current_income_statement.total_opex, +# 'noi': current_income_statement.noi +# } +# return hist_table_dict + +# def get_cagr(self): +# """ +# Get compound annual growth rate +# Return: +# float: compound annual growth rate +# """ +# return copy.deepcopy(self.cagr) + +# def get_average(self): +# """ +# Get average income statement. Only need initialized Income_Statement_Table +# Return: +# dictionary: dict of average income statement, Keys are income statement items. +# Description: +# output_dict = {'year': None, 'revenue': 95000.0, ... ,'noi': 35166.666666666657} +# """ +# # current_year = 'Average' +# current_income_statement = Income_Statement() +# average_revenue = mean(list(i_s.revenue for i_s in self.hist_table)) +# annual_bills = { +# 'electricity': +# mean(list(i_s.electricity_opex for i_s in self.hist_table)), +# 'gas': +# mean(list(i_s.gas_opex for i_s in self.hist_table)), +# 'oil': +# mean(list(i_s.oil_opex for i_s in self.hist_table)), +# 'water': +# mean(list(i_s.water_opex for i_s in self.hist_table)) +# } +# current_income_statement.put_average(average_revenue, annual_bills, self.characters) +# return convert_income_statement_class(current_income_statement) + +# def get_single_year(self, year): +# """ +# Get single year income statement from self.table. Table can either contain or not contain projection +# Args: +# year (int): the year that need to be extracted +# Return: +# dict: single year income statement. Keys are income statement items. +# Note: +# if the target year is not in self.table, then return None. +# """ +# for current_income_statement in self.table: +# if current_income_statement.year == year: +# return { +# 'year': current_income_statement.year, +# 'revenue': current_income_statement.revenue, +# 'utility_expense': current_income_statement.utility_expense, +# 'energy_opex': current_income_statement.energy_opex, +# 'electricity_opex': current_income_statement.electricity_opex, +# 'gas_opex': current_income_statement.gas_opex, +# 'oil_opex': current_income_statement.oil_opex, +# 'water_opex': current_income_statement.water_opex, +# 'other_utility': current_income_statement.other_utility, +# 'non_utility_expense': current_income_statement.non_utility_expense, +# 'net_non_energy_opex': current_income_statement.net_non_energy_opex, +# 'total_opex': current_income_statement.total_opex, +# 'noi': current_income_statement.noi +# } +# return None + +# def get_noi_dict(self): +# """ +# Get a dictionary of net operating income. +# Return: +# dictionary: net operating income for each year in income statement table. Key is year +# """ +# noi_dict = {} +# for current_income_statement in self.table: +# noi_dict[ +# current_income_statement.year] = current_income_statement.noi +# return noi_dict + +# def get_first_year_noi(self, commission_date): +# """ +# Get first year noi after commissioning year, from post_saving income statement +# Args: +# commission_date (date): construction finishing date. Saving starts NEXT month/year +# Return: +# float: noi of the next year after commission date +# """ +# first_year = commission_date.year + 1 +# for current_income_statement in self.table: +# if current_income_statement.year == first_year: +# return current_income_statement.noi + +# def get_full_income_table(self): +# """ +# Get full projected income statement table +# Return: +# dictionary: dict of dict of income statement. Key is year +# """ +# # validate projection availability +# if self.table[-1].year <= self.hist_end_year: +# raise ValueError('income statement is not projected properly') +# table_dict = {} +# for current_income_statement in self.table: +# table_dict[current_income_statement.year] = { +# 'year': current_income_statement.year, +# 'revenue': current_income_statement.revenue, +# 'utility_expense': current_income_statement.utility_expense, +# 'energy_opex': current_income_statement.energy_opex, +# 'electricity_opex': current_income_statement.electricity_opex, +# 'gas_opex': current_income_statement.gas_opex, +# 'oil_opex': current_income_statement.oil_opex, +# 'water_opex': current_income_statement.water_opex, +# 'other_utility': current_income_statement.other_utility, +# 'non_utility_expense': current_income_statement.non_utility_expense, +# 'net_non_energy_opex': current_income_statement.net_non_energy_opex, +# 'total_opex': current_income_statement.total_opex, +# 'noi': current_income_statement.noi +# } +# return table_dict + +# def get_total_energy_dict(self): +# total_energy_dict = {} +# for current_income_statement in self.table: +# total_energy_dict[ +# current_income_statement.year] = current_income_statement.energy_opex +# return total_energy_dict class Balance_Sheet(): diff --git a/bpfin/tests/test_financials/test_financial_income.py b/bpfin/tests/test_financials/test_financial_income.py index b43e819..f92f427 100644 --- a/bpfin/tests/test_financials/test_financial_income.py +++ b/bpfin/tests/test_financials/test_financial_income.py @@ -8,3 +8,30 @@ def test_validate_growth(): output_list = [True, True, True, False, True, False, True, False, False] for (growth, validation) in zip(input_list, output_list): assert validation == validate_growth_rate_flag(growth) + +# Income_Statement_Table is tested in test_back_end_call.py +# def test_Income_Statement_Table(): +# input_raw_income_input = db.raw_income_input +# input_annual_bill_table = db.bill_overview_organized +# output_cagr = 0.05409255338945984 +# output_hist_table = db.income_statement_full +# output_average_table = db.income_statement_average +# output_noi_dict = db.noi_dict_average +# output_single_year = db.income_statement_2017_avg +# output_first_year_noi = 33165.377210606544 + +# IS_table = Income_Statement_Table( +# input_raw_income_input, +# input_annual_bill_table, +# db.analysis_date) +# IS_table.project(-1.0, db.bill_overview_organized) + +# assert IS_table.get_cagr() == output_cagr # test get_cagr +# assert IS_table.get_hist_table() == output_hist_table # test get_hist_table +# assert IS_table.get_average() == output_average_table # test get_average +# assert IS_table.get_noi_dict() == output_noi_dict # test get_noi_dict +# assert IS_table.get_single_year( +# 2017) == output_single_year # test get_single_year +# print(IS_table.get_single_year(2018)) +# assert IS_table.get_first_year_noi(datetime.date(2017, 3, 14)) == output_first_year_noi + diff --git a/bpfin/tests/test_financials/test_financial_lib.py b/bpfin/tests/test_financials/test_financial_lib.py index e24e1b6..f77ace8 100644 --- a/bpfin/tests/test_financials/test_financial_lib.py +++ b/bpfin/tests/test_financials/test_financial_lib.py @@ -1,7 +1,7 @@ import datetime import bpfin.financials.financial_lib as fl from bpfin.tests.testdata import sample_data as db -from bpfin.financials.financial_lib import Income_Statement_Table +from bpfin.financials.financial_income import Income_Statement_Table from bpfin.financials.financial_lib import Balance_Sheet_Table @@ -14,32 +14,6 @@ def test_organize_bill_overview(): assert output_dict == result_dict -def test_Income_Statement_Table(): - input_raw_income_input = db.raw_income_input - input_annual_bill_table = db.bill_overview_organized - output_cagr = 0.05409255338945984 - output_hist_table = db.income_statement_full - output_average_table = db.income_statement_average - output_noi_dict = db.noi_dict_average - output_single_year = db.income_statement_2017_avg - output_first_year_noi = 33165.377210606544 - - IS_table = Income_Statement_Table( - input_raw_income_input, - input_annual_bill_table, - db.analysis_date) - IS_table.project(-1.0, db.bill_overview_organized) - - assert IS_table.get_cagr() == output_cagr # test get_cagr - assert IS_table.get_hist_table() == output_hist_table # test get_hist_table - assert IS_table.get_average() == output_average_table # test get_average - assert IS_table.get_noi_dict() == output_noi_dict # test get_noi_dict - assert IS_table.get_single_year( - 2017) == output_single_year # test get_single_year - print(IS_table.get_single_year(2018)) - assert IS_table.get_first_year_noi(datetime.date(2017, 3, 14)) == output_first_year_noi - - def test_Balance_Sheet_Table(): input_raw_balance_sheet = db.raw_balance_sheet output_hist_balance_sheet_table = db.hist_balance_sheet -- GitLab From 89817939954fb6e225ba2a4e37747ce9029f3098 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Wed, 31 May 2017 23:57:06 -0400 Subject: [PATCH 26/37] Structure out backend call prelim_scenario(). Will need detail clean up. Balance_Sheet_Table need more work after merging from refactoring --- bpfin/financials/financial_lib.py | 5 +- bpfin/financials/scenario.py | 78 +++++++++--------- bpfin/lib/back_end_call.py | 82 +++++++++++++------ .../test_balance_sheet_projection.py | 1 - bpfin/tests/test_lib/test_back_end_call.py | 6 +- 5 files changed, 103 insertions(+), 69 deletions(-) diff --git a/bpfin/financials/financial_lib.py b/bpfin/financials/financial_lib.py index 43a218f..97c4151 100644 --- a/bpfin/financials/financial_lib.py +++ b/bpfin/financials/financial_lib.py @@ -525,9 +525,8 @@ class Balance_Sheet(): """ self.year = year self.cash = balance_sheet_input['cash'][year] - self.other_debt_service = balance_sheet_input['other_debt_service'][ - year] - self.net_income = balance_sheet_input['net_income'][year] + self.other_debt_service = (balance_sheet_input['other_debt_service'][year] if year in balance_sheet_input['other_debt_service'] else 0) + self.net_income = (balance_sheet_input['net_income'][year] if year in balance_sheet_input['net_income'] else 0) def convert_balance_sheet_class(balance_sheet_class): diff --git a/bpfin/financials/scenario.py b/bpfin/financials/scenario.py index ca50967..c3f1f78 100644 --- a/bpfin/financials/scenario.py +++ b/bpfin/financials/scenario.py @@ -6,7 +6,7 @@ from bpfin.lib.other import add_year_dictionary, divide_dscr_dict, min_none_list from bpfin.utilbills.bill_lib import form_bill_year, annualizing_projection from bpfin.financials.liability import final_liability_dict from bpfin.financials.balance_sheet_projection import balance_sheet_projection -from bpfin.lib.back_end_call import prior_income_statement_table +# from bpfin.lib.back_end_call import prior_income_statement_table from bpfin.financials.financial_income import Income_Statement_Table from bpfin.financials.financial_lib import Balance_Sheet_Table @@ -311,41 +311,41 @@ class Scenario(): # # ***** ugly test that can be a guide for front end dev ***** -growth_toggle = 0.01 -prior_IS_table = Income_Statement_Table( - db.raw_income_input, - db.prior_annual_bill, - db.analysis_date) -prior_IS_table.project(growth_toggle, db.prior_annual_bill) -prior_BS_table = Balance_Sheet_Table(sdb.raw_balance_sheet) -prior_BS_table.project_balance_sheet( - db.analysis_date, - db.liability_dictionary, - prior_IS_table.get_noi_dict()) - -scenario = Scenario( - analysis_date=db.analysis_date, - commission_date=db.commission_date, - construction_cost=db.cost_estimation, - manual_input_dict=db.manual_input_dict, - prior_annual_bill_table=db.prior_annual_bill, - prior_income_statement_table=prior_IS_table, - other_debt_service=db.liability_dictionary, - growth_rate_flag=growth_toggle, - prior_balance_sheet_table=prior_BS_table, - loan_input_list=db.raw_loan_input_list -) - -prior_month_bill=monthly_bill(db.raw_bill_table, db.analysis_date)[2] -scenario.prelim_analysis( - prior_month_bill=prior_month_bill, - percent_saving_dict=db.percent_saving_dict, - full_saving_dict=db.full_saving_dict, - growth_rate_flag=growth_toggle, - req_dscr=db.req_dscr, - customer_preference=db.customer_preference) - -print(scenario.get_annual_debt_service()) -print(scenario.get_graph_dict()) -print(scenario.get_dscr()) -print(scenario.get_economics()) +# growth_toggle = 0.01 +# prior_IS_table = Income_Statement_Table( +# db.raw_income_input, +# db.prior_annual_bill, +# db.analysis_date) +# prior_IS_table.project(growth_toggle, db.prior_annual_bill) +# prior_BS_table = Balance_Sheet_Table(sdb.raw_balance_sheet) +# prior_BS_table.project_balance_sheet( +# db.analysis_date, +# db.liability_dictionary, +# prior_IS_table.get_noi_dict()) + +# scenario = Scenario( +# analysis_date=db.analysis_date, +# commission_date=db.commission_date, +# construction_cost=db.cost_estimation, +# manual_input_dict=db.manual_input_dict, +# prior_annual_bill_table=db.prior_annual_bill, +# prior_income_statement_table=prior_IS_table, +# other_debt_service=db.liability_dictionary, +# growth_rate_flag=growth_toggle, +# prior_balance_sheet_table=prior_BS_table, +# loan_input_list=db.raw_loan_input_list +# ) + +# prior_month_bill = monthly_bill(db.raw_bill_table, db.analysis_date)[2] +# scenario.prelim_analysis( +# prior_month_bill=prior_month_bill, +# percent_saving_dict=db.percent_saving_dict, +# full_saving_dict=db.full_saving_dict, +# growth_rate_flag=growth_toggle, +# req_dscr=db.req_dscr, +# customer_preference=db.customer_preference) + +# print(scenario.get_annual_debt_service()) +# print(scenario.get_graph_dict()) +# print(scenario.get_dscr()) +# print(scenario.get_economics()) diff --git a/bpfin/lib/back_end_call.py b/bpfin/lib/back_end_call.py index e3ef089..8205010 100644 --- a/bpfin/lib/back_end_call.py +++ b/bpfin/lib/back_end_call.py @@ -1,11 +1,10 @@ from bpfin.lib.other import UTILITY_TYPE_LIST from bpfin.utilbills.bill import Bill -# from bpfin.financials.financial_lib import Income_Statement_Table +from bpfin.financials.cash_balance import cash_balance +from bpfin.financials.liability import final_liability_dict from bpfin.financials.financial_income import Income_Statement_Table from bpfin.financials.financial_lib import Balance_Sheet_Table -# from bpfin.financials.scenario import Scenario from bpfin.tests.testdata import feature_data as db -from bpfin.financials.liability import final_liability_dict import pprint @@ -144,9 +143,12 @@ def annual_bill(raw_bill_table, raw_annual_bill_table, analysis_date): # return annual_bill_table -def prior_income_statement_table(raw_income_input, raw_bill_table, - raw_annual_bill_table, analysis_date, - growth_rate_flag): +def form_prior_income_table( + raw_income_input, + raw_bill_table, + raw_annual_bill_table, + analysis_date, + growth_rate_flag): """ Take in prior-annual_bill_table, and raw inputs of income statements Generate historical income statement, calculate its characters including CAGR and other percent ratios @@ -210,37 +212,54 @@ def prelim_scenario(raw_bill_table, raw_annual_bill_table, analysis_date, commission_date, construction_cost, percent_saving_dict, full_saving_dict, req_dscr, customer_preference): - + from bpfin.financials.scenario import Scenario prior_annual_bill_table, manual_input_dict = annual_bill( raw_bill_table, raw_annual_bill_table, analysis_date ) - liability = final_liability_dict(analysis_date, raw_liability_input,) - - prior_bs = Balance_Sheet_Table(balance_sheet_input) + prior_income_table = Income_Statement_Table(raw_income_input, prior_annual_bill_table, analysis_date) - prior_is = Income_Statement_Table(raw_income_input, annual_bill_table, - analysis_date) + cash_balance_dict = cash_balance(analysis_date, raw_cash_balance) + liability_dict = final_liability_dict(analysis_date, raw_liability_input,) - scenario_ob = Scenario(analysis_date, commission_date, construction_cost, - bill_overview, prior_income_statement_table, - raw_annual_bill_table, growth_rate_flag, prior_bs, - loan_input_list) + balance_sheet_input = { + 'cash': cash_balance_dict, + 'other_debt_service': liability_dict, + 'net_income': prior_income_table.get_noi_dict() + } - savings_scenario_ob = scenario_ob.prelim_analysis( - prior_month_bill, percent_saving_dict, full_saving_dict, - growth_rate_flag, req_dscr, customer_preference) + prior_income_table.project(growth_rate_flag, prior_annual_bill_table) + prior_bs = Balance_Sheet_Table(balance_sheet_input) - post_is = Income_Statement_Table( - raw_income_input, scenario_ob.get_post_energy_bill, analysis_date) + prior_bs.project_balance_sheet(analysis_date, liability_dict, prior_income_table.get_noi_dict()) + + scenario_ob = Scenario( + analysis_date=analysis_date, + commission_date=commission_date, + construction_cost=construction_cost, + manual_input_dict=manual_input_dict, + prior_annual_bill_table=prior_annual_bill_table, + prior_income_statement_table=prior_income_table, + other_debt_service=liability_dict, + growth_rate_flag=growth_rate_flag, + prior_balance_sheet_table=prior_bs, + loan_input_list=raw_loan_input_list) + + scenario_ob.prelim_analysis( + prior_month_bill=monthly_bill(raw_bill_table, analysis_date)[2], + percent_saving_dict=percent_saving_dict, + full_saving_dict=full_saving_dict, + growth_rate_flag=growth_rate_flag, + req_dscr=req_dscr, + customer_preference=customer_preference) # Define raw_annual_bill_table as a "get" of prior_bill # Define raw_bill_table as a "get" of prior_bill # Delete prior_annual_bill_table return { - 'prior_energy_bill': 'hello', - 'prior_income_statement': 'hello', + 'prior_energy_bill': prior_annual_bill_table, + 'prior_income_statement': prior_income_table.get_full_income_table(), 'prior_balance_sheet': 'hello', 'post_energy_bill': 'hello', 'post_income_statement': 'hello', @@ -273,3 +292,20 @@ def prelim_scenario(raw_bill_table, raw_annual_bill_table, # f = open('data_generation.py', 'w') # f.write(writein) # f.close() + +print(prelim_scenario( + raw_bill_table=db.raw_bill_table, + raw_annual_bill_table=db.raw_annual_bill_table, + raw_income_input=db.raw_income_input, + growth_rate_flag=-2.0, + raw_liability_input=db.raw_liability_input, + raw_cash_balance=db.raw_cash_balance, + raw_loan_input_list=db.raw_loan_input_list, + analysis_date=db.analysis_date, + commission_date=db.commission_date, + construction_cost=db.cost_estimation, + percent_saving_dict=db.percent_saving_dict, + full_saving_dict=db.full_saving_dict, + req_dscr=db.req_dscr, + customer_preference=db.customer_preference + )) diff --git a/bpfin/tests/test_financials/test_balance_sheet_projection.py b/bpfin/tests/test_financials/test_balance_sheet_projection.py index fc0cc9c..fdf7813 100644 --- a/bpfin/tests/test_financials/test_balance_sheet_projection.py +++ b/bpfin/tests/test_financials/test_balance_sheet_projection.py @@ -1,5 +1,4 @@ from bpfin.financials.balance_sheet_projection import balance_sheet_projection -from bpfin.financials.financial_lib import Income_Statement_Table from bpfin.tests.testdata import sample_data as db import datetime diff --git a/bpfin/tests/test_lib/test_back_end_call.py b/bpfin/tests/test_lib/test_back_end_call.py index 8e305d5..b23b975 100644 --- a/bpfin/tests/test_lib/test_back_end_call.py +++ b/bpfin/tests/test_lib/test_back_end_call.py @@ -1,4 +1,4 @@ -from bpfin.lib.back_end_call import monthly_bill, annual_bill, prior_income_statement_table +from bpfin.lib.back_end_call import monthly_bill, annual_bill, form_prior_income_table from bpfin.tests.testdata import feature_data as db from bpfin.tests.testdata import sample_data as sdb @@ -19,12 +19,12 @@ def test_annual_bill(): assert output_dict == result_dict -def test_prior_income_statement_table(): +def test_form_prior_income_table(): output_income_statement = db.prior_income_statement_cagr output_next_year_income = db.next_year_income output_average_income = db.average_income output_historical_cagr = db.historical_cagr - prior_income, next_year_income, average_income, historical_cagr = prior_income_statement_table( + prior_income, next_year_income, average_income, historical_cagr = form_prior_income_table( db.raw_income_input, db.raw_bill_table, db.raw_annual_bill_table, -- GitLab From b5f6c81d96bc0fb7b6849cd81c4da84c8a8318ae Mon Sep 17 00:00:00 2001 From: Sarey Hamarneh Date: Thu, 1 Jun 2017 18:00:05 -0400 Subject: [PATCH 27/37] Push --- bpfin/lib/back_end_call.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bpfin/lib/back_end_call.py b/bpfin/lib/back_end_call.py index 8205010..b51acc9 100644 --- a/bpfin/lib/back_end_call.py +++ b/bpfin/lib/back_end_call.py @@ -261,7 +261,7 @@ def prelim_scenario(raw_bill_table, raw_annual_bill_table, 'prior_energy_bill': prior_annual_bill_table, 'prior_income_statement': prior_income_table.get_full_income_table(), 'prior_balance_sheet': 'hello', - 'post_energy_bill': 'hello', + 'post_energy_bill': 'helloz', 'post_income_statement': 'hello', 'post_balance_sheet': 'hello', } -- GitLab From 5b8534f4bd83969820d872c049efc866defdb52c Mon Sep 17 00:00:00 2001 From: Sarey Hamarneh Date: Thu, 1 Jun 2017 18:07:14 -0400 Subject: [PATCH 28/37] Tasks --- bpfin/lib/back_end_call.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/bpfin/lib/back_end_call.py b/bpfin/lib/back_end_call.py index b51acc9..c41c3ee 100644 --- a/bpfin/lib/back_end_call.py +++ b/bpfin/lib/back_end_call.py @@ -229,6 +229,8 @@ def prelim_scenario(raw_bill_table, raw_annual_bill_table, } prior_income_table.project(growth_rate_flag, prior_annual_bill_table) + + # refactor balance sheet prior_bs = Balance_Sheet_Table(balance_sheet_input) prior_bs.project_balance_sheet(analysis_date, liability_dict, prior_income_table.get_noi_dict()) @@ -258,12 +260,14 @@ def prelim_scenario(raw_bill_table, raw_annual_bill_table, # Delete prior_annual_bill_table return { + # return code for graphs, so return the three bar graph things + 'prior_energy_bill': prior_annual_bill_table, 'prior_income_statement': prior_income_table.get_full_income_table(), 'prior_balance_sheet': 'hello', - 'post_energy_bill': 'helloz', - 'post_income_statement': 'hello', - 'post_balance_sheet': 'hello', + 'post_energy_bill': 'get from scenario', + 'post_income_statement': 'scenario', + 'post_balance_sheet': 'scenario', } -- GitLab From b217665272283db8f83b6ad0072eaf815372dbcc Mon Sep 17 00:00:00 2001 From: Sarey Hamarneh Date: Thu, 1 Jun 2017 18:07:30 -0400 Subject: [PATCH 29/37] Tasks --- bpfin/lib/back_end_call.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bpfin/lib/back_end_call.py b/bpfin/lib/back_end_call.py index c41c3ee..dc90e27 100644 --- a/bpfin/lib/back_end_call.py +++ b/bpfin/lib/back_end_call.py @@ -261,6 +261,7 @@ def prelim_scenario(raw_bill_table, raw_annual_bill_table, return { # return code for graphs, so return the three bar graph things + # scenario has something for graphs 'prior_energy_bill': prior_annual_bill_table, 'prior_income_statement': prior_income_table.get_full_income_table(), -- GitLab From 774ea6e82cc05d50c7b63e958f72a620a090b727 Mon Sep 17 00:00:00 2001 From: Sarey Hamarneh Date: Thu, 1 Jun 2017 21:27:48 -0400 Subject: [PATCH 30/37] Push changes --- bpfin/lib/back_end_call.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/bpfin/lib/back_end_call.py b/bpfin/lib/back_end_call.py index dc90e27..ff918b9 100644 --- a/bpfin/lib/back_end_call.py +++ b/bpfin/lib/back_end_call.py @@ -3,7 +3,7 @@ from bpfin.utilbills.bill import Bill from bpfin.financials.cash_balance import cash_balance from bpfin.financials.liability import final_liability_dict from bpfin.financials.financial_income import Income_Statement_Table -from bpfin.financials.financial_lib import Balance_Sheet_Table +from bpfin.financials.financial_balance import Balance_Sheet_Table from bpfin.tests.testdata import feature_data as db import pprint @@ -223,15 +223,14 @@ def prelim_scenario(raw_bill_table, raw_annual_bill_table, liability_dict = final_liability_dict(analysis_date, raw_liability_input,) balance_sheet_input = { - 'cash': cash_balance_dict, - 'other_debt_service': liability_dict, - 'net_income': prior_income_table.get_noi_dict() + 'cash_dictionary': cash_balance_dict, + 'other_debt_service_dictionary': liability_dict, + 'net_income_dictionary': prior_income_table.get_noi_dict() } prior_income_table.project(growth_rate_flag, prior_annual_bill_table) - # refactor balance sheet - prior_bs = Balance_Sheet_Table(balance_sheet_input) + prior_bs = Balance_Sheet_Table(cash_balance, liability_dict, prior_income_table.get_noi_dict()) prior_bs.project_balance_sheet(analysis_date, liability_dict, prior_income_table.get_noi_dict()) -- GitLab From de966ecb4ce75ed23b68207616bce19ec8530bfc Mon Sep 17 00:00:00 2001 From: Sarey Hamarneh Date: Thu, 1 Jun 2017 22:06:38 -0400 Subject: [PATCH 31/37] Finish scenario --- bpfin/financials/financial_balance.py | 1 - bpfin/financials/scenario.py | 2 +- bpfin/lib/back_end_call.py | 16 +++------------- bpfin/tests/test_financials/test_cash_balance.py | 5 ++--- 4 files changed, 6 insertions(+), 18 deletions(-) diff --git a/bpfin/financials/financial_balance.py b/bpfin/financials/financial_balance.py index b8643c9..a56472b 100644 --- a/bpfin/financials/financial_balance.py +++ b/bpfin/financials/financial_balance.py @@ -81,7 +81,6 @@ class Balance_Sheet_Table(): self.hist_balance_sheet_table = [] # entire table, not just historical self.bs_table = [] - for year in sorted(cash_balance_dictionary): current_balance_sheet = Balance_Sheet() if year in net_income_dictionary: diff --git a/bpfin/financials/scenario.py b/bpfin/financials/scenario.py index c3f1f78..b075d4d 100644 --- a/bpfin/financials/scenario.py +++ b/bpfin/financials/scenario.py @@ -8,7 +8,7 @@ from bpfin.financials.liability import final_liability_dict from bpfin.financials.balance_sheet_projection import balance_sheet_projection # from bpfin.lib.back_end_call import prior_income_statement_table from bpfin.financials.financial_income import Income_Statement_Table -from bpfin.financials.financial_lib import Balance_Sheet_Table +from bpfin.financials.financial_balance import Balance_Sheet_Table # may delete from here after sample built from bpfin.tests.testdata import feature_data as db diff --git a/bpfin/lib/back_end_call.py b/bpfin/lib/back_end_call.py index ff918b9..eb60d15 100644 --- a/bpfin/lib/back_end_call.py +++ b/bpfin/lib/back_end_call.py @@ -220,7 +220,7 @@ def prelim_scenario(raw_bill_table, raw_annual_bill_table, prior_income_table = Income_Statement_Table(raw_income_input, prior_annual_bill_table, analysis_date) cash_balance_dict = cash_balance(analysis_date, raw_cash_balance) - liability_dict = final_liability_dict(analysis_date, raw_liability_input,) + liability_dict = final_liability_dict(analysis_date, raw_liability_input) balance_sheet_input = { 'cash_dictionary': cash_balance_dict, @@ -230,7 +230,7 @@ def prelim_scenario(raw_bill_table, raw_annual_bill_table, prior_income_table.project(growth_rate_flag, prior_annual_bill_table) - prior_bs = Balance_Sheet_Table(cash_balance, liability_dict, prior_income_table.get_noi_dict()) + prior_bs = Balance_Sheet_Table(cash_balance_dict, liability_dict, prior_income_table.get_noi_dict()) prior_bs.project_balance_sheet(analysis_date, liability_dict, prior_income_table.get_noi_dict()) @@ -258,17 +258,7 @@ def prelim_scenario(raw_bill_table, raw_annual_bill_table, # Define raw_bill_table as a "get" of prior_bill # Delete prior_annual_bill_table - return { - # return code for graphs, so return the three bar graph things - # scenario has something for graphs - - 'prior_energy_bill': prior_annual_bill_table, - 'prior_income_statement': prior_income_table.get_full_income_table(), - 'prior_balance_sheet': 'hello', - 'post_energy_bill': 'get from scenario', - 'post_income_statement': 'scenario', - 'post_balance_sheet': 'scenario', - } + return scenario_ob.get_graph_dict() # **** ugly test **** diff --git a/bpfin/tests/test_financials/test_cash_balance.py b/bpfin/tests/test_financials/test_cash_balance.py index 03c2f1c..f9098fa 100644 --- a/bpfin/tests/test_financials/test_cash_balance.py +++ b/bpfin/tests/test_financials/test_cash_balance.py @@ -29,9 +29,8 @@ def test_cash_balance(): input_dictionary = { date(2014, 11, 1): (500, False), date(2015, 12, 31): (600, True), - date(2016, 11, 11): (500, False), - date(2016, 10, 10): (400, False) date(2016, 11, 11): (300, False), + date(2016, 10, 10): (400, False), date(2016, 10, 10): (500, False) } input_analysis_date = { @@ -49,7 +48,7 @@ def test_cash_balance(): 2013: 500, 2014: 500.0, 2015: 600, - 2016: 450.0 + 2016: 400.0 } result = cash_balance(input_analysis_date, input_dictionary) -- GitLab From 436aec80b29153c52358fa9da04ad4d12e3461e1 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Fri, 2 Jun 2017 01:56:43 -0400 Subject: [PATCH 32/37] Minor update --- bpfin/financials/financial_income.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bpfin/financials/financial_income.py b/bpfin/financials/financial_income.py index 5340d33..4c26066 100644 --- a/bpfin/financials/financial_income.py +++ b/bpfin/financials/financial_income.py @@ -11,6 +11,10 @@ from bpfin.lib.other import UTILITY_TYPE_LIST class Income_Statement(): + """ + Generate Income Statement for single year, with standard accounting line items + Will be called in Income_Statement_Table() class + """ def __init__(self): self.year = None self.revenue = None -- GitLab From a52faa3d3dcb9507949f086515e86b33a6ce3c61 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Fri, 2 Jun 2017 01:59:18 -0400 Subject: [PATCH 33/37] Replace utility_type_list --- bpfin/financials/financial_saving.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/bpfin/financials/financial_saving.py b/bpfin/financials/financial_saving.py index 09a6644..82bd4f7 100644 --- a/bpfin/financials/financial_saving.py +++ b/bpfin/financials/financial_saving.py @@ -6,6 +6,7 @@ from bpfin.utilbills.bill_lib import form_year_calendar from bpfin.utilbills.bill_lib import form_bill_calendar from bpfin.utilbills.bill_post_proj_rough import bill_post_proj_rough from bpfin.tests.testdata import sample_data as db +from bpfin.lib.other import UTILITY_TYPE_LIST class Saving(): @@ -284,11 +285,9 @@ class Saving_Overview(): 'charge': list, 'price': list} """ - utility_type_list = ['electricity', 'gas', 'oil', 'water'] - total_first_year_saving = 0 total_first_year_prior_charge = 0 - for utility in utility_type_list: + for utility in UTILITY_TYPE_LIST: is_manual_input = self.manual_input_dict[utility] utility_saving = Saving(is_manual_input, self.commissioning_date, self.proforma_date) @@ -355,8 +354,7 @@ class Saving_Overview(): } """ post_annual_bill_table = {} - utility_type_list = ['electricity', 'gas', 'oil', 'water'] - for utility_type in utility_type_list: + for utility_type in UTILITY_TYPE_LIST: post_annual_bill_table[utility_type] = copy.deepcopy( self.utility_saving_dict[utility_type].get_annual_proforma_charge()) return post_annual_bill_table -- GitLab From 1b900b7dbe30106b723cc5f947d90e140619c6ab Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Fri, 2 Jun 2017 02:05:41 -0400 Subject: [PATCH 34/37] Clean imports for scenario --- bpfin/financials/scenario.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/bpfin/financials/scenario.py b/bpfin/financials/scenario.py index b075d4d..cefc43f 100644 --- a/bpfin/financials/scenario.py +++ b/bpfin/financials/scenario.py @@ -1,19 +1,16 @@ import copy -# from bpfin.financials.saving import Saving_Overview from bpfin.financials.financial_saving import Saving_Overview from bpfin.financials.loan import Loan_List from bpfin.lib.other import add_year_dictionary, divide_dscr_dict, min_none_list from bpfin.utilbills.bill_lib import form_bill_year, annualizing_projection -from bpfin.financials.liability import final_liability_dict -from bpfin.financials.balance_sheet_projection import balance_sheet_projection -# from bpfin.lib.back_end_call import prior_income_statement_table -from bpfin.financials.financial_income import Income_Statement_Table -from bpfin.financials.financial_balance import Balance_Sheet_Table - # may delete from here after sample built -from bpfin.tests.testdata import feature_data as db -from bpfin.tests.testdata import sample_data as sdb -from bpfin.lib.back_end_call import monthly_bill +# from bpfin.tests.testdata import feature_data as db +# from bpfin.tests.testdata import sample_data as sdb +# from bpfin.lib.back_end_call import monthly_bill +# from bpfin.financials.liability import final_liability_dict +# from bpfin.financials.balance_sheet_projection import balance_sheet_projection +# from bpfin.financials.financial_income import Income_Statement_Table +# from bpfin.financials.financial_balance import Balance_Sheet_Table class Scenario(): -- GitLab From b33225125bcf9948a91de3f4bb067de278c69254 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Fri, 2 Jun 2017 02:10:50 -0400 Subject: [PATCH 35/37] Deepcopy and sort in financial_income --- bpfin/financials/financial_income.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bpfin/financials/financial_income.py b/bpfin/financials/financial_income.py index 4c26066..93532e4 100644 --- a/bpfin/financials/financial_income.py +++ b/bpfin/financials/financial_income.py @@ -252,7 +252,7 @@ class Income_Statement_Table(): self.characters = {} self.analysis_date = analysis_date - for year in raw_income_input.keys(): + for year in sorted(raw_income_input.keys()): current_income_statement = Income_Statement() current_income_statement.put_hist(year, raw_income_input[year], annual_bill_table) @@ -279,7 +279,7 @@ class Income_Statement_Table(): self.revenue_average = revenue_sum / ( self.hist_end_year - self.hist_start_year + 1) - self.table = self.hist_table + self.table = copy.deepcopy(self.hist_table) self.characters = { 'start_year': self.hist_start_year, 'end_year': self.hist_end_year, -- GitLab From 09d207235d7e0298079e3c17173072f535af3d54 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Fri, 2 Jun 2017 02:14:56 -0400 Subject: [PATCH 36/37] Replace utility_type_list in scenario --- bpfin/financials/scenario.py | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/bpfin/financials/scenario.py b/bpfin/financials/scenario.py index cefc43f..a027182 100644 --- a/bpfin/financials/scenario.py +++ b/bpfin/financials/scenario.py @@ -3,6 +3,7 @@ from bpfin.financials.financial_saving import Saving_Overview from bpfin.financials.loan import Loan_List from bpfin.lib.other import add_year_dictionary, divide_dscr_dict, min_none_list from bpfin.utilbills.bill_lib import form_bill_year, annualizing_projection +from bpfin.lib.other import UTILITY_TYPE_LIST # may delete from here after sample built # from bpfin.tests.testdata import feature_data as db # from bpfin.tests.testdata import sample_data as sdb @@ -73,10 +74,8 @@ class Scenario(): self.prior_annual_bill_table = copy.deepcopy(prior_annual_bill_table) - self.prior_income_statement_table = copy.deepcopy( - prior_income_statement_table) - self.prior_balance_sheet_table = copy.deepcopy( - prior_balance_sheet_table) + self.prior_income_statement_table = copy.deepcopy(prior_income_statement_table) + self.prior_balance_sheet_table = copy.deepcopy(prior_balance_sheet_table) self.post_income_statement_table = None self.post_balance_sheet_table = None @@ -143,17 +142,14 @@ class Scenario(): self.post_income_statement_table = post_income_statement_table # generate post_saving balance_sheet_table object - post_saving_noi_dict = copy.deepcopy( - self.post_income_statement_table.get_noi_dict()) - post_balance_sheet_table = copy.deepcopy( - self.prior_balance_sheet_table) + post_saving_noi_dict = copy.deepcopy(self.post_income_statement_table.get_noi_dict()) + post_balance_sheet_table = copy.deepcopy(self.prior_balance_sheet_table) post_balance_sheet_table.project_balance_sheet( self.analysis_date, self.other_debt_service, post_saving_noi_dict) self.post_balance_sheet_table = post_balance_sheet_table # allocate loan and get loan schedules - first_year_saving = copy.deepcopy( - self.saving_overview.get_total_first_year_saving()) + first_year_saving = copy.deepcopy(self.saving_overview.get_total_first_year_saving()) first_year_noi = copy.deepcopy( self.post_income_statement_table.get_first_year_noi( self.commission_date)) @@ -182,14 +178,12 @@ class Scenario(): """ proforma_year = form_bill_year(self.analysis_date['proforma_start'], self.analysis_date['proforma_duration']) - post_annual_bill_table = copy.deepcopy( - self.saving_overview.get_post_annual_bill_table()) - utility_type_list = ['electricity', 'gas', 'oil', 'water'] + post_annual_bill_table = copy.deepcopy(self.saving_overview.get_post_annual_bill_table()) post_energy_bill = {} for year in proforma_year: current_total_energy_bill = 0 - for utility_type in utility_type_list: + for utility_type in UTILITY_TYPE_LIST: current_total_energy_bill += post_annual_bill_table[ utility_type][year] post_energy_bill[year] = current_total_energy_bill @@ -258,8 +252,7 @@ class Scenario(): debt_dict = copy.deepcopy(self.get_annual_debt_service()) savings_dict = {} - utility_type_list = ['electricity', 'gas', 'oil', 'water'] - for utility_type in utility_type_list: + for utility_type in UTILITY_TYPE_LIST: savings_dict = add_year_dictionary( savings_dict, copy.deepcopy( -- GitLab From 26de3a9ad2b4b6096b4f2209860d3e68213ef698 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Fri, 2 Jun 2017 02:26:37 -0400 Subject: [PATCH 37/37] Clean up cash_balance test file, and formatting --- bpfin/financials/scenario.py | 35 +++++--------- bpfin/lib/back_end_call.py | 48 +++++++++---------- .../test_financials/test_cash_balance.py | 2 +- 3 files changed, 34 insertions(+), 51 deletions(-) diff --git a/bpfin/financials/scenario.py b/bpfin/financials/scenario.py index a027182..3e4405b 100644 --- a/bpfin/financials/scenario.py +++ b/bpfin/financials/scenario.py @@ -223,8 +223,7 @@ class Scenario(): graph_dict = {} proforma_bill = copy.deepcopy(self.get_post_energy_bill()) annual_debt_service = copy.deepcopy(self.get_annual_debt_service()) - prior_annual_bill = copy.deepcopy( - self.prior_income_statement_table.get_total_energy_dict()) + prior_annual_bill = copy.deepcopy(self.prior_income_statement_table.get_total_energy_dict()) net_saving_dict = {} for year in prior_annual_bill: net_saving_dict[ @@ -245,19 +244,16 @@ class Scenario(): dscr_dict = {'noi_dscr': noi_dscr, 'cash_dscr': cash_dscr, 'saving_dscr': saving_dscr} noi_dscr = {2017: 1.17, 2018: 1.98, ...} """ - noi_dict = copy.deepcopy( - self.post_income_statement_table.get_noi_dict()) - cash_dict = copy.deepcopy( - self.post_balance_sheet_table.get_cash_dict()) + noi_dict = copy.deepcopy(self.post_income_statement_table.get_noi_dict()) + cash_dict = copy.deepcopy(self.post_balance_sheet_table.get_cash_dict()) debt_dict = copy.deepcopy(self.get_annual_debt_service()) savings_dict = {} for utility_type in UTILITY_TYPE_LIST: savings_dict = add_year_dictionary( savings_dict, - copy.deepcopy( - self.saving_overview.get_utility_annual_saving_charge( - utility_type))) + copy.deepcopy(self.saving_overview.get_utility_annual_saving_charge(utility_type)) + ) dscr_dict = {} dscr_dict['noi_dscr'] = divide_dscr_dict(noi_dict, debt_dict) @@ -282,21 +278,12 @@ class Scenario(): dscr_dict = self.get_dscr() economics_overview = {} economics_overview['estimated_cost'] = self.construction_cost - economics_overview[ - 'overall_saving'] = self.saving_overview.get_total_saving_percent( - ) - economics_overview[ - 'first_year_saving'] = self.saving_overview.get_total_first_year_saving( - ) - economics_overview[ - 'simple_payback'] = self.saving_overview.get_simple_payback( - self.construction_cost) - economics_overview['min_saving_dscr'] = min_none_list( - dscr_dict['saving_dscr'].values()) - economics_overview['min_noi_dscr'] = min_none_list( - dscr_dict['noi_dscr'].values()) - economics_overview['min_cash_dscr'] = min_none_list( - dscr_dict['cash_dscr'].values()) + economics_overview['overall_saving'] = self.saving_overview.get_total_saving_percent() + economics_overview['first_year_saving'] = self.saving_overview.get_total_first_year_saving() + economics_overview['simple_payback'] = self.saving_overview.get_simple_payback(self.construction_cost) + economics_overview['min_saving_dscr'] = min_none_list(dscr_dict['saving_dscr'].values()) + economics_overview['min_noi_dscr'] = min_none_list(dscr_dict['noi_dscr'].values()) + economics_overview['min_cash_dscr'] = min_none_list(dscr_dict['cash_dscr'].values()) return economics_overview diff --git a/bpfin/lib/back_end_call.py b/bpfin/lib/back_end_call.py index eb60d15..74c02a6 100644 --- a/bpfin/lib/back_end_call.py +++ b/bpfin/lib/back_end_call.py @@ -4,8 +4,8 @@ from bpfin.financials.cash_balance import cash_balance from bpfin.financials.liability import final_liability_dict from bpfin.financials.financial_income import Income_Statement_Table from bpfin.financials.financial_balance import Balance_Sheet_Table -from bpfin.tests.testdata import feature_data as db -import pprint +# from bpfin.tests.testdata import feature_data as db +# import pprint # Bill Overview Monthly Input @@ -61,8 +61,7 @@ def monthly_bill(raw_bill_table, analysis_date): # raise ValueError( # 'Bill_Overview - monthly_bill has empty raw_bill_table') if not analysis_date: - raise ValueError( - 'Bill_Overview - monthly_bill has empty analysis_date') + raise ValueError('Bill_Overview - monthly_bill has empty analysis_date') bill_overview_dict = {} manual_input_dict = {} prior_month_bill_dict = {} @@ -191,15 +190,12 @@ def form_prior_income_table( prior_income = {2014: {'year': 2014, 'revenue': 100.0, ..., 'not': 5.0}, ... , 2016:{}} """ - annual_bill_table = annual_bill(raw_bill_table, raw_annual_bill_table, - analysis_date)[0] - income_table = Income_Statement_Table(raw_income_input, annual_bill_table, - analysis_date) + annual_bill_table = annual_bill(raw_bill_table, raw_annual_bill_table, analysis_date)[0] + income_table = Income_Statement_Table(raw_income_input, annual_bill_table, analysis_date) income_table.project(growth_rate_flag, annual_bill_table) prior_income = income_table.get_full_income_table() - next_year_income = income_table.get_single_year(income_table.hist_end_year - + 1) + next_year_income = income_table.get_single_year(income_table.hist_end_year + 1) average_income = income_table.get_average() historical_cagr = income_table.get_cagr() return prior_income, next_year_income, average_income, historical_cagr @@ -287,19 +283,19 @@ def prelim_scenario(raw_bill_table, raw_annual_bill_table, # f.write(writein) # f.close() -print(prelim_scenario( - raw_bill_table=db.raw_bill_table, - raw_annual_bill_table=db.raw_annual_bill_table, - raw_income_input=db.raw_income_input, - growth_rate_flag=-2.0, - raw_liability_input=db.raw_liability_input, - raw_cash_balance=db.raw_cash_balance, - raw_loan_input_list=db.raw_loan_input_list, - analysis_date=db.analysis_date, - commission_date=db.commission_date, - construction_cost=db.cost_estimation, - percent_saving_dict=db.percent_saving_dict, - full_saving_dict=db.full_saving_dict, - req_dscr=db.req_dscr, - customer_preference=db.customer_preference - )) +# print(prelim_scenario( +# raw_bill_table=db.raw_bill_table, +# raw_annual_bill_table=db.raw_annual_bill_table, +# raw_income_input=db.raw_income_input, +# growth_rate_flag=-2.0, +# raw_liability_input=db.raw_liability_input, +# raw_cash_balance=db.raw_cash_balance, +# raw_loan_input_list=db.raw_loan_input_list, +# analysis_date=db.analysis_date, +# commission_date=db.commission_date, +# construction_cost=db.cost_estimation, +# percent_saving_dict=db.percent_saving_dict, +# full_saving_dict=db.full_saving_dict, +# req_dscr=db.req_dscr, +# customer_preference=db.customer_preference +# )) diff --git a/bpfin/tests/test_financials/test_cash_balance.py b/bpfin/tests/test_financials/test_cash_balance.py index f9098fa..880f499 100644 --- a/bpfin/tests/test_financials/test_cash_balance.py +++ b/bpfin/tests/test_financials/test_cash_balance.py @@ -30,7 +30,7 @@ def test_cash_balance(): date(2014, 11, 1): (500, False), date(2015, 12, 31): (600, True), date(2016, 11, 11): (300, False), - date(2016, 10, 10): (400, False), + date(2016, 10, 11): (400, False), date(2016, 10, 10): (500, False) } input_analysis_date = { -- GitLab