diff --git a/bpfin/financials/financial_lib.py b/bpfin/financials/financial_lib.py index d452d45f457bb937a5ca45cfda101406d9df666a..dabbf2b3d6ecaf31deb12d0ee03f2100c12afa1a 100644 --- a/bpfin/financials/financial_lib.py +++ b/bpfin/financials/financial_lib.py @@ -644,6 +644,16 @@ class Balance_Sheet_Table(): if current_balance_sheet.year == first_year: return current_balance_sheet.cash + def get_cash_dict(self): + """ + Get a dictionary of cash. + Return: + dictionary: cash for each year in balance sheet table. Key is year + """ + cash_dict = {} + for current_balance_sheet in self.bs_table: + cash_dict[current_balance_sheet.year] = current_balance_sheet.cash + return cash_dict # # ************ guide for front end dev *********** # # First, fill in bill overview, save it. diff --git a/bpfin/financials/scenario.py b/bpfin/financials/scenario.py index 92a301966d3be4e76b7ee458fdbe7409607c7b60..5f3f992716bdc96a6d700f43548b98c02f20da4d 100644 --- a/bpfin/financials/scenario.py +++ b/bpfin/financials/scenario.py @@ -1,10 +1,12 @@ import copy -# from bpfin.utilbills.bill_lib import form_bill_calendar from bpfin.financials.saving import Saving_Overview from bpfin.financials.loan import Loan_List -from bpfin.tests.testdata import sample_data as db -from bpfin.financials.financial_lib import Income_Statement_Table, Balance_Sheet_Table +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 +# may delete from here after sample built +from bpfin.financials.cash_balance import cash_balance +from bpfin.financials.financial_lib import Income_Statement_Table, Balance_Sheet_Table +from bpfin.tests.testdata import sample_data as db class Scenario(): @@ -22,10 +24,8 @@ class Scenario(): 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.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 @@ -52,12 +52,9 @@ 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 @@ -79,8 +76,7 @@ class Scenario(): self.post_balance_sheet_table.get_first_year_cash( self.commission_date)) - # print('first year =', first_year_saving, first_year_noi, first_year_cash) - # print(self.loan_list.loan_list[0].institute) + # allocate loan and calculate loan schedule for each loan scheduled_loan_list = self.loan_list.get_schedule( customer_preference=customer_preference, cost=self.construction_cost, @@ -94,8 +90,7 @@ class Scenario(): def get_post_energy_bill(self): 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 = {} @@ -132,17 +127,15 @@ class Scenario(): 'total_loan': {year: float} 'net_savings': {year: float} } - # """ + """ graph_dict = {} proforma_bill = self.get_post_energy_bill() annual_debt_service = self.get_annual_debt_service() prior_annual_bill = self.prior_income_statement_table.get_total_energy_dict( ) net_saving_dict = {} - print(prior_annual_bill) 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, @@ -150,39 +143,52 @@ class Scenario(): } return graph_dict - def get_dscr(self, analysis_date, noi_dict, cash_dict, savings_dict, - debt_dict): - - pro_forma_years = form_bill_year(analysis_date['proforma_start'], - analysis_date['proforma_duration']) - - dscr_dict = {'noi_dict': {}, 'cash_dict': {}, 'savings_dict': {}} - - for year in pro_forma_years: - noi_temp_dict = {} - cash_temp_dict = {} - savings_temp_dict = {} - if year in debt_dict and debt_dict[year] != 0: - if year in noi_dict: - noi_temp_dict[year] = noi_dict[year] / debt_dict[ - year] - noi_temp_dict[year] = -1 - if year in cash_dict: - cash_temp_dict[year] = cash_dict[year] / debt_dict[ - year] - noi_temp_dict[year] = -1 - if year in savings_dict: - savings_temp_dict[year] = savings_dict[ - year] / debt_dict[year] - noi_temp_dict[year] = -1 - dscr_dict['noi_dict'] = noi_temp_dict - dscr_dict['cash_dict'] = cash_temp_dict - dscr_dict['savings_dict'] = savings_temp_dict + def get_dscr(self): + 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 = 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, self.saving_overview.get_utility_annual_saving_charge(utility_type)) + + dscr_dict = {} + dscr_dict['noi_dscr'] = divide_dscr_dict(noi_dict, debt_dict) + dscr_dict['cash_dscr'] = divide_dscr_dict(cash_dict, debt_dict) + dscr_dict['saving_dscr'] = divide_dscr_dict(savings_dict, debt_dict) return dscr_dict + def get_economics(self): + """ + Return: + dictionary: { + 'estimated_cost': float, + 'overall_saving': float, inpercent, + 'first_year_saving': float, indollar, + 'simple_payback': float, in year, + 'min_saving_dscr': float, in x multiple, + 'min_noi_dscr': float, in x multiple, + 'min_cash_dscr': float, in x multiple} + + To Do: generate dscr for every year + """ + 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()) + return economics_overview -# ***** ugly test that can be a guide for front end dev ***** + +# # ***** 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, @@ -197,7 +203,7 @@ class Scenario(): # scenario = Scenario( # analysis_date=db.analysis_date, # commission_date=db.commission_date, -# construction_cost=50000, +# construction_cost=60000, # bill_overview=db.bill_overview, # prior_annual_bill_table=db.bill_overview_organized, # other_debt_service=db.liability_dictionary, @@ -216,4 +222,5 @@ class Scenario(): # print(scenario.get_annual_debt_service()) # print(scenario.get_graph_dict()) -# print(scenario.get_graph_dict()) +# print(scenario.get_dscr()) +# print(scenario.get_economics()) diff --git a/bpfin/lib/other.py b/bpfin/lib/other.py index 6c083675e0ea51bf30e3f1da6a775fc0607cca1d..7f4e6b8fa3a83308798584ae567e25676ea803f9 100644 --- a/bpfin/lib/other.py +++ b/bpfin/lib/other.py @@ -3,6 +3,7 @@ import calendar import numpy as np from scipy.optimize import linprog + 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 @@ -13,6 +14,23 @@ def subtract_year_dictionary(dict_1, dict_2): return summed_dict +def divide_dscr_dict(dict_1, dict_2): + ratio_dict = { + x: (dict_1.get(x, 0) / dict_2.get(x, 0) + if dict_2.get(x, 0) != 0 else None) + for x in set(dict_1).union(dict_2) + } + return ratio_dict + + +def min_none_list(list_1): + new_list = [] + for element in list_1: + if element is not None: + new_list.append(element) + return min(new_list) + + def add_list(obj_list, number): """Add a number to each value in a list. diff --git a/bpfin/tests/test_lib/test_other.py b/bpfin/tests/test_lib/test_other.py index 78a6f3da844409bf8587c1cfca23e3c01a54cfc1..0fdbb95ba10c153dfe93d25228efac026b7e125b 100644 --- a/bpfin/tests/test_lib/test_other.py +++ b/bpfin/tests/test_lib/test_other.py @@ -1,4 +1,6 @@ -from bpfin.lib.other import add_year_dictionary, subtract_year_dictionary +from bpfin.lib.other import add_year_dictionary +from bpfin.lib.other import subtract_year_dictionary +from bpfin.lib.other import divide_dscr_dict from bpfin.tests.testdata import sample_data as db @@ -17,3 +19,11 @@ def test_subtract_year_dictionary(): output = db.dict_sub result = subtract_year_dictionary(year_1_input, year_2_input) assert result == output + + +def test_divide_dscr_dict(): + year_1_input = db.dict_year_1 + year_2_input = db.dict_year_2 + output = {2011: 0.0, 2012: 2.5, 2013: 0.3333333333333333, 2014: 2.0, 2015: None} + result = divide_dscr_dict(year_1_input, year_2_input) + assert result == output