diff --git a/bpfin/back_end_call/back_end_budget.py b/bpfin/back_end_call/back_end_budget.py index 8fc31368369c9497f847872bb64a3c90fb434cb5..b004567eeb0c75d7642192d746c515eb9739cc41 100644 --- a/bpfin/back_end_call/back_end_budget.py +++ b/bpfin/back_end_call/back_end_budget.py @@ -1,5 +1,5 @@ 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 @@ -78,7 +78,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) @@ -149,7 +149,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..30f08b2f7c119949db703b51cf4b52591a1f170f 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,9 +33,9 @@ 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 = { + raw_monthly_bill_table = { 'electricity': { 'date_from': list of date, 'date_to', list of date, @@ -45,7 +46,11 @@ def monthly_bill(raw_bill_table, analysis_date): 'oil': None, 'water': None } - + raw_annual_bill_table = { + 'electricity': {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, ...}, 'oil': dict of oil_bill, @@ -55,23 +60,20 @@ 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]) - else: - current_bill.put_month_bill(None) - bill_overview_dict[utility] = current_bill.get_annual_bill() + current_bill.put_raw_bill(raw_monthly_bill_table[utility], 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 +82,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 +116,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,7 +130,7 @@ 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 = { + raw_monthly_bill_table = { 'electricity': { 'date_from': list of date, 'date_to', list of date, @@ -188,7 +151,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 +164,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..bfabaac7f977f1b7151403e8fd99b24464d6d708 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,7 +44,7 @@ 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 = { + raw_monthly_bill_table = { 'electricity': { 'date_from': list of date, 'date_to', list of date, @@ -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/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..62c924f429ad1ceeb9a9d22bec450ee3e5ca1ce4 100644 --- a/bpfin/tests/test_financials/test_financial_saving.py +++ b/bpfin/tests/test_financials/test_financial_saving.py @@ -2,7 +2,7 @@ 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 def test_Saving_put_monthly_proforma(): @@ -91,7 +91,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 diff --git a/bpfin/tests/testdata/feature_data.py b/bpfin/tests/testdata/feature_data.py index 1ec42900797033744d714caea5c65f6559a83eba..6497dd17d3f7d74b442b0c9cecfdd85fc89a15f8 100644 --- a/bpfin/tests/testdata/feature_data.py +++ b/bpfin/tests/testdata/feature_data.py @@ -172,7 +172,7 @@ raw_water_bill_demo['charge'] = [ raw_water_bill_demo['usage'] = [ 3500000, 3600000, 3300000] -raw_bill_table = { +raw_monthly_bill_table = { 'gas': raw_gas_bill_demo, 'electricity': raw_elec_bill_demo, 'oil': raw_oil_bill_demo, @@ -710,30 +710,30 @@ 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 = { diff --git a/bpfin/utilbills/bill.py b/bpfin/utilbills/bill.py index 0f4593f067e35a6c4354eca4b075bb64c6ecc8df..93616fa00028c8666f072a08f631f875c9660d8d 100644 --- a/bpfin/utilbills/bill.py +++ b/bpfin/utilbills/bill.py @@ -15,11 +15,11 @@ from bpfin.lib.other import average_list_with_none # from bpfin.tests.testdata import feature_data as db -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 +27,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 +76,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 +113,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 +137,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 +204,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 +221,21 @@ 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']) +# e_bill.put_month_bill(db.raw_monthly_bill_table['electricity']) # 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..5885f914b539ae54f3ae6b414aae719f93cd36bc 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 = { + 'electricity': {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/setup.py b/setup.py index 37eca03c5a87003585298e5e7a09ecac584355ac..0f426463aaf7100bb7505f439a8f2f9dbe1f0e5e 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.0', + version='0.1.8', description='Finance models and utilites', author='BlocPower', author_email='admin@blocpower.org',