diff --git a/bpfin/back_end_call/back_end_budget.py b/bpfin/back_end_call/back_end_budget.py index 8fc31368369c9497f847872bb64a3c90fb434cb5..51abfe1003d2037432d4b22610d79877011e675f 100644 --- a/bpfin/back_end_call/back_end_budget.py +++ b/bpfin/back_end_call/back_end_budget.py @@ -1,11 +1,12 @@ import copy -from bpfin.back_end_call.back_end_inputs import annual_bill +from bpfin.back_end_call.back_end_inputs import form_annual_bill_table from bpfin.financials.financial_income import Income_Statement_Table from bpfin.financials.financial_balance import Balance_Sheet_Table from bpfin.financials.cash_balance import cash_balance from bpfin.financials.liability import final_liability_dict from bpfin.financials.loan import Loan_List from bpfin.financials.financial_budget_simulator import form_max_financing, form_budget_simulation_result +from bpfin.lib.other import UTILITY_TYPE_LIST def budget_simulation( @@ -40,34 +41,29 @@ def budget_simulation( Description: raw_bill_table = { 'gas': raw_gas_bill_demo, - 'electricity': raw_elec_bill_demo, + 'electric': raw_elec_bill_demo, 'oil': raw_oil_bill_demo, 'water': None} raw_annual_bill_table = { - 'electricity': None, + 'electric': None, 'gas': None, 'oil': None, 'water': None} - To Do: + TODO: finish description saving_interval will be read from frond-end in next version + make preference_list = ['loan_only'...] a global constant """ # data validation and empty conversion: if raw_bill_table is None: - raw_bill_table = { - 'electricity': None, - 'gas': None, - 'oil': None, - 'water': None} + for utility in UTILITY_TYPE_LIST: + raw_bill_table[utility] = None if raw_annual_bill_table is None: - raw_annual_bill_table = { - 'electricity': None, - 'gas': None, - 'oil': None, - 'water': None} + for utility in UTILITY_TYPE_LIST: + raw_annual_bill_table[utility] = None if raw_liability_input is None: raw_liability_input = {} @@ -78,7 +74,7 @@ def budget_simulation( # function variable building up preference_list = ['loan_only', 'loan_first', 'sf_first', 'sf_max'] - annual_bill_table = annual_bill(raw_bill_table, raw_annual_bill_table, analysis_date)[0] + annual_bill_table = form_annual_bill_table(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) @@ -135,11 +131,7 @@ def budget_simulation( for current_list, amount in zip(budget_simulation_result[preference], amount_list): current_list.append(amount) - return [ - budget_simulation_result['loan_only'], - budget_simulation_result['loan_first'], - budget_simulation_result['sf_first'], - budget_simulation_result['sf_max']] + return [budget_simulation_result[preference] for preference in preference_list] # **** ugly test **** @@ -149,7 +141,7 @@ def budget_simulation( # db.commission_date, # db.customer_preference, # db.req_dscr, -# db.raw_bill_table, +# db.raw_monthly_bill_table, # db.raw_annual_bill_table, # db.raw_income_input, # db.growth_rate_flag, diff --git a/bpfin/back_end_call/back_end_inputs.py b/bpfin/back_end_call/back_end_inputs.py index bdd422cd72ba73fc941bd975b8216ec2e34d5b63..8c7b283f7a7f4acd5a202ea5616adbe249c79c3c 100644 --- a/bpfin/back_end_call/back_end_inputs.py +++ b/bpfin/back_end_call/back_end_inputs.py @@ -1,28 +1,29 @@ from bpfin.lib.other import UTILITY_TYPE_LIST from bpfin.utilbills.bill import Bill -from bpfin.financials.cash_balance import cash_balance -from bpfin.financials.liability import final_liability_dict +from bpfin.utilbills.bill_lib import sum_energy_opex from bpfin.financials.financial_income import Income_Statement_Table -from bpfin.financials.financial_balance import Balance_Sheet_Table -# Bill Overview Monthly Input -def monthly_bill(raw_bill_table, analysis_date): +def form_annual_bill_table(raw_monthly_bill_table, raw_annual_bill_table, analysis_date): """ - Take in raw_bill_table - Generate annual bill for utility type with available bill + Annual bill overview Calculation + Take in raw_monthly_bill_table and raw_annual_bill_table + Generate prior annual bill for utility type with available bill Generate manual_input dictionary indicating manual input label for 4 utilities + Return formatted annual bill table Args: - raw_bill_table (dictionary): dict of dict of raw_bill. Keys are utility types + raw_monthly_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 + raw_annual_bill_table (dictionary): dictionary of dictionary of annual bills, at lease 0 year data is required Returns: + list: list of lists, display prior_annual_bill and manual_input indicators in displaying formatting bill_overview_dict (dictionary): dictionary of dictionary of annual bills, see description for detail # manual_input_dict (dictionary): dictionary of boolean values, keys are utilities Error Validate: - raw_bill_table, analysis_date == None, Raise empty error + raw_monthly_bill_table, analysis_date == None, Raise empty error bill_overview_dict == None or missing utility, Raise calculation error manual_input_dict == None or missing utility, Raise calculation error Data Validate: @@ -32,10 +33,10 @@ def monthly_bill(raw_bill_table, analysis_date): raw_bill > 12 months, annual bill generated, manual_input == False Description: - raw_bill_table contains 4 utilities raw bill data. Each utility is a dictionary with 4 keys. + raw_monthly_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': { + raw_monthly_bill_table = { + 'electric': { 'date_from': list of date, 'date_to', list of date, 'usage', list of float, @@ -45,9 +46,13 @@ def monthly_bill(raw_bill_table, analysis_date): 'oil': None, 'water': None } - + raw_annual_bill_table = { + 'electric': {2014: 100, 2015:200, ...}, + 'oil': dict of oil_bill, + 'gas': dict of gas_bill, + 'water': dict of water_bill} bill_overview_dict = { - 'electricity': {2014: 100, 2015:200, ...}, + 'electric': {2014: 100, 2015:200, ...}, 'oil': dict of oil_bill, 'gas': dict of gas_bill, 'water': dict of water_bill} @@ -55,23 +60,23 @@ def monthly_bill(raw_bill_table, analysis_date): 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( - # '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 - 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: - current_bill.put_month_bill(raw_bill_table[utility]) + if utility in raw_monthly_bill_table: + current_bill.put_raw_bill(raw_monthly_bill_table[utility], raw_annual_bill_table[utility]) else: - current_bill.put_month_bill(None) - bill_overview_dict[utility] = current_bill.get_annual_bill() + current_bill.put_raw_bill(None, raw_annual_bill_table[utility]) + + bill_overview_dict[utility] = current_bill.get_prior_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' @@ -80,69 +85,30 @@ def monthly_bill(raw_bill_table, analysis_date): 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 + # formatting annual bill (bill overview on front end) + proforma_year = sorted(bill_overview_dict[UTILITY_TYPE_LIST[0]]) + bill_overview_front_end_list = [] -def annual_bill(raw_bill_table, raw_annual_bill_table, analysis_date): - """ - Take in raw_annual_bill_table - Generate annual bill for utility type with and without available bill + bill_overview_front_end_list.append(['Data Source', 'Utility/Year']) + bill_overview_front_end_list[0] += proforma_year - 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 - raw_annual_bill_table (dictionary): dictionary of dictionary of annual bills, at lease 0 year data is required + for utility in UTILITY_TYPE_LIST: + utility_expense_list = [] + utility_expense_list.append('Annual Estimate' if manual_input_dict[utility] else 'Monthly Bill') + utility_expense_list.append(utility) + utility_expense_list += [bill_overview_dict[utility][year] for year in proforma_year] + bill_overview_front_end_list.append(utility_expense_list) - Returns: - annual_bill_table (dictionary): dictionary of dictionary of annual bills, see description for detail + bill_overview_front_end_list.append(['', 'Total Energy Expense']) + bill_overview_front_end_list[-1] += sum_energy_opex(bill_overview_dict)[1] - Description: - raw_annual_bill_table = { - 'electricity': {2014: 100, 2015:200, ...}, - 'oil': dict of oil_bill, - 'gas': dict of gas_bill, - 'water': dict of water_bill} - annual_bill_table = { - 'electricity': {2014: 100, 2015:200, ...}, - 'oil': dict of oil_bill, - '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 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: - current_bill.put_month_bill(raw_bill_table[utility]) - else: - current_bill.put_month_bill(None) - 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' - ) - 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 + return bill_overview_dict, manual_input_dict, prior_month_bill_dict, bill_overview_front_end_list def form_prior_income_table( raw_income_input, - raw_bill_table, + raw_monthly_bill_table, raw_annual_bill_table, analysis_date, growth_rate_flag): @@ -153,7 +119,7 @@ def form_prior_income_table( Args: raw_income_input (dictionary): dict of dict of incomplete income statement, for historical years. Key = year - raw_bill_table (dictionary): dict of dict of raw_bill. Keys are utility types + raw_monthly_bill_table (dictionary): dict of dict of raw_bill. Keys are utility types raw_annual_bill_table (dictionary): dictionary of dictionary of annual bills, at lease 0 year data is required 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 @@ -167,8 +133,8 @@ def form_prior_income_table( Description: raw_income_input = {2014: {'revenue': 90.0, 'utility_expense': 55.0, 'non_utility_expense': 35.0}, 2015:{},} - raw_bill_table = { - 'electricity': { + raw_monthly_bill_table = { + 'electric': { 'date_from': list of date, 'date_to', list of date, 'usage', list of float, @@ -180,7 +146,7 @@ def form_prior_income_table( } raw_annual_bill_table = { - 'electricity': None + 'electric': None 'gas': {2014: 100, 2015:200, ...}, 'oil': {2014: 100, 2015:200, ...}, 'water': dict of water_bill} @@ -188,7 +154,7 @@ 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] + annual_bill_table = form_annual_bill_table(raw_monthly_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) @@ -201,19 +167,25 @@ def form_prior_income_table( # **** ugly test **** # import pprint +# from bpfin.financials.cash_balance import cash_balance +# from bpfin.financials.liability import final_liability_dict +# from bpfin.financials.financial_balance import Balance_Sheet_Table # from bpfin.tests.testdata import feature_data as db -# 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('\nannual_bill =', form_annual_bill_table(db.raw_monthly_bill_table, db.raw_annual_bill_table, db.analysis_date)[-1]) + +# pp = pprint.PrettyPrinter(width=120, indent=4, compact=True) +# pp.pprint(form_annual_bill_table(db.raw_monthly_bill_table, db.raw_annual_bill_table, db.analysis_date)[-1]) + # print('\nprior_income_statement =', form_prior_income_table( # db.raw_income_input, -# db.raw_bill_table, +# db.raw_monthly_bill_table, # db.raw_annual_bill_table, # db.analysis_date, # -2.0)) # result = form_prior_income_table( # db.raw_income_input, -# db.raw_bill_table, +# db.raw_monthly_bill_table, # db.raw_annual_bill_table, # db.analysis_date, # -2.0)[0] diff --git a/bpfin/back_end_call/back_end_prelim.py b/bpfin/back_end_call/back_end_prelim.py index 0d22179d0f6d69d98702e547de1716cd6a003851..f917a14a14dbe2d448d31fd12d865849a3bcf00a 100644 --- a/bpfin/back_end_call/back_end_prelim.py +++ b/bpfin/back_end_call/back_end_prelim.py @@ -3,14 +3,14 @@ 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.financials.scenario import Scenario -from bpfin.back_end_call.back_end_inputs import monthly_bill, annual_bill +from bpfin.back_end_call.back_end_inputs import form_annual_bill_table # delete following imports when online # from bpfin.tests.testdata import feature_data as db # import pprint -def prelim_scenario(raw_bill_table, raw_annual_bill_table, raw_income_input, +def prelim_scenario(raw_monthly_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, @@ -19,7 +19,7 @@ def prelim_scenario(raw_bill_table, raw_annual_bill_table, raw_income_input, Conduct Preliminary Financial Analysis Args: - raw_bill_table (dictionary): dict of dict of raw_bill. Keys are utility types + raw_monthly_bill_table (dictionary): dict of dict of raw_bill. Keys are utility types raw_annual_bill_table (dictionary): dictionary of dictionary of annual bills, at lease 0 year data is required raw_income_input (dictionary): dict of dict of incomplete income statement, for historical years. Key = year growth_rate_flag (float): indicating assumed growth rate, -2.0 == cagr, -1.0 == historical average @@ -44,8 +44,8 @@ def prelim_scenario(raw_bill_table, raw_annual_bill_table, raw_income_input, Description: raw_income_input = {2014: {'revenue': 90.0, 'utility_expense': 55.0, 'non_utility_expense': 35.0}, 2015:{},} - raw_bill_table = { - 'electricity': { + raw_monthly_bill_table = { + 'electric': { 'date_from': list of date, 'date_to', list of date, 'usage', list of float, @@ -56,7 +56,7 @@ def prelim_scenario(raw_bill_table, raw_annual_bill_table, raw_income_input, 'water': None } raw_annual_bill_table = { - 'electricity': None + 'electric': None 'gas': {2014: 100, 2015:200, ...}, 'oil': {2014: 100, 2015:200, ...}, 'water': dict of water_bill @@ -68,7 +68,7 @@ def prelim_scenario(raw_bill_table, raw_annual_bill_table, raw_income_input, raw_cash_balance = {date(year, month, date):(cash value, year)} raw_loan_input_list = [{'institute': str, 'max_amount': float, 'interest': float, 'duration': int}, {}] percent_saving_dict = { - 'electricity': 0.25, + 'electric': 0.25, 'gas': 0.10, 'oil': 0.80, 'water': 0.0 @@ -111,8 +111,8 @@ def prelim_scenario(raw_bill_table, raw_annual_bill_table, raw_income_input, monthly_financial_projection_table write unit test file for scenario class and for prelim_scenario back_end_call """ - prior_annual_bill_table, manual_input_dict = annual_bill( - raw_bill_table, raw_annual_bill_table, analysis_date + prior_annual_bill_table, manual_input_dict, prior_month_bill, unsued_display_table = form_annual_bill_table( + raw_monthly_bill_table, raw_annual_bill_table, analysis_date ) prior_income_table = Income_Statement_Table( @@ -156,14 +156,14 @@ def prelim_scenario(raw_bill_table, raw_annual_bill_table, raw_income_input, loan_input_list=raw_loan_input_list) scenario_ob.prelim_analysis( - prior_month_bill=monthly_bill(raw_bill_table, analysis_date)[2], + prior_month_bill=prior_month_bill, percent_saving_dict=percent_saving_dict, full_saving_dict=full_saving_dict, 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 + # Define raw_monthly_bill_table as a "get" of prior_bill # Delete prior_annual_bill_table # the following is front-end formatting building: loan_showcase_list = [ @@ -211,7 +211,7 @@ def prelim_scenario(raw_bill_table, raw_annual_bill_table, raw_income_input, # print( # prelim_scenario( -# raw_bill_table=db.raw_bill_table, +# raw_monthly_bill_table=db.raw_monthly_bill_table, # raw_annual_bill_table=db.raw_annual_bill_table, # raw_income_input=db.raw_income_input, # growth_rate_flag=-2.0, diff --git a/bpfin/financials/financial_income.py b/bpfin/financials/financial_income.py index c3dca1e2c6b2633c2b727b545179e8f1cb4717ec..c398fc6d6665f8b4d188e359370e8c4840653184 100644 --- a/bpfin/financials/financial_income.py +++ b/bpfin/financials/financial_income.py @@ -49,15 +49,18 @@ class Income_Statement(): 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} + + TODO: + create gloabl constant list for income statement line items and replace the properties """ 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.electricity_opex = annual_bill_table[UTILITY_TYPE_LIST[0]][self.year] + self.gas_opex = annual_bill_table[UTILITY_TYPE_LIST[1]][self.year] + self.oil_opex = annual_bill_table[UTILITY_TYPE_LIST[2]][self.year] + self.water_opex = annual_bill_table[UTILITY_TYPE_LIST[3]][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 @@ -84,13 +87,13 @@ class Income_Statement(): '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} + annual_bills = {'electric: 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.electricity_opex = annual_bills[UTILITY_TYPE_LIST[0]] + self.gas_opex = annual_bills[UTILITY_TYPE_LIST[1]] + self.oil_opex = annual_bills[UTILITY_TYPE_LIST[2]] + self.water_opex = annual_bills[UTILITY_TYPE_LIST[3]] 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[ @@ -152,7 +155,7 @@ class Income_Statement_Next(): '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} + annual_bill_table = {'electric: 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): @@ -167,10 +170,10 @@ class Income_Statement_Next(): 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.electricity_opex = annual_bill_table[UTILITY_TYPE_LIST[0]][self.year] + self.gas_opex = annual_bill_table[UTILITY_TYPE_LIST[1]][self.year] + self.oil_opex = annual_bill_table[UTILITY_TYPE_LIST[2]][self.year] + self.water_opex = annual_bill_table[UTILITY_TYPE_LIST[3]][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'] @@ -206,7 +209,7 @@ class Income_Statement_Table(): 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} + annual_bill_table = {'electric: electricity_bill, 'oil': oil_bill, 'gas': gas_bill, 'water': water_bill} electricity_bill = {2014: 100, 2015:200, ...} characters = { 'start_year': (int) 2014, @@ -360,13 +363,13 @@ class Income_Statement_Table(): current_income_statement = Income_Statement() average_revenue = mean(list(i_s.revenue for i_s in self.hist_table)) annual_bills = { - 'electricity': + UTILITY_TYPE_LIST[0]: mean(list(i_s.electricity_opex for i_s in self.hist_table)), - 'gas': + UTILITY_TYPE_LIST[1]: mean(list(i_s.gas_opex for i_s in self.hist_table)), - 'oil': + UTILITY_TYPE_LIST[2]: mean(list(i_s.oil_opex for i_s in self.hist_table)), - 'water': + UTILITY_TYPE_LIST[3]: mean(list(i_s.water_opex for i_s in self.hist_table)) } current_income_statement.put_average(average_revenue, annual_bills, self.characters) @@ -509,8 +512,8 @@ def validate_annual_bill_table(annual_bill_table): 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()) + start_year = sorted(annual_bill_table[UTILITY_TYPE_LIST[0]].keys())[0] + duration = len(annual_bill_table[UTILITY_TYPE_LIST[0]].keys()) for utility in UTILITY_TYPE_LIST: if sorted(annual_bill_table[utility].keys())[0] != start_year: diff --git a/bpfin/financials/financial_saving.py b/bpfin/financials/financial_saving.py index 19a0524f1875bcfc00a01765ff9b4972298322b5..dd692eba28d6bd54d68b33c80031424381f10b1b 100644 --- a/bpfin/financials/financial_saving.py +++ b/bpfin/financials/financial_saving.py @@ -207,12 +207,12 @@ class Saving_Overview(): 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} + saving_percent_charge (dictionary): key is utility type, value is float {'electric': 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, ...} + prior_annual_bill_table = {'electric': electricity_bill, 'oil': oil_bill, ...} electricity_bill = {2014: 100, 2015:200, ...} """ @@ -235,19 +235,19 @@ class Saving_Overview(): Description: manual_input_dict = { - 'electricity': True, + 'electric': True, 'oil': False, 'gas': False, 'water': False} prior_annual_bill_table = { - 'electricity': {2014: 100, 2015:200, ...}, + 'electric': {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], + # 'electric': bill_overview['electric'][1], # 'gas': bill_overview['gas'][1], # 'oil': bill_overview['oil'][1], # 'water': bill_overview['water'][1]} @@ -255,8 +255,11 @@ class Saving_Overview(): 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.utility_saving_dict = {} + self.saving_percent_charge = {} + for utility in UTILITY_TYPE_LIST: + self.utility_saving_dict[utility] = None + self.saving_percent_charge[utility] = None self.total_first_year_saving = 0 # dollar self.total_saving_percent = 0 # dollar percentage @@ -272,7 +275,7 @@ class Saving_Overview(): Description: prior_month_bill = { - 'electricity': electricity_prior_bill_rough, + 'electric': electricity_prior_bill_rough, 'gas': None, 'oil': None, 'water': None} @@ -348,7 +351,7 @@ class Saving_Overview(): 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} + output = {'electric': electricity_bill, 'oil': oil_bill, 'gas': gas_bill, 'water': water_bill} electricity_bill = {2014: 100, 2015:200, ...} } """ @@ -362,7 +365,7 @@ class Saving_Overview(): """ Get the proforma annual saving on charge for a utility_type Args: - utility_type (string): 'electricity', 'gas', 'oil', 'water' + utility_type (string): 'electric', 'gas', 'oil', 'water' Return: dictionary: {year: saving on charge} """ @@ -388,7 +391,7 @@ class Saving_Overview(): return savings_dict # total_saving_dict = {} - # for year in copy.deepcopy(self.prior_annual_bill_table['electricity']): + # for year in copy.deepcopy(self.prior_annual_bill_table['electric']): # total_saving_dict[year] = 0 # for utility in UTILITY_TYPE_LIST: @@ -411,7 +414,7 @@ class Saving_Overview(): # 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('\n electricity_annual_saving_charge', so.get_utility_annual_saving_charge('electric')) # print(so.get_post_annual_bill_table()) @@ -423,6 +426,6 @@ class Saving_Overview(): # # print('\n first_year_dollar_saving =', sav_o.get_total_first_year_saving()) # # print('\n simple payback =', sav_o.get_simple_payback(150000)) # # print('\n total saving percent =', sav_o.get_total_saving_percent()) -# # print('\n electricity_annual_saving_charge', sav_o.get_utility_annual_saving_charge('electricity')) +# # print('\n electricity_annual_saving_charge', sav_o.get_utility_annual_saving_charge('electric')) # # print(sav_o.get_post_annual_bill_table()) diff --git a/bpfin/lib/other.py b/bpfin/lib/other.py index 3730e6a02c61eb517e94a81efe4dc50cfcc4d0a9..a54ef55a4748c04423614c9de09f63bd6f365ecc 100644 --- a/bpfin/lib/other.py +++ b/bpfin/lib/other.py @@ -5,7 +5,8 @@ import copy from scipy.optimize import linprog -UTILITY_TYPE_LIST = ['electricity', 'gas', 'oil', 'water'] +# UTILITY_TYPE_LIST = ['electricity', 'gas', 'oil', 'water'] +UTILITY_TYPE_LIST = ['electric', 'gas', 'oil', 'water'] def add_year_dictionary(dict_1, dict_2): @@ -50,16 +51,16 @@ def min_none_list(list_1): return min(new_list, default=0) -def add_list(obj_list, number): - """Add a number to each value in a list. +# def add_list(obj_list, number): +# """Add a number to each value in a list. - Args: - obj_list (list): list of numbers - number (int): number value - Returns: - list: numbers + number to each value - """ - return [x + number for x in obj_list] +# Args: +# obj_list (list): list of numbers +# number (int): number value +# Returns: +# list: numbers + number to each value +# """ +# return [x + number for x in obj_list] def cal_last_day(obj_year, obj_month): @@ -75,27 +76,27 @@ def cal_last_day(obj_year, obj_month): return last_day_num -def form_bill_calendar(date_start, year_term): - """Return single list value of first date in bill period and last date in bill period. +# def form_bill_calendar(date_start, year_term): +# """Return single list value of first date in bill period and last date in bill period. - Args: - date_start (datetime): date xx/yy/abcd - year_term (int): number of years in bill - Returns: - list: first date in bill period, last date in bill period +# Args: +# date_start (datetime): date xx/yy/abcd +# year_term (int): number of years in bill +# Returns: +# list: first date in bill period, last date in bill period - """ - bdstart = [] - bdend = [] - day = date_start - for term in range(12 * year_term): - first = datetime.date(day=1, month=day.month, year=day.year) - bdstart.append(first) - last = datetime.date(day.year, day.month, - cal_last_day(day.year, day.month)) - bdend.append(last) - day = last + datetime.timedelta(days=1) - return [bdstart, bdend] +# """ +# bdstart = [] +# bdend = [] +# day = date_start +# for term in range(12 * year_term): +# first = datetime.date(day=1, month=day.month, year=day.year) +# bdstart.append(first) +# last = datetime.date(day.year, day.month, +# cal_last_day(day.year, day.month)) +# bdend.append(last) +# day = last + datetime.timedelta(days=1) +# return [bdstart, bdend] def form_date_calendar(date_start, date_end): @@ -126,108 +127,108 @@ def form_date_calendar(date_start, date_end): return [bdstart, bdend] -def form_year_month(target_terms): - """Return list of month,year of datetimes in a list. +# def form_year_month(target_terms): +# """Return list of month,year of datetimes in a list. - Args: - target_terms (list of datetimes): date xx/yy/abcd - Returns: - list: list of tuples containing year and month - """ - obj_list = [] - for term in target_terms: - obj_list.append((term.year, term.month)) - return obj_list +# Args: +# target_terms (list of datetimes): date xx/yy/abcd +# Returns: +# list: list of tuples containing year and month +# """ +# obj_list = [] +# for term in target_terms: +# obj_list.append((term.year, term.month)) +# return obj_list -def cal_inflation_product(inflation_rate_dict, present_date): - """Return the inflation value for the current date. +# def cal_inflation_product(inflation_rate_dict, present_date): +# """Return the inflation value for the current date. - Args: - inflation_rate_dict (dictionary): dictionary of {date,inflation value} - present_date (datetime): present date - Returns: - integer: inflation rate +# Args: +# inflation_rate_dict (dictionary): dictionary of {date,inflation value} +# present_date (datetime): present date +# Returns: +# integer: inflation rate - """ - date_start = sorted(inflation_rate_dict)[0] - product = 1 - for term in form_date_calendar(date_start, present_date)[1]: - product = product * inflation_rate_dict[term] - return product +# """ +# date_start = sorted(inflation_rate_dict)[0] +# product = 1 +# for term in form_date_calendar(date_start, present_date)[1]: +# product = product * inflation_rate_dict[term] +# return product -def cal_inflated_item(base_list, target_terms, inflation_coeff_dict): - # Deleted "present_day" from inputs. - """Create dictionary of inflated terms. +# def cal_inflated_item(base_list, target_terms, inflation_coeff_dict): +# # Deleted "present_day" from inputs. +# """Create dictionary of inflated terms. - Args: - base_list (integer): base value - target_terms (list): list of inflation values - inflation_coeff_dict (dictionary): dictioanry of inflation coefficients with date - Returns: - dictionary: coefficients and dates - """ - new_dict = dict(zip([], [])) - for term in target_terms: - new_dict[term] = base_list[term.month - 1] * inflation_coeff_dict[term] - return [new_dict[term] for term in sorted(new_dict)] +# Args: +# base_list (integer): base value +# target_terms (list): list of inflation values +# inflation_coeff_dict (dictionary): dictioanry of inflation coefficients with date +# Returns: +# dictionary: coefficients and dates +# """ +# new_dict = dict(zip([], [])) +# for term in target_terms: +# new_dict[term] = base_list[term.month - 1] * inflation_coeff_dict[term] +# return [new_dict[term] for term in sorted(new_dict)] -def form_inflation_ratedict(inflationyears, inflationhist): - """Create dictionary of {date,inflation}. +# def form_inflation_ratedict(inflationyears, inflationhist): +# """Create dictionary of {date,inflation}. - Args: - inflationyears (list): list of years - inflationhist (list): list of inflation values - Returns: - dictionary: {datetime, adjusted inflation} - """ - inflationterms = form_bill_calendar( - datetime.date(int(inflationyears[0]), 1, 31), len(inflationyears))[1] - inflation_rate = [] - for year, rate in zip(inflationyears, inflationhist): - for number in range(12): - inflation_rate.append(rate / 12) - inflation_rate = add_list(inflation_rate, 1) - dict1 = dict(zip(inflationterms, - inflation_rate)) # return (2016,2,29 : 100.67%) - return dict1 +# Args: +# inflationyears (list): list of years +# inflationhist (list): list of inflation values +# Returns: +# dictionary: {datetime, adjusted inflation} +# """ +# inflationterms = form_bill_calendar( +# datetime.date(int(inflationyears[0]), 1, 31), len(inflationyears))[1] +# inflation_rate = [] +# for year, rate in zip(inflationyears, inflationhist): +# for number in range(12): +# inflation_rate.append(rate / 12) +# inflation_rate = add_list(inflation_rate, 1) +# dict1 = dict(zip(inflationterms, +# inflation_rate)) # return (2016,2,29 : 100.67%) +# return dict1 -def form_inflation_coeffdict(inflationyears, inflationhist, present_date): - """Create dictionary of date:inflation relative to present date. +# def form_inflation_coeffdict(inflationyears, inflationhist, present_date): +# """Create dictionary of date:inflation relative to present date. - Args: - inflationyears (list): list of years - inflationhist (list): list of inflation values - present_date (datetime): present date - Returns: - dictionary: date:inflation relative to present date - """ - inflation_rate_dict = form_inflation_ratedict(inflationyears, - inflationhist) - inflationterms = sorted(inflation_rate_dict) - new_dict = dict(zip([], [])) - for term in inflationterms: - new_dict[term] = cal_inflation_product( - inflation_rate_dict, term) / cal_inflation_product( - inflation_rate_dict, present_date) - return new_dict +# Args: +# inflationyears (list): list of years +# inflationhist (list): list of inflation values +# present_date (datetime): present date +# Returns: +# dictionary: date:inflation relative to present date +# """ +# inflation_rate_dict = form_inflation_ratedict(inflationyears, +# inflationhist) +# inflationterms = sorted(inflation_rate_dict) +# new_dict = dict(zip([], [])) +# for term in inflationterms: +# new_dict[term] = cal_inflation_product( +# inflation_rate_dict, term) / cal_inflation_product( +# inflation_rate_dict, present_date) +# return new_dict -def occupancy_final_list(occupancy_rate_list): - """Return list of occupancy values. +# def occupancy_final_list(occupancy_rate_list): +# """Return list of occupancy values. - Args: - occupancy_rate_list (list): list of occupancy integers - Returns: - list: list of occupancy integers * 24, representing occupancy in hours - """ - occupancy_list = [] - for occ in occupancy_rate_list: - occupancy_list.append(occ * 24) - return occupancy_list +# Args: +# occupancy_rate_list (list): list of occupancy integers +# Returns: +# list: list of occupancy integers * 24, representing occupancy in hours +# """ +# occupancy_list = [] +# for occ in occupancy_rate_list: +# occupancy_list.append(occ * 24) +# return occupancy_list ########################################### need to check duplication ################### @@ -250,23 +251,23 @@ def product2list(list1, list2): return [x * y for x, y in zip(list1, list2)] -def product(list1): - a = 1 - for i in list1: - a = a * i - return a +# def product(list1): +# a = 1 +# for i in list1: +# a = a * i +# return a -def sum2list(list1, list2): - return [x + y for x, y in zip(list1, list2)] +# def sum2list(list1, list2): +# return [x + y for x, y in zip(list1, list2)] -def sum3list(list1, list2, list3): - return [x + y + z for x, y, z in zip(list1, list2, list3)] +# def sum3list(list1, list2, list3): +# return [x + y + z for x, y, z in zip(list1, list2, list3)] -def sublist(list1, list2): - return [x - y for x, y in zip(list1, list2)] +# def sublist(list1, list2): +# return [x - y for x, y in zip(list1, list2)] # def add_list(obj_list, number): @@ -285,9 +286,9 @@ def multiply_list(obj_list, number): return [x * number for x in obj_list] -def form_dict(terms, obj): - obj_dict = dict(zip(terms, obj)) - return obj_dict +# def form_dict(terms, obj): +# obj_dict = dict(zip(terms, obj)) +# return obj_dict # calculate number of days in given month @@ -340,10 +341,10 @@ def date_diff(startdate, enddate): # return [bdstart, bdend] -def form_year_terms(year): - start_date = datetime.date(year, 1, 31) - terms = form_bill_calendar(start_date, 1) - return terms[1] +# def form_year_terms(year): +# start_date = datetime.date(year, 1, 31) +# terms = form_bill_calendar(start_date, 1) +# return terms[1] # print(form_year_terms(2013)) @@ -353,19 +354,19 @@ def convert_timestamp_date(list1): return list(map(lambda x: datetime.date(x.year, x.month, x.day), list1)) -def cal_latest_day(terms_list): - latestday = datetime.date(1900, 1, 1) - for term_i in terms_list: - for term in term_i: - latestday = (term if term > latestday else latestday) - return latestday +# def cal_latest_day(terms_list): +# latestday = datetime.date(1900, 1, 1) +# for term_i in terms_list: +# for term in term_i: +# latestday = (term if term > latestday else latestday) +# return latestday -def average(list1): - if len(list1) == 0: - return 0 - else: - return sum(list1) / len(list1) +# def average(list1): +# if len(list1) == 0: +# return 0 +# else: +# return sum(list1) / len(list1) def average_nonzero_list(list1): @@ -463,54 +464,54 @@ def duplicate2terms(list1, target_terms): # calculate max loan term and assign to total energy loan -def cal_max_term(loan_list): - max_length = 0 - max_ID = 0 - for loanID in range(len(loan_list)): - if len(loan_list[loanID].terms) >= max_length: - max_length = len(loan_list[loanID].terms) - max_ID = loanID - return loan_list[max_ID].terms +# def cal_max_term(loan_list): +# max_length = 0 +# max_ID = 0 +# for loanID in range(len(loan_list)): +# if len(loan_list[loanID].terms) >= max_length: +# max_length = len(loan_list[loanID].terms) +# max_ID = loanID +# return loan_list[max_ID].terms # calculate and assign cash flow for loans and for total energy loan -def align2term(terms1, list1, target_terms): - dict1 = dict(zip(terms1, list1)) - new_dict = dict(zip([], [])) - for term in target_terms: - if term in terms1: - new_dict[term] = dict1[term] - else: - new_dict[term] = 0 - return [new_dict[term] for term in sorted(new_dict)] +# def align2term(terms1, list1, target_terms): +# dict1 = dict(zip(terms1, list1)) +# new_dict = dict(zip([], [])) +# for term in target_terms: +# if term in terms1: +# new_dict[term] = dict1[term] +# else: +# new_dict[term] = 0 +# return [new_dict[term] for term in sorted(new_dict)] # calculate loan's (loan amount/debt service), just like a payback -def cal_loan_payback(interest, duration): - return ( - (1 + interest)**duration - 1) / (interest * (1 + interest)**duration) +# def cal_loan_payback(interest, duration): +# return ( +# (1 + interest)**duration - 1) / (interest * (1 + interest)**duration) # cauclate loan amount should be borrowed from each bank, given assumed total cost and loan info -def loan_allocate(total_cost, loan_list): - sum_loan_max = 0 - bound_list = [] - c_base = [] - for loan in loan_list: - sum_loan_max += loan.max_amount - c_base.append( - 1 / loan.payback - ) # loan amount / ratio = DS, targeting minimum total DS, equivalent to longest payback - bound_list.append((0, loan.max_amount)) - c = c_base # c_base is target function - A = [-1] * len(loan_list) - b = [max(0 - total_cost, 0 - sum_loan_max)] - bounds = bound_list - if total_cost > sum_loan_max: - print('alert: upfront cost > available loan amount') - res = linprog(c, A_ub=A, b_ub=b, bounds=bounds, options={'disp': False}) - for i in range(len(loan_list)): - loan_list[i].amount = res.x[i] +# def loan_allocate(total_cost, loan_list): +# sum_loan_max = 0 +# bound_list = [] +# c_base = [] +# for loan in loan_list: +# sum_loan_max += loan.max_amount +# c_base.append( +# 1 / loan.payback +# ) # loan amount / ratio = DS, targeting minimum total DS, equivalent to longest payback +# bound_list.append((0, loan.max_amount)) +# c = c_base # c_base is target function +# A = [-1] * len(loan_list) +# b = [max(0 - total_cost, 0 - sum_loan_max)] +# bounds = bound_list +# if total_cost > sum_loan_max: +# print('alert: upfront cost > available loan amount') +# res = linprog(c, A_ub=A, b_ub=b, bounds=bounds, options={'disp': False}) +# for i in range(len(loan_list)): +# loan_list[i].amount = res.x[i] # return res.x diff --git a/bpfin/tests/test_back_end_call/test_back_end_budget.py b/bpfin/tests/test_back_end_call/test_back_end_budget.py index d05d722930b2b44f7372e34ad5559b105576c46f..6b539ac43fd29562d9ccf369eeb71cb441364934 100644 --- a/bpfin/tests/test_back_end_call/test_back_end_budget.py +++ b/bpfin/tests/test_back_end_call/test_back_end_budget.py @@ -9,7 +9,7 @@ def test_budget_simulation(): db.commission_date, db.customer_preference, db.req_dscr, - db.raw_bill_table, + db.raw_monthly_bill_table, db.raw_annual_bill_table, db.raw_income_input, db.growth_rate_flag, diff --git a/bpfin/tests/test_back_end_call/test_back_end_inputs.py b/bpfin/tests/test_back_end_call/test_back_end_inputs.py index 8033219f5773aaba2d3d7bafcd7f0afdc40f09a1..63ed41a80b334ee9b9372a23493e4099eadb6038 100644 --- a/bpfin/tests/test_back_end_call/test_back_end_inputs.py +++ b/bpfin/tests/test_back_end_call/test_back_end_inputs.py @@ -1,21 +1,11 @@ # from bpfin.lib.back_end_call import budget_simulation -from bpfin.back_end_call.back_end_inputs import monthly_bill, annual_bill, form_prior_income_table +from bpfin.back_end_call.back_end_inputs import form_annual_bill_table, form_prior_income_table from bpfin.tests.testdata import feature_data as db -def test_monthly_bill(): - output_dict = { - 'electricity': db.prior_annual_bill['electricity'], - '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)[0] - assert output_dict == result_dict - - -def test_annual_bill(): +def test_form_annual_bill_table(): output_dict = db.prior_annual_bill - result_dict = annual_bill(db.raw_bill_table, db.raw_annual_bill_table, db.analysis_date)[0] + result_dict = form_annual_bill_table(db.raw_monthly_bill_table, db.raw_annual_bill_table, db.analysis_date)[0] assert output_dict == result_dict @@ -26,7 +16,7 @@ def test_form_prior_income_table(): output_historical_cagr = db.historical_cagr prior_income, next_year_income, average_income, historical_cagr = form_prior_income_table( db.raw_income_input, - db.raw_bill_table, + db.raw_monthly_bill_table, db.raw_annual_bill_table, db.analysis_date, -2.0) diff --git a/bpfin/tests/test_financials/test_financial_saving.py b/bpfin/tests/test_financials/test_financial_saving.py index fa921e6a9288f52d663c9307a57d663dcd9afe54..01757828ebe010990412c7dd2037bf3bea9e1d8e 100644 --- a/bpfin/tests/test_financials/test_financial_saving.py +++ b/bpfin/tests/test_financials/test_financial_saving.py @@ -2,7 +2,8 @@ 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 -from bpfin.back_end_call.back_end_inputs import monthly_bill +from bpfin.back_end_call.back_end_inputs import form_annual_bill_table +from bpfin.lib.other import UTILITY_TYPE_LIST def test_Saving_put_monthly_proforma(): @@ -91,7 +92,7 @@ def test_Saving_Overview(): 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] + prior_monthly_bill = form_annual_bill_table(db.raw_monthly_bill_table, db. raw_annual_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 @@ -135,7 +136,7 @@ def test_Saving_Overview(): 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_electricity_annual_saving_charge = saving_overview.get_utility_annual_saving_charge(UTILITY_TYPE_LIST[0]) result_post_annual_bill_table = saving_overview.get_post_annual_bill_table() assert result_first_year_saving == output_first_year_saving diff --git a/bpfin/tests/test_utilbills/test_bill.py b/bpfin/tests/test_utilbills/test_bill.py index 02ebf740ddc9e5091a6222f6fd277db901a85320..9223b407686b5e0d41cea4eb73ab3e0c40ab5811 100644 --- a/bpfin/tests/test_utilbills/test_bill.py +++ b/bpfin/tests/test_utilbills/test_bill.py @@ -1,41 +1,39 @@ from datetime import date from bpfin.utilbills.bill import Bill from bpfin.tests.testdata import feature_data as db +from bpfin.lib.other import UTILITY_TYPE_LIST -UTILITY_TYPE_LIST = ['electricity', 'gas', 'oil', 'water'] - - -def test_Bill_put_month(): +def test_Bill_put_raw_bill(): """ 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() - + input_raw_monthly_bill = db.raw_monthly_bill_table[utility] + input_raw_annual_bill = db.raw_annual_bill_table[utility] + current_bill = Bill(utility, analysis_date) + current_bill.put_raw_bill(input_raw_monthly_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_prior_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_put_annual(): +# """ +# test Bill with utility inputs +# """ +# analysis_date = db.analysis_date + +# for utility in UTILITY_TYPE_LIST: +# if not db.raw_monthly_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(): # """ diff --git a/bpfin/tests/test_utilbills/test_month_normalize_rough.py b/bpfin/tests/test_utilbills/test_month_normalize_rough.py index 74e0318a532833107534c9262bd84654f6c8fa0e..f1f816551126b7437208e8008251a4650f44601b 100644 --- a/bpfin/tests/test_utilbills/test_month_normalize_rough.py +++ b/bpfin/tests/test_utilbills/test_month_normalize_rough.py @@ -1,13 +1,14 @@ import datetime from bpfin.utilbills.bill_month_normalize_rough import bill_month_normalize_rough from bpfin.tests.testdata import sample_data as db +from bpfin.lib.other import UTILITY_TYPE_LIST def test_month_normalization_rough(): input_dict = db.raw_bill output_dict = db.monthly_normalized_bill - result_dict = bill_month_normalize_rough('electricity', input_dict) + result_dict = bill_month_normalize_rough(UTILITY_TYPE_LIST[0], input_dict) assert result_dict == output_dict diff --git a/bpfin/tests/testdata/feature_data.py b/bpfin/tests/testdata/feature_data.py index 1ec42900797033744d714caea5c65f6559a83eba..a6080ef9afdf200cc708e184a9944e4dc947dcfe 100644 --- a/bpfin/tests/testdata/feature_data.py +++ b/bpfin/tests/testdata/feature_data.py @@ -2,6 +2,7 @@ feature_data.py is a fake database to store demo test data """ from datetime import date +from bpfin.lib.other import UTILITY_TYPE_LIST # from bpfin.utilbills.bill import form_bill_list_month # from bpfin.utilbills.bill import form_annual_bill_table # from bpfin.utilbills.bill import Bill_Table @@ -44,24 +45,24 @@ customer_preference = { } -percent_saving_dict = { - 'electricity': 0.25, - 'gas': 0.10, - 'oil': 0.80, - 'water': 0.0 +percent_saving_fdict = { + UTILITY_TYPE_LIST[0]: 0.25, + UTILITY_TYPE_LIST[1]: 0.10, + UTILITY_TYPE_LIST[2]: 0.80, + UTILITY_TYPE_LIST[3]: 0.0 } full_saving_dict = { - 'electricity': None, - 'gas': None, - 'oil': None, - 'water': None + UTILITY_TYPE_LIST[0]: None, + UTILITY_TYPE_LIST[1]: None, + UTILITY_TYPE_LIST[2]: None, + UTILITY_TYPE_LIST[3]: None } # dict of engineering analysis, {'date_from': [], 'date_to': [], 'heating': [], 'cooling': [], 'other': []} raw_elec_bill_demo = {} -raw_elec_bill_demo['utility_type'] = 'electricity' +raw_elec_bill_demo['utility_type'] = UTILITY_TYPE_LIST[0] 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), @@ -96,7 +97,7 @@ raw_elec_bill_demo['usage'] = [ 190.8, 189.42, 214.66] raw_gas_bill_demo = {} -raw_gas_bill_demo['utility_type'] = 'gas' +raw_gas_bill_demo['utility_type'] = UTILITY_TYPE_LIST[1] 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), @@ -127,7 +128,7 @@ raw_gas_bill_demo['usage'] = [ 429.00, 389.00, 429.00, 402.00] raw_oil_bill_demo = {} -raw_oil_bill_demo['utility_type'] = 'oil' +raw_oil_bill_demo['utility_type'] = UTILITY_TYPE_LIST[2] 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), @@ -162,7 +163,7 @@ raw_oil_bill_demo['usage'] = [ 1350, 1550, 1450] raw_water_bill_demo = {} -raw_water_bill_demo['utility_type'] = 'water' +raw_water_bill_demo['utility_type'] = UTILITY_TYPE_LIST[3] raw_water_bill_demo['date_from'] = [ date(2016, 1, 3), date(2015, 1, 1), date(2014, 1, 2)] raw_water_bill_demo['date_to'] = [ @@ -172,17 +173,17 @@ raw_water_bill_demo['charge'] = [ 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_monthly_bill_table = { + UTILITY_TYPE_LIST[0]: raw_elec_bill_demo, + UTILITY_TYPE_LIST[1]: raw_gas_bill_demo, + UTILITY_TYPE_LIST[2]: raw_oil_bill_demo, + UTILITY_TYPE_LIST[3]: None} # raw_bill_table = { -# 'gas': None, -# 'electricity': None, -# 'oil': None, -# 'water': None} +# UTILITY_TYPE_LIST[1]: None, +# UTILITY_TYPE_LIST[0]: None, +# UTILITY_TYPE_LIST[2]: None, +# UTILITY_TYPE_LIST[3]: None} # raw annual_bill # annual_bill_gas = {2014: 0, 2015: 1020, 2016: 1220, 2017: 1520} @@ -193,24 +194,24 @@ annual_bill_water = {2014: 20000, 2015: 20500, 2016: 21000} # annual_bill_oil = {2015: 1010, 2016: 1210, 2017: 1510} raw_annual_bill_table = { - 'electricity': None, - 'gas': None, - 'oil': None, - 'water': annual_bill_water + UTILITY_TYPE_LIST[0]: None, + UTILITY_TYPE_LIST[1]: None, + UTILITY_TYPE_LIST[2]: None, + UTILITY_TYPE_LIST[3]: annual_bill_water } # raw_annual_bill_table = { -# 'electricity': None, -# 'gas': None, -# 'oil': None, -# 'water': None +# UTILITY_TYPE_LIST[0]: None, +# UTILITY_TYPE_LIST[1]: None, +# UTILITY_TYPE_LIST[2]: None, +# UTILITY_TYPE_LIST[3]: None # } manual_input_dict = { - 'electricity': False, - 'gas': False, - 'oil': False, - 'water': True + UTILITY_TYPE_LIST[0]: False, + UTILITY_TYPE_LIST[1]: False, + UTILITY_TYPE_LIST[2]: False, + UTILITY_TYPE_LIST[3]: True } # raw income_statement @@ -254,17 +255,17 @@ raw_income_input = { # saving scenarios percent_saving_dict = { - 'electricity': 0.25, - 'gas': 0.10, - 'oil': 0.80, - 'water': 0.0 + UTILITY_TYPE_LIST[0]: 0.25, + UTILITY_TYPE_LIST[1]: 0.10, + UTILITY_TYPE_LIST[2]: 0.80, + UTILITY_TYPE_LIST[3]: 0.0 } full_saving_dict = { - 'electricity': None, - 'gas': None, - 'oil': None, - 'water': None + UTILITY_TYPE_LIST[0]: None, + UTILITY_TYPE_LIST[1]: None, + UTILITY_TYPE_LIST[2]: None, + UTILITY_TYPE_LIST[3]: None } # dict of engineering analysis, {'date_from': [], 'date_to': [], 'heating': [], 'cooling': [], 'other': []} @@ -290,7 +291,7 @@ raw_loan_input_list = [loan_term_1, loan_term_2, loan_term_3] # ****** result ***** prior_annual_bill = { - 'electricity': { + UTILITY_TYPE_LIST[0]: { 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, @@ -299,7 +300,7 @@ prior_annual_bill = { 2032: 1153.3039252083101, 2033: 1175.9341789481377, 2034: 1199.1695873801598, 2035: 1223.0386652944458, 2036: 1247.5443683668141 }, - 'gas': { + UTILITY_TYPE_LIST[1]: { 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, @@ -308,7 +309,7 @@ prior_annual_bill = { 2032: 6513.1311498178793, 2033: 6640.9586307853224, 2034: 6772.2131729990733, 2035: 6907.0434291160136, 2036: 7045.4681428808135 }, - 'oil': { + UTILITY_TYPE_LIST[2]: { 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, @@ -317,7 +318,7 @@ prior_annual_bill = { 2032: 42544.132418124602, 2033: 43378.864396965881, 2034: 44235.89304442647, 2035: 45116.305108602697, 2036: 46020.203841190028 }, - 'water': { + UTILITY_TYPE_LIST[3]: { 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, @@ -710,34 +711,34 @@ historical_cagr = 0.01242283656582921 growth_rate_flag = -2.0 budget_simulation_result = [ - [['saving_percentage', 0.1, 0.2, 0.30000000000000004, 0.4, 0.5], - ['Budget', 37723.783022506694, 68031.962268808478, 68031.962268808478, 68031.962268808478, 68031.962268808478], - ['NYSERDA', 0.0, 0.0, 0.0, 0.0, 0.0], - ['Joe Fund', 37723.783022506694, 50000.0, 50000.0, 50000.0, 50000.0], - ['Tooraj Capital', 0.0, 18031.962268808486, 18031.962268808486, 18031.962268808486, 18031.962268808486], - ['Self Finance', 0.0, 0.0, 0.0, 0.0, 0.0]], - [['saving_percentage', 0.1, 0.2, 0.30000000000000004, 0.4, 0.5], - ['Budget', 37723.783022506694, 77213.635268808473, 118031.96226880848, 118031.96226880848, 118031.96226880848], - ['NYSERDA', 0.0, 0.0, 0.0, 0.0, 0.0], - ['Joe Fund', 37723.783022506694, 50000.0, 50000.0, 50000.0, 50000.0], - ['Tooraj Capital', 0.0, 18031.962268808486, 18031.962268808486, 18031.962268808486, 18031.962268808486], - ['Self Finance', 0.0, 9181.6730000000007, 50000.0, 50000.0, 50000.0]], - [['saving_percentage', 0.1, 0.2, 0.30000000000000004, 0.4, 0.5], - ['Budget', 52184.67464428641, 89908.457666793111, 118031.96226880848, 118031.96226880848, 118031.96226880848], - ['NYSERDA', 0.0, 0.0, 0.0, 0.0, 0.0], - ['Joe Fund', 2184.6746442864069, 39908.457666793111, 50000.0, 50000.0, 50000.0], - ['Tooraj Capital', 0.0, 0.0, 18031.962268808486, 18031.962268808486, 18031.962268808486], - ['Self Finance', 50000.0, 50000.0, 50000.0, 50000.0, 50000.0]], - [['saving_percentage', 0.1, 0.2, 0.30000000000000004, 0.4, 0.5], - ['Budget', 87723.783022506686, 118031.96226880848, 118031.96226880848, 118031.96226880848, 118031.96226880848], - ['NYSERDA', 0.0, 0.0, 0.0, 0.0, 0.0], - ['Joe Fund', 37723.783022506694, 50000.0, 50000.0, 50000.0, 50000.0], - ['Tooraj Capital', 0.0, 18031.962268808486, 18031.962268808486, 18031.962268808486, 18031.962268808486], - ['Self Finance', 50000.0, 50000.0, 50000.0, 50000.0, 50000.0]] + [['saving_percentage', 0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5], + ['Budget', 0.0, 37723.783022506694, 68031.962268808478, 68031.962268808478, 68031.962268808478, 68031.962268808478], + ['NYSERDA', 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ['Joe Fund', 0.0, 37723.783022506694, 50000.0, 50000.0, 50000.0, 50000.0], + ['Tooraj Capital', 0.0, 0.0, 18031.962268808486, 18031.962268808486, 18031.962268808486, 18031.962268808486], + ['Self Finance', 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]], + [['saving_percentage', 0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5], + ['Budget', 0.0, 37723.783022506694, 77213.635268808473, 118031.96226880848, 118031.96226880848, 118031.96226880848], + ['NYSERDA', 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ['Joe Fund', 0.0, 37723.783022506694, 50000.0, 50000.0, 50000.0, 50000.0], + ['Tooraj Capital', 0.0, 0.0, 18031.962268808486, 18031.962268808486, 18031.962268808486, 18031.962268808486], + ['Self Finance', 0.0, 0.0, 9181.6730000000007, 50000.0, 50000.0, 50000.0]], + [['saving_percentage', 0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5], + ['Budget', 0.0, 52184.67464428641, 89908.457666793111, 118031.96226880848, 118031.96226880848, 118031.96226880848], + ['NYSERDA', 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ['Joe Fund', 0.0, 2184.6746442864069, 39908.457666793111, 50000.0, 50000.0, 50000.0], + ['Tooraj Capital', 0.0, 0.0, 0.0, 18031.962268808486, 18031.962268808486, 18031.962268808486], + ['Self Finance', 0.0, 50000.0, 50000.0, 50000.0, 50000.0, 50000.0]], + [['saving_percentage', 0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5], + ['Budget', 50000.0, 87723.783022506686, 118031.96226880848, 118031.96226880848, 118031.96226880848, 118031.96226880848], + ['NYSERDA', 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ['Joe Fund', 0.0, 37723.783022506694, 50000.0, 50000.0, 50000.0, 50000.0], + ['Tooraj Capital', 0.0, 0.0, 18031.962268808486, 18031.962268808486, 18031.962268808486, 18031.962268808486], + ['Self Finance', 50000.0, 50000.0, 50000.0, 50000.0, 50000.0, 50000.0]] ] post_annual_bill = { - 'electricity': { + UTILITY_TYPE_LIST[0]: { 2012: 792.50603354980865, 2013: 806.56436875723125, 2014: 819.06930386346062, @@ -764,7 +765,7 @@ post_annual_bill = { 2035: 917.27899897083421, 2036: 935.65827627511044 }, - 'gas': { + UTILITY_TYPE_LIST[1]: { 2012: 4475.7823032289816, 2013: 4554.23035844273, 2014: 4625.0674743716318, @@ -791,7 +792,7 @@ post_annual_bill = { 2035: 6216.3390862044125, 2036: 6340.9213285927335 }, - 'oil': { + UTILITY_TYPE_LIST[2]: { 2012: 29234.099384206329, 2013: 29755.35937994433, 2014: 30216.03963037725, @@ -818,7 +819,7 @@ post_annual_bill = { 2035: 9023.2610217205365, 2036: 9204.0407682380028 }, - 'water': { + UTILITY_TYPE_LIST[3]: { 2012: 20500.0, 2013: 20500.0, 2014: 20000, diff --git a/bpfin/utilbills/bill.py b/bpfin/utilbills/bill.py index 0f4593f067e35a6c4354eca4b075bb64c6ecc8df..d86df376db3f6ff1758fc9a78331e81ceb49e98d 100644 --- a/bpfin/utilbills/bill.py +++ b/bpfin/utilbills/bill.py @@ -1,25 +1,20 @@ from datetime import date import copy import sys -from bpfin.utilbills.bill_lib import annualizing_projection -from bpfin.utilbills.bill_lib import form_bill_calendar -from bpfin.utilbills.bill_lib import form_bill_year -# from bpfin.lib.other import average_nonzero_list -from bpfin.lib.other import form_date_calendar +from bpfin.utilbills.bill_lib import annualizing_projection, form_bill_calendar, form_bill_year 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 average_list_with_none, form_date_calendar from bpfin.lib.other import UTILITY_TYPE_LIST -from bpfin.tests.testdata import feature_data as db -from bpfin.lib.other import average_list_with_none -# from bpfin.tests.testdata import feature_data as db +# from bpfin.lib.other import average_nonzero_list -def validate_raw_bill(raw_bill): +def validate_raw_monthly_bill(raw_monthly_bill): """ - Raw bill validation. A valid raw_bill is not None, and it covers at least 12 months + Raw bill validation. A valid raw_monthly_bill is not None, and it covers at least 12 months Args: - raw_bill (dictionary): dictionary of lists. Keys are + raw_monthly_bill (dictionary): dictionary of lists. Keys are 'date_from': list of datetime, 'date_to', list of datetime, 'usage', list of float values, @@ -27,10 +22,10 @@ def validate_raw_bill(raw_bill): Return: Bollean: True == data validated. False == data is not validated """ - if raw_bill: + if raw_monthly_bill: month_list = form_date_calendar( - raw_bill['date_from'][0], - raw_bill['date_to'][-1])[1] + raw_monthly_bill['date_from'][0], + raw_monthly_bill['date_to'][-1])[1] if len(month_list) >= 12: return True else: @@ -76,17 +71,23 @@ class Bill(): Project bill for the past and for the future for pro-forma porpuse, with inflation applied Attributes: - monthly_normalized_bill_rough (dictionary): dict of lists, for 12 months of usage, charge and price - prior_bill_rough (dictionary): dictionary of lists, prior_saving bill, for pro-forma period - monthly_normailzed_bill_reg (dictionary): unknown - prior_bill_reg (dictionary): unknown - annual_bill (dictionary): dict of float, annual charge for pro-forma period. {year: float} utility_type (string): utility type analysis_date (dictionary): proforma's starting date and the years of proforma proforma_date (list): list of dates, months of pro-forma time period is_manual_input (boolean): flag of raw bill validation. True == raw bill is not valid, annual bills are manually input False == raw bill is valid, annual bills are calculated automatically + raw_monthly_bill (dictionary): dictionary of lists. Keys are + 'date_from': list of date, + 'date_to', list of date, + 'usage', list of float, + 'charge', list of float, + raw_annual_bill (dictionary): {year: float}. annual bill allowing some years data missing + monthly_normalized_bill_rough (dictionary): dict of lists, for 12 months of usage, charge and price + prior_bill_rough (dictionary): dictionary of lists, prior_saving bill, for pro-forma period + monthly_normailzed_bill_reg (dictionary): unknown + prior_bill_reg (dictionary): unknown + annual_bill (dictionary): dict of float, annual charge for pro-forma period. {year: float} Description: monthly_normalized_bill_rough = { @@ -107,12 +108,17 @@ class Bill(): Add in rate plan feature to replace/supplement current rough monthly pricing method """ + utility_type = None + analysis_date = None + proforma_date = None + is_manual_input = None + raw_monthly_bill = None + raw_annual_bill = None monthly_normalized_bill_rough = None prior_bill_rough = None monthly_normailzed_bill_reg = None prior_bill_reg = None - annual_bill = None - utility_type = None + prior_annual_bill = None def __init__(self, utility_type, analysis_date): """ @@ -126,48 +132,52 @@ class Bill(): self.proforma_date = form_bill_calendar(analysis_date['proforma_start'], analysis_date['proforma_duration'])[1] self.is_manual_input = True - def put_month_bill(self, raw_bill): + def put_raw_bill(self, raw_monthly_bill, raw_annual_bill): """ - Put raw monthly bill. - Validate input data (Not None and time coverage >=12 months) - Roughly month_normalize the bill and roughly project prior_saving bill - Determine annual bill with prior_saving bill + Put raw monthly bill and raw annual bill. + Validate input data + If monthly bill is Not None and time coverage >=12 months: + Roughly month_normalize the bill and roughly project prior_saving bill + Else: + Project annual energy bill and project prior_saving bill only for annual + Determine all annual bill with prior_saving bill Args: - raw_bill (dictionary): dictionary of lists. Keys are + raw_monthly_bill (dictionary): dictionary of lists. Keys are 'date_from': list of date, 'date_to', list of date, 'usage', list of float, 'charge', list of float, + raw_annual_bill (dictionary): {year: float}. annual bill allowing some years data missing """ - validation = validate_raw_bill(raw_bill) + self.raw_monthly_bill = raw_monthly_bill + self.raw_annual_bill = raw_annual_bill + + validation = validate_raw_monthly_bill(raw_monthly_bill) if validation: - self.monthly_normalized_bill_rough = bill_month_normalize_rough(self.utility_type, copy.deepcopy(raw_bill)) + self.monthly_normalized_bill_rough = bill_month_normalize_rough( + self.utility_type, + copy.deepcopy(raw_monthly_bill) + ) self.is_manual_input = False self.prior_bill_rough = bill_prior_proj_rough( copy.deepcopy(self.monthly_normalized_bill_rough), - copy.deepcopy(raw_bill), + copy.deepcopy(raw_monthly_bill), self.analysis_date, inflation_coeff_dict ) - self.annual_bill = annualizing_projection(self.proforma_date, self.prior_bill_rough['charge']) + self.prior_annual_bill = annualizing_projection(self.proforma_date, self.prior_bill_rough['charge']) else: + # if self.raw_annual_bill: + self.prior_annual_bill = estimate_annual_bill( + copy.deepcopy(self.raw_annual_bill), + self.analysis_date + ) if validation == -1: raise ValueError('monthly bill input not valid for ', self.utility_type) else: pass - def put_annual_bill(self, raw_annual_bill): - """ - Put annual bill to the bill with raw bill not valid (manual_input == True) - Calculate average annual charge and assign the average value to missing years - - Args: - raw_annual_bill (dictionary): {year: float}. annual bill allowing some years data missing - """ - if self.is_manual_input: - self.annual_bill = estimate_annual_bill(raw_annual_bill, self.analysis_date) - def get_prior_proj_rough(self): """ Get roughly projected prior_saving monthly bill @@ -189,13 +199,13 @@ class Bill(): """ return self.prior_bill_reg - def get_annual_bill(self): + def get_prior_annual_bill(self): """ Get annual bill in dictionary format Return: dictionary: {year, float} """ - return self.annual_bill + return self.prior_annual_bill def get_manual_input(self): """ @@ -206,150 +216,22 @@ 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 - -# class Bill_Table(): -# """ -# """ -# def __init__(self, analysis_date): -# """ -# """ -# self.analysis_date = analysis_date -# self.raw_bill_table = None -# self.manual_input_dict = {} -# self.raw_annual_bill_table = None -# self.utility_bill_dict = {} # dict of object -# for utility_type in UTILITY_TYPE_LIST: -# self.utility_bill_dict[utility_type] = Bill(utility_type, analysis_date) - -# def put_month_bill_table(self, raw_bill_table): -# """ -# """ -# self.raw_bill_table = raw_bill_table -# for utility_type in UTILITY_TYPE_LIST: -# if utility_type in self.raw_bill_table: -# self.utility_bill_dict[utility_type].put_month_bill(self.raw_bill_table[utility_type]) -# # else: -# # self.utility_bill_dict[utility_type].put_month_bill(None) -# self.manual_input_dict[utility_type] = copy.deepcopy(self.utility_bill_dict[utility_type].is_manual_input) - -# def put_annual_bill_table(self, raw_annual_bill_table): -# """ -# """ -# self.raw_annual_bill_table = raw_annual_bill_table -# for utility_type in UTILITY_TYPE_LIST: -# if utility_type in self.raw_annual_bill_table: -# self.utility_bill_dict[utility_type].put_annual_bill(self.raw_annual_bill_table[utility_type]) - -# def get_bill_overview(self): -# """ -# should be deleted or replaced when future calling func got updated -# because all functions would need to use either the bill or the yes/no flag. -# """ -# bill_overview = {} -# for utility_type in UTILITY_TYPE_LIST: -# bill_overview[utility_type] = [ -# ( -# self.raw_annual_bill_table[utility_type] if -# self.utility_bill_dict[utility_type].is_manual_input -# else self.utility_bill_dict[utility_type].get_annual_bill() -# ), -# self.utility_bill_dict[utility_type].is_manual_input -# ] -# return bill_overview - -# def get_annual_bill_table(self): -# """ -# Annual bill table, for 4 utility types, with annualized projected charge, or average annual charge -# sample_data.bill_overview_organized -# """ -# annual_bill_table = {} -# for utility_type in UTILITY_TYPE_LIST: -# annual_bill_table[utility_type] = self.utility_bill_dict[utility_type].get_annual_bill() -# return annual_bill_table - -# def get_bill_list(self): -# """ -# Get list of Bill objects. For future use in other functions -# Return: -# list: list of Bill objects. Order in 'electricity', 'gas', 'oil', 'water' -# """ -# bill_list = [] -# for utility_type in UTILITY_TYPE_LIST: -# bill_list.append(copy.deepcopy(self.utility_bill_dict[utility_type])) -# return bill_list - # **** ugly test **** -# e_bill = Bill('electricity', db.analysis_date) -# e_bill.put_month_bill(db.raw_bill_table['electricity']) +# from bpfin.tests.testdata import feature_data as db +# e_bill = Bill('electric', db.analysis_date) +# e_bill.put_month_bill(db.raw_monthly_bill_table['electric']) # print('\n annual_bill_rough', e_bill.annual_bill) -# o_bill = Bill(db.raw_bill_dict['oil'], db.analysis_date) +# o_bill = Bill(db.raw_monthly_bill_dict['oil'], db.analysis_date) # o_bill.put_annual_bill(db.raw_annual_bill_dict['oil']) # print('\n annual_bill_oil', o_bill.get_annual_bill()) -# bill_table = Bill_Table(db.raw_bill_table, db.analysis_date) +# bill_table = Bill_Table(db.raw_monthly_bill_table, db.analysis_date) # bill_table.put_annual_bill_table(db.raw_annual_bill_table) # 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)) +# print(form_prior_month_bill(db.raw_monthly_bill_table, db.analysis_date, True)) diff --git a/bpfin/utilbills/bill_lib.py b/bpfin/utilbills/bill_lib.py index 69d21ca09842c039d915905513df9114fd6f4b9a..7d4765e7a235e32cc5126127db1bb31fa8185448 100644 --- a/bpfin/utilbills/bill_lib.py +++ b/bpfin/utilbills/bill_lib.py @@ -3,6 +3,36 @@ import calendar import pandas as pd import copy from bpfin.lib.other import month_shift +from bpfin.lib.other import UTILITY_TYPE_LIST + + +def sum_energy_opex(bill_overview_dict): + """Calculate total energy opex + Args: + bill_overview_dict = { + 'electric': {2014: 100, 2015:200, ...}, + 'oil': dict of oil_bill, + 'gas': dict of gas_bill, + 'water': dict of water_bill} + Return: + dictionary: total energy expense with year as key + list: total energy expense in list + """ + proforma_year = sorted(bill_overview_dict[UTILITY_TYPE_LIST[0]]) + total_opex_dict = {} + total_opex_list = [] + for year in proforma_year: + opex = 0 + for utility in UTILITY_TYPE_LIST: + if year in bill_overview_dict[utility]: + opex += bill_overview_dict[utility][year] + else: + # opex +=0 + raise ValueError('Key error: year not in bill_overview_dict when cal total bill. Year:', year) + total_opex_dict[year] = opex + total_opex_list.append(opex) + + return total_opex_dict, total_opex_list def add_list(obj_list, number): diff --git a/bpfin/utilbills/data_generation.py b/bpfin/utilbills/data_generation.py index dd81a5a94abaf1cf4cd9417b2bdf4d471af78af5..f03a42f695679182a46cf394568dd45b6afd55e2 100644 --- a/bpfin/utilbills/data_generation.py +++ b/bpfin/utilbills/data_generation.py @@ -23,7 +23,7 @@ # saving = Saving(datetime.date(2017, 11, 1), db.proforma_date_to, db.prior_proj_rough_charge, db.post_proj_rough_charge) # # print(saving_list) -# post_energy_bill['electricity'] = saving.get_annual_bill() +# post_energy_bill['electric'] = saving.get_annual_bill() # IS_post = fl.Income_Statement_Table(raw_income_input, post_energy_bill) # IS_post.project(-2.0, db.analysis_date, post_energy_bill) diff --git a/setup.py b/setup.py index 0f6f22b4269b975fc5614b860715e971c0988bff..c8098820cfa13cc114500eca5fda8aabef271198 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ reqs = [str(req.req) for req in install_reqs] setup( name='bpfin', - version='0.1.7', + version='0.2.0', description='Finance models and utilites', author='BlocPower', author_email='admin@blocpower.org',