From d59781d3d636319630115de3e1cfb8ef1b3842d0 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Tue, 2 May 2017 11:39:45 -0400 Subject: [PATCH 01/15] Create Saving_Overview class --- bpfin/financials/saving.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/bpfin/financials/saving.py b/bpfin/financials/saving.py index 2c8a5df..ff3d633 100644 --- a/bpfin/financials/saving.py +++ b/bpfin/financials/saving.py @@ -82,3 +82,22 @@ class Saving(): """ annual_proforma_bill = annualizing_projection(self.proforma_date, self.proforma_bill) return annual_proforma_bill + + +def Saving_Overview(): + """ + Generate saving schedule, annual usages and charges for 4 utility types + Also calculate percentage saving on usages and charges. + If rate plan applies, usage % saving can be different from charge % saving + Saving_Overview should be scenario based, aka it is an "attribute" of a scenario + Attributes: + saving_percent_usage (dictionary): key is utility type, value is float {'electricity': float} + saving_percent_charge (dictionary): key is utility type, value is float {'electricity': float} + total_first_year_saving (float): saving on charge for the first 12 month after commissioning + total_saving_percent (float): percentage saving on charge for the first 12 month after commissioning + """ + def __init__(self): + self.saving_percent_usage = {'electricity': None, 'gas': None, 'oil': None, 'water': None} + self.saving_percent_charge = {'electricity': None, 'gas': None, 'oil': None, 'water': None} + self.total_first_year_saving = None + self.total_saving_percent = None -- GitLab From fa14fd9db2ed34a5cc8d9d2040cbc404f0b05acf Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Tue, 2 May 2017 14:19:48 -0400 Subject: [PATCH 02/15] Add is_manual_input judgement in Saving, for No mannual input. Make draft in test_saving Add discriptive comments. --- bpfin/financials/financial_lib.py | 3 + bpfin/financials/saving.py | 127 ++++++++++++++------- bpfin/tests/test_financials/test_saving.py | 31 +++++ bpfin/tests/testdata/sample_data.py | 2 +- 4 files changed, 119 insertions(+), 44 deletions(-) diff --git a/bpfin/financials/financial_lib.py b/bpfin/financials/financial_lib.py index f9c22cc..787d4c1 100644 --- a/bpfin/financials/financial_lib.py +++ b/bpfin/financials/financial_lib.py @@ -20,6 +20,9 @@ def organize_bill_overview(bill_overview, analysis_date): Description: analysis_date: {'proforma_start': datetime.date, 'proforma_duration': int} + bill_overview (dictionary): dict of a list, + list[0] = dict of annual bill, allow some year missing, for 4 utility_types + list[1] = boolean value, False == from manual input, True == from scraper """ proforma_year = form_bill_year(analysis_date['proforma_start'], analysis_date['proforma_duration']) diff --git a/bpfin/financials/saving.py b/bpfin/financials/saving.py index ff3d633..da05aba 100644 --- a/bpfin/financials/saving.py +++ b/bpfin/financials/saving.py @@ -8,6 +8,7 @@ class Saving(): Calculate savings and project bills with commissioning date considered. Attributes: commissioning_date (date): the date that construction work finished, saving starts at NEXT month + is_manual_input (boolean): lable indicating is bill input by scraper or manual. Yes == manual input proforma_date (list): list of dates, months of pro-forma time period prior_saving_list (list): list of float, usage or charge without (prior to) savings post_saving_list (list): list of float, usage or charge with (post to) savings @@ -18,73 +19,112 @@ class Saving(): Data before commissioning date == historical Data after commissioning date == post saving data first_year_saving (float): first year saving, usage or charge + annual_proforma_bill {dictionary}: annual charge """ - def __init__(self, commissioning_date, proforma_date, prior_saving_list, post_saving_list): + def __init__(self, is_manual_input, commissioning_date, proforma_date, prior_saving_usage, post_saving_usage, prior_saving_charge, post_saving_charge): + """ + Initiate Saving object + + """ + self.is_manual_input = is_manual_input self.commissioning_date = commissioning_date self.proforma_date = proforma_date - self.prior_saving_list = prior_saving_list - self.post_saving_list = post_saving_list - self.proforma_bill = [] - self.proforma_saving = [] - self.first_year_saving = None + # self.prior_saving_usage = None + # self.post_saving_usage = None + # self.prior_saving_charge = None + # self.post_saving_charge = None + + self.proforma_usage = [] + self.proforma_charge = [] + self.proforma_saving_usage = [] + self.proforma_saving_charge = [] + self.first_year_saving_charge = None + self.first_year_saving_usage = None + self.annual_proforma_usage = {} + self.annual_proforma_charge = {} + + if self.is_manual_input is False: + saving_start_date = datetime.date( + self.commissioning_date.year, + self.commissioning_date.month, + cal_last_day(self.commissioning_date.year, self.commissioning_date.month)) + + saving_usage_dict = {} + saving_charge_dict = {} + proforma_usage_dict = {} + proforma_charge_dict = {} + first_year_saving_usage = 0 + first_year_saving_charge = 0 + first_yr_counter = 0 + for date, prior_usage, post_usage, prior_charge, post_charge in zip( + proforma_date, + prior_saving_usage, + post_saving_usage, + prior_saving_charge, + post_saving_charge): + if date > saving_start_date: + saving_usage_dict[date] = prior_usage - post_usage + saving_charge_dict[date] = prior_charge - post_charge + proforma_usage_dict[date] = post_usage + proforma_charge_dict[date] = post_charge + if first_yr_counter <= 12: + first_year_saving_usage += prior_usage - post_usage + first_year_saving_charge += prior_charge - post_charge + first_yr_counter += 1 + else: + saving_usage_dict[date] = 0 + saving_charge_dict[date] = 0 + proforma_usage_dict[date] = prior_usage + proforma_charge_dict[date] = prior_charge + + self.proforma_usage = list(proforma_usage_dict.values()) + self.proforma_charge = list(proforma_charge_dict.values()) + self.proforma_saving_usage = list(saving_usage_dict.values()) + self.proforma_saving_charge = list(saving_charge_dict.values()) + self.first_year_saving_usage = first_year_saving_usage + self.first_year_saving_charge = first_year_saving_charge + self.annual_proforma_usage = annualizing_projection(self.proforma_date, self.proforma_charge) + self.annual_proforma_charge = annualizing_projection(self.proforma_date, self.proforma_charge) - saving_start_date = datetime.date( - self.commissioning_date.year, - self.commissioning_date.month, - cal_last_day(self.commissioning_date.year, self.commissioning_date.month)) - saving_dict = {} - bill_dict = {} - first_year_saving = 0 - first_yr_count = 0 - for date, prior, post in zip(proforma_date, prior_saving_list, post_saving_list): - if date > saving_start_date: - saving_dict[date] = prior - post - bill_dict[date] = post - if first_yr_count <= 12: - first_year_saving += prior - post - first_yr_count += 1 - else: - saving_dict[date] = 0 - bill_dict[date] = prior - self.proforma_saving = list(saving_dict.values()) - self.proforma_bill = list(bill_dict.values()) - self.first_year_saving = first_year_saving + # self.proforma_saving = list(saving_dict.values()) + # self.proforma_bill = list(bill_dict.values()) + # self.first_year_saving = first_year_saving + # self.annual_proforma_bill = annualizing_projection(self.proforma_date, self.proforma_bill) - def get_proforma_bill(self): + def get_proforma_charge(self): """ - Get proforma_bill + Get proforma_charge Return: - list: proforma_bill + list: proforma_charge """ - return self.proforma_bill + return self.proforma_charge - def get_proforma_saving(self): + def get_proforma_saving_charge(self): """ - Get proforma_saving + Get proforma_saving_charge Return: - list: proforma_saving + list: proforma_saving_charge """ - return self.proforma_saving + return self.proforma_saving_charge - def get_first_year_saving(self): + def get_first_year_saving_charge(self): """ Get first year saving Return: float: sum of first 12 months of savings """ - return self.first_year_saving + return self.first_year_saving_charge - def get_annual_bill(self): + def get_annual_proforma_charge(self): """ - Calculate and return annual pro-forma usage or charge + Calculate and return annual pro-forma charge Return: - dictionary: dict of annual item, {year: annual usage or charge} + dictionary: dict of annual item, {year: annual charge} """ - annual_proforma_bill = annualizing_projection(self.proforma_date, self.proforma_bill) - return annual_proforma_bill + return self.annual_proforma_charge -def Saving_Overview(): +class Saving_Overview(): """ Generate saving schedule, annual usages and charges for 4 utility types Also calculate percentage saving on usages and charges. @@ -101,3 +141,4 @@ def Saving_Overview(): self.saving_percent_charge = {'electricity': None, 'gas': None, 'oil': None, 'water': None} self.total_first_year_saving = None self.total_saving_percent = None +# input = bill_overview manual input lable, pass in none if manual input diff --git a/bpfin/tests/test_financials/test_saving.py b/bpfin/tests/test_financials/test_saving.py index cf6be7b..b23e94b 100644 --- a/bpfin/tests/test_financials/test_saving.py +++ b/bpfin/tests/test_financials/test_saving.py @@ -31,3 +31,34 @@ def test_Saving(): assert elec_saving.get_annual_bill() == {2017: 770} # print('1st yr saving =', elec_saving.get_first_year_saving()) # print('annual_bill =', elec_saving.get_annual_bill()) + + +def test_Saving(): + input_proforma_date = [ + datetime.date(2017, 1, 31), + datetime.date(2017, 2, 28), + datetime.date(2017, 3, 31), + datetime.date(2017, 4, 30), + datetime.date(2017, 5, 31), + datetime.date(2017, 6, 30), + datetime.date(2017, 7, 31), + datetime.date(2017, 8, 31), + datetime.date(2017, 9, 30), + datetime.date(2017, 10, 31), + datetime.date(2017, 11, 30), + datetime.date(2017, 12, 31), ] + input_commissioning_date = datetime.date(2017, 3, 14) + input_prior_list = [100] * 12 + input_post_list = [100, 90, 80, 70, 60, 50, 40, 30, 40, 50, 60, 70] + + output_saving = [0, 0, 0, 30, 40, 50, 60, 70, 60, 50, 40, 30] + output_bill = [100, 100, 100, 70, 60, 50, 40, 30, 40, 50, 60, 70] + elec_saving = Saving(False, input_commissioning_date, input_proforma_date, input_prior_list, input_post_list) + result_saving = elec_saving.get_proforma_saving() + result_bill = elec_saving.get_proforma_bill() + assert output_saving == result_saving + assert output_bill == result_bill + assert elec_saving.get_first_year_saving() == 430 + assert elec_saving.get_annual_bill() == {2017: 770} + # print('1st yr saving =', elec_saving.get_first_year_saving()) + # print('annual_bill =', elec_saving.get_annual_bill()) diff --git a/bpfin/tests/testdata/sample_data.py b/bpfin/tests/testdata/sample_data.py index 9fd24b8..02cdd8f 100644 --- a/bpfin/tests/testdata/sample_data.py +++ b/bpfin/tests/testdata/sample_data.py @@ -95,7 +95,7 @@ annual_bill_oil = {2015: 1010, 2016: 1210, 2017: 1510} annual_bill_water = {2015: 0, 2016: 0, 2017: 0} bill_overview = { - 'electricity': [annual_bill_electricity, True], + 'electricity': [annual_bill_electricity, True], # True == scraper 'gas': [annual_bill_gas, False], 'oil': [annual_bill_oil, False], 'water': [annual_bill_water, False] -- GitLab From 6f245a6212b3f53e288c3dcf1b021f2015c5f2a5 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Tue, 2 May 2017 15:20:57 -0400 Subject: [PATCH 03/15] Add form_year_list in bill_lib Add annual_proforma in Saving class --- bpfin/financials/saving.py | 35 +++++---- bpfin/tests/test_financials/test_saving.py | 79 +++++++++++---------- bpfin/tests/test_utilbills/test_bill_lib.py | 8 +++ bpfin/utilbills/bill_lib.py | 22 ++++++ 4 files changed, 93 insertions(+), 51 deletions(-) diff --git a/bpfin/financials/saving.py b/bpfin/financials/saving.py index da05aba..4efd2e1 100644 --- a/bpfin/financials/saving.py +++ b/bpfin/financials/saving.py @@ -7,8 +7,8 @@ class Saving(): """ Calculate savings and project bills with commissioning date considered. Attributes: - commissioning_date (date): the date that construction work finished, saving starts at NEXT month is_manual_input (boolean): lable indicating is bill input by scraper or manual. Yes == manual input + commissioning_date (date): the date that construction work finished, saving starts at NEXT month proforma_date (list): list of dates, months of pro-forma time period prior_saving_list (list): list of float, usage or charge without (prior to) savings post_saving_list (list): list of float, usage or charge with (post to) savings @@ -21,7 +21,7 @@ class Saving(): first_year_saving (float): first year saving, usage or charge annual_proforma_bill {dictionary}: annual charge """ - def __init__(self, is_manual_input, commissioning_date, proforma_date, prior_saving_usage, post_saving_usage, prior_saving_charge, post_saving_charge): + def __init__(self, is_manual_input, commissioning_date, proforma_date): """ Initiate Saving object @@ -33,16 +33,16 @@ class Saving(): # self.post_saving_usage = None # self.prior_saving_charge = None # self.post_saving_charge = None - - self.proforma_usage = [] - self.proforma_charge = [] - self.proforma_saving_usage = [] - self.proforma_saving_charge = [] + self.proforma_usage = None + self.proforma_charge = None + self.proforma_saving_usage = None + self.proforma_saving_charge = None self.first_year_saving_charge = None self.first_year_saving_usage = None - self.annual_proforma_usage = {} - self.annual_proforma_charge = {} + self.annual_proforma_usage = None + self.annual_proforma_charge = None + def put_monthly_proforma(self, prior_saving_usage, post_saving_usage, prior_saving_charge, post_saving_charge): if self.is_manual_input is False: saving_start_date = datetime.date( self.commissioning_date.year, @@ -86,10 +86,19 @@ class Saving(): self.annual_proforma_usage = annualizing_projection(self.proforma_date, self.proforma_charge) self.annual_proforma_charge = annualizing_projection(self.proforma_date, self.proforma_charge) - # self.proforma_saving = list(saving_dict.values()) - # self.proforma_bill = list(bill_dict.values()) - # self.first_year_saving = first_year_saving - # self.annual_proforma_bill = annualizing_projection(self.proforma_date, self.proforma_bill) + # def put_annual_proforma(self, annual_bill, percent_saving): + # """ + # Args: + # annual_bill (dictionary): dict of annual charge, {2014: 100, 2015: 120, ...} + # percent_saving (float): + # """ + # if self.is_manual_input is True: + # proforma_year = + + + # def put_monthly_proforma_reg ?? + # do we do saving projection here? actually we can, and maybe we should + # it is not developed in front end yet def get_proforma_charge(self): """ diff --git a/bpfin/tests/test_financials/test_saving.py b/bpfin/tests/test_financials/test_saving.py index b23e94b..71f5a5b 100644 --- a/bpfin/tests/test_financials/test_saving.py +++ b/bpfin/tests/test_financials/test_saving.py @@ -2,35 +2,35 @@ import datetime from bpfin.financials.saving import Saving -def test_Saving(): - input_proforma_date = [ - datetime.date(2017, 1, 31), - datetime.date(2017, 2, 28), - datetime.date(2017, 3, 31), - datetime.date(2017, 4, 30), - datetime.date(2017, 5, 31), - datetime.date(2017, 6, 30), - datetime.date(2017, 7, 31), - datetime.date(2017, 8, 31), - datetime.date(2017, 9, 30), - datetime.date(2017, 10, 31), - datetime.date(2017, 11, 30), - datetime.date(2017, 12, 31), ] - input_commissioning_date = datetime.date(2017, 3, 14) - input_prior_list = [100] * 12 - input_post_list = [100, 90, 80, 70, 60, 50, 40, 30, 40, 50, 60, 70] +# def test_Saving(): +# input_proforma_date = [ +# datetime.date(2017, 1, 31), +# datetime.date(2017, 2, 28), +# datetime.date(2017, 3, 31), +# datetime.date(2017, 4, 30), +# datetime.date(2017, 5, 31), +# datetime.date(2017, 6, 30), +# datetime.date(2017, 7, 31), +# datetime.date(2017, 8, 31), +# datetime.date(2017, 9, 30), +# datetime.date(2017, 10, 31), +# datetime.date(2017, 11, 30), +# datetime.date(2017, 12, 31), ] +# input_commissioning_date = datetime.date(2017, 3, 14) +# input_prior_list = [100] * 12 +# input_post_list = [100, 90, 80, 70, 60, 50, 40, 30, 40, 50, 60, 70] - output_saving = [0, 0, 0, 30, 40, 50, 60, 70, 60, 50, 40, 30] - output_bill = [100, 100, 100, 70, 60, 50, 40, 30, 40, 50, 60, 70] - elec_saving = Saving(input_commissioning_date, input_proforma_date, input_prior_list, input_post_list) - result_saving = elec_saving.get_proforma_saving() - result_bill = elec_saving.get_proforma_bill() - assert output_saving == result_saving - assert output_bill == result_bill - assert elec_saving.get_first_year_saving() == 430 - assert elec_saving.get_annual_bill() == {2017: 770} - # print('1st yr saving =', elec_saving.get_first_year_saving()) - # print('annual_bill =', elec_saving.get_annual_bill()) +# output_saving = [0, 0, 0, 30, 40, 50, 60, 70, 60, 50, 40, 30] +# output_bill = [100, 100, 100, 70, 60, 50, 40, 30, 40, 50, 60, 70] +# elec_saving = Saving(input_commissioning_date, input_proforma_date, input_prior_list, input_post_list) +# result_saving = elec_saving.get_proforma_saving() +# result_bill = elec_saving.get_proforma_bill() +# assert output_saving == result_saving +# assert output_bill == result_bill +# assert elec_saving.get_first_year_saving() == 430 +# assert elec_saving.get_annual_bill() == {2017: 770} +# # print('1st yr saving =', elec_saving.get_first_year_saving()) +# # print('annual_bill =', elec_saving.get_annual_bill()) def test_Saving(): @@ -46,19 +46,22 @@ def test_Saving(): datetime.date(2017, 9, 30), datetime.date(2017, 10, 31), datetime.date(2017, 11, 30), - datetime.date(2017, 12, 31), ] + datetime.date(2017, 12, 31)] input_commissioning_date = datetime.date(2017, 3, 14) - input_prior_list = [100] * 12 - input_post_list = [100, 90, 80, 70, 60, 50, 40, 30, 40, 50, 60, 70] + input_prior_charge = [100] * 12 + input_post_charge = [100, 90, 80, 70, 60, 50, 40, 30, 40, 50, 60, 70] + input_prior_usage = [15] * 12 + input_post_usage = [10, 9, 8, 7, 6, 5, 4, 3, 4, 5, 6, 7] output_saving = [0, 0, 0, 30, 40, 50, 60, 70, 60, 50, 40, 30] - output_bill = [100, 100, 100, 70, 60, 50, 40, 30, 40, 50, 60, 70] - elec_saving = Saving(False, input_commissioning_date, input_proforma_date, input_prior_list, input_post_list) - result_saving = elec_saving.get_proforma_saving() - result_bill = elec_saving.get_proforma_bill() + output_charge = [100, 100, 100, 70, 60, 50, 40, 30, 40, 50, 60, 70] + + elec_saving = Saving(False, input_commissioning_date, input_proforma_date, input_prior_usage, input_post_usage, input_prior_charge, input_post_charge) + result_saving = elec_saving.get_proforma_saving_charge() + result_charge = elec_saving.get_proforma_charge() assert output_saving == result_saving - assert output_bill == result_bill - assert elec_saving.get_first_year_saving() == 430 - assert elec_saving.get_annual_bill() == {2017: 770} + assert output_charge == result_charge + assert elec_saving.get_first_year_saving_charge() == 430 + assert elec_saving.get_annual_proforma_charge() == {2017: 770} # print('1st yr saving =', elec_saving.get_first_year_saving()) # print('annual_bill =', elec_saving.get_annual_bill()) diff --git a/bpfin/tests/test_utilbills/test_bill_lib.py b/bpfin/tests/test_utilbills/test_bill_lib.py index c6f1410..d03d1d4 100644 --- a/bpfin/tests/test_utilbills/test_bill_lib.py +++ b/bpfin/tests/test_utilbills/test_bill_lib.py @@ -38,3 +38,11 @@ def test_cal_oil_price(): output_list = [2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0] result_list = bl.cal_oil_price(input_oilcharge, input_oiluse) assert output_list == result_list + + +def test_form_year_calendar(): + input_date_start = date(2012, 3, 4) + input_date_end = date(2017, 5, 9) + output_list = [2012, 2013, 2014, 2015, 2016, 2017] + result_list = bl.form_year_calendar(input_date_start, input_date_end) + assert output_list == result_list diff --git a/bpfin/utilbills/bill_lib.py b/bpfin/utilbills/bill_lib.py index 8df3fd0..57001fb 100644 --- a/bpfin/utilbills/bill_lib.py +++ b/bpfin/utilbills/bill_lib.py @@ -97,6 +97,28 @@ def form_date_calendar(date_start, date_end): return [bdstart, bdend] +def form_year_calendar(date_start, date_end): + """Return list of all calendar years. + + Args: + date_start (datetime): date xx/yy/abcd + date_end (datetime): date xx/yy/abcd + Returns: + list: all years, first year is year of date_start, last year is year of date_end + """ + year_list = [] + year = date_start.year + counter = 0 + while year <= date_end.year: + if counter > 9999: + return False + year_list.append(year) + year += 1 + counter += 1 + return year_list + + + def form_year_month(target_terms): """Return list of month,year of datetimes in a list. -- GitLab From dc2a31ca9b53d0de8c171492e0e2346aa90d73ee Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Tue, 2 May 2017 16:03:22 -0400 Subject: [PATCH 04/15] Add annual estimation saving calculation in Saving class. Add test files for mannual_input and non_mannual_input --- bpfin/financials/saving.py | 38 ++++++++++++----- bpfin/tests/test_financials/test_saving.py | 49 +++++++++++++++++++++- 2 files changed, 74 insertions(+), 13 deletions(-) diff --git a/bpfin/financials/saving.py b/bpfin/financials/saving.py index 4efd2e1..940faf5 100644 --- a/bpfin/financials/saving.py +++ b/bpfin/financials/saving.py @@ -1,6 +1,7 @@ import datetime from bpfin.utilbills.bill_lib import cal_last_day from bpfin.utilbills.bill_lib import annualizing_projection +from bpfin.utilbills.bill_lib import form_year_calendar class Saving(): @@ -57,7 +58,7 @@ class Saving(): first_year_saving_charge = 0 first_yr_counter = 0 for date, prior_usage, post_usage, prior_charge, post_charge in zip( - proforma_date, + self.proforma_date, prior_saving_usage, post_saving_usage, prior_saving_charge, @@ -86,15 +87,29 @@ class Saving(): self.annual_proforma_usage = annualizing_projection(self.proforma_date, self.proforma_charge) self.annual_proforma_charge = annualizing_projection(self.proforma_date, self.proforma_charge) - # def put_annual_proforma(self, annual_bill, percent_saving): - # """ - # Args: - # annual_bill (dictionary): dict of annual charge, {2014: 100, 2015: 120, ...} - # percent_saving (float): - # """ - # if self.is_manual_input is True: - # proforma_year = - + def put_annual_proforma(self, annual_charge, percent_saving): + """ + Args: + annual_charge (dictionary): dict of annual prior saving charge, {2014: 100, 2015: 120, ...}, with future estimated + percent_saving (float): percent of saving, 0.030 == 3.0% + """ + if self.is_manual_input is True: + annual_saving_dict = {} + annual_charge_dict = {} + proforma_year = form_year_calendar(self.proforma_date[0], self.proforma_date[-1]) + for year in proforma_year: + if year < self.commissioning_date.year: + annual_saving_dict[year] = 0 + annual_charge_dict[year] = annual_charge[year] + if year > self.commissioning_date.year: + annual_saving_dict[year] = annual_charge[year] * percent_saving + annual_charge_dict[year] = annual_charge[year] * (1 - percent_saving) + if year == self.commissioning_date.year: + effective_saving = (12 - self.commissioning_date.month) / 12 * percent_saving # partial year saving + annual_saving_dict[year] = annual_charge[year] * effective_saving + annual_charge_dict[year] = annual_charge[year] * (1 - effective_saving) + self.first_year_saving_charge = annual_saving_dict[self.commissioning_date.year + 1] + self.annual_proforma_charge = annual_charge_dict # def put_monthly_proforma_reg ?? # do we do saving projection here? actually we can, and maybe we should @@ -145,9 +160,10 @@ class Saving_Overview(): total_first_year_saving (float): saving on charge for the first 12 month after commissioning total_saving_percent (float): percentage saving on charge for the first 12 month after commissioning """ + # input = bill_overview manual input lable, pass in none if manual input def __init__(self): self.saving_percent_usage = {'electricity': None, 'gas': None, 'oil': None, 'water': None} self.saving_percent_charge = {'electricity': None, 'gas': None, 'oil': None, 'water': None} self.total_first_year_saving = None self.total_saving_percent = None -# input = bill_overview manual input lable, pass in none if manual input + diff --git a/bpfin/tests/test_financials/test_saving.py b/bpfin/tests/test_financials/test_saving.py index 71f5a5b..21d6b72 100644 --- a/bpfin/tests/test_financials/test_saving.py +++ b/bpfin/tests/test_financials/test_saving.py @@ -33,7 +33,7 @@ from bpfin.financials.saving import Saving # # print('annual_bill =', elec_saving.get_annual_bill()) -def test_Saving(): +def test_Saving_put_monthly_proforma(): input_proforma_date = [ datetime.date(2017, 1, 31), datetime.date(2017, 2, 28), @@ -56,7 +56,8 @@ def test_Saving(): output_saving = [0, 0, 0, 30, 40, 50, 60, 70, 60, 50, 40, 30] output_charge = [100, 100, 100, 70, 60, 50, 40, 30, 40, 50, 60, 70] - elec_saving = Saving(False, input_commissioning_date, input_proforma_date, input_prior_usage, input_post_usage, input_prior_charge, input_post_charge) + elec_saving = Saving(False, input_commissioning_date, input_proforma_date) + elec_saving.put_monthly_proforma(input_prior_usage, input_post_usage, input_prior_charge, input_post_charge) result_saving = elec_saving.get_proforma_saving_charge() result_charge = elec_saving.get_proforma_charge() assert output_saving == result_saving @@ -65,3 +66,47 @@ def test_Saving(): assert elec_saving.get_annual_proforma_charge() == {2017: 770} # print('1st yr saving =', elec_saving.get_first_year_saving()) # print('annual_bill =', elec_saving.get_annual_bill()) + + +def test_Saving_put_annual_proforma(): + input_proforma_date = [ + datetime.date(2017, 1, 31), + datetime.date(2017, 2, 28), + datetime.date(2017, 3, 31), + datetime.date(2017, 4, 30), + datetime.date(2017, 5, 31), + datetime.date(2017, 6, 30), + datetime.date(2017, 7, 31), + datetime.date(2017, 8, 31), + datetime.date(2017, 9, 30), + datetime.date(2017, 10, 31), + datetime.date(2017, 11, 30), + datetime.date(2017, 12, 31), + datetime.date(2018, 1, 31), + datetime.date(2018, 2, 28), + datetime.date(2018, 3, 31), + datetime.date(2018, 4, 30), + datetime.date(2018, 5, 31), + datetime.date(2018, 6, 30), + datetime.date(2018, 7, 31), + datetime.date(2018, 8, 31), + datetime.date(2018, 9, 30), + datetime.date(2018, 10, 31), + datetime.date(2018, 11, 30), + datetime.date(2018, 12, 31)] + input_commissioning_date = datetime.date(2017, 3, 14) + input_annual_charge = {2017: 100, 2018: 100} + input_percent_saving = 0.20 + + output_first_year_saving_charge = 20 + output_annual_proforma_charge = {2017: 85, 2018: 80} + + elec_saving = Saving(True, input_commissioning_date, input_proforma_date) + elec_saving.put_annual_proforma(input_annual_charge, input_percent_saving) + + result_first_year_saving_charge = elec_saving.get_first_year_saving_charge() + result_annual_proforma_charge = elec_saving.get_annual_proforma_charge() + assert result_first_year_saving_charge == output_first_year_saving_charge + assert result_annual_proforma_charge == output_annual_proforma_charge + # print('1st yr saving =', elec_saving.get_first_year_saving()) + # print('annual_bill =', elec_saving.get_annual_bill()) -- GitLab From abfd56a22b43c2789176e08dfc3bdaa26840928b Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Tue, 2 May 2017 16:59:28 -0400 Subject: [PATCH 05/15] Update test files for Saving. Clean description. --- bpfin/financials/saving.py | 62 ++++++++++++++++------ bpfin/tests/test_financials/test_saving.py | 45 +++------------- 2 files changed, 54 insertions(+), 53 deletions(-) diff --git a/bpfin/financials/saving.py b/bpfin/financials/saving.py index 940faf5..77df25d 100644 --- a/bpfin/financials/saving.py +++ b/bpfin/financials/saving.py @@ -11,29 +11,35 @@ class Saving(): is_manual_input (boolean): lable indicating is bill input by scraper or manual. Yes == manual input commissioning_date (date): the date that construction work finished, saving starts at NEXT month proforma_date (list): list of dates, months of pro-forma time period - prior_saving_list (list): list of float, usage or charge without (prior to) savings - post_saving_list (list): list of float, usage or charge with (post to) savings - proforma_bill (list): monthly usage or charge, for pro-forma period - Data before commissioning date == historical - Data after commissioning date == post saving data - proforma_saving (list): monthly savings on usage or charge, for pro-forma period + proforma_usage (list) : list of monthly usage, for pro-forma period Data before commissioning date == historical Data after commissioning date == post saving data - first_year_saving (float): first year saving, usage or charge - annual_proforma_bill {dictionary}: annual charge + proforma_charge (list) : list of monthly charge, for pro-forma period + Data before commissioning date == historical + Data after commissioning date == post saving data + proforma_saving_usage (list) : monthly savings on usage, for pro-forma period + Data before commissioning date == historical + Data after commissioning date == post saving data + proforma_saving_charge (list) : monthly savings on usage, for pro-forma period + Data before commissioning date == historical + Data after commissioning date == post saving data + first_year_saving_usage (float) : first 12 months saving on usage. + first_year_saving_charge (float) : first 12 months saving on charge. If data is annual, saving is on NEXT year + annual_proforma_usage (dictionary) : key is year, value is float, annual usage + annual_proforma_charge (dictionary) : key is year, value is float, annual charge + overall_saving (float): percentage saving on first year charge. 0.2 == 20% """ def __init__(self, is_manual_input, commissioning_date, proforma_date): """ - Initiate Saving object - + Initiate Saving object. + Args: + is_manual_input (boolean): lable indicating is bill input by scraper or manual. Yes == manual input + commissioning_date (date): the date that construction work finished, saving starts at NEXT month + proforma_date (list): list of dates, months of pro-forma time period """ self.is_manual_input = is_manual_input self.commissioning_date = commissioning_date self.proforma_date = proforma_date - # self.prior_saving_usage = None - # self.post_saving_usage = None - # self.prior_saving_charge = None - # self.post_saving_charge = None self.proforma_usage = None self.proforma_charge = None self.proforma_saving_usage = None @@ -42,8 +48,19 @@ class Saving(): self.first_year_saving_usage = None self.annual_proforma_usage = None self.annual_proforma_charge = None + self.overall_saving = 0 def put_monthly_proforma(self, prior_saving_usage, post_saving_usage, prior_saving_charge, post_saving_charge): + """ + Put monthly prior_saving and post_saving, generate: monthly usage and charge for pro-forma purpose. + Also generate first year savings, and annual usage and annual charge + + Args: + prior_saving_usage (list): list of float, usage without (prior to) savings + post_saving_usage (list): list of float, usage with (post to) savings + prior_saving_charge (list): list of float, charge without (prior to) savings + post_saving_charge (list): list of float, charge with (post to) savings + """ if self.is_manual_input is False: saving_start_date = datetime.date( self.commissioning_date.year, @@ -57,6 +74,7 @@ class Saving(): first_year_saving_usage = 0 first_year_saving_charge = 0 first_yr_counter = 0 + first_year_prior_charge = 0 for date, prior_usage, post_usage, prior_charge, post_charge in zip( self.proforma_date, prior_saving_usage, @@ -71,6 +89,7 @@ class Saving(): if first_yr_counter <= 12: first_year_saving_usage += prior_usage - post_usage first_year_saving_charge += prior_charge - post_charge + first_year_prior_charge += prior_charge first_yr_counter += 1 else: saving_usage_dict[date] = 0 @@ -86,11 +105,14 @@ class Saving(): self.first_year_saving_charge = first_year_saving_charge self.annual_proforma_usage = annualizing_projection(self.proforma_date, self.proforma_charge) self.annual_proforma_charge = annualizing_projection(self.proforma_date, self.proforma_charge) + self.overall_saving = first_year_saving_charge / first_year_prior_charge def put_annual_proforma(self, annual_charge, percent_saving): """ + Put annual prior_saving charge, calculate saving on charge and overall percentage saving + Args: - annual_charge (dictionary): dict of annual prior saving charge, {2014: 100, 2015: 120, ...}, with future estimated + annual_charge (dictionary): dict of annual prior saving charge, {2014: 100, ...}, with future estimated percent_saving (float): percent of saving, 0.030 == 3.0% """ if self.is_manual_input is True: @@ -110,6 +132,8 @@ class Saving(): annual_charge_dict[year] = annual_charge[year] * (1 - effective_saving) self.first_year_saving_charge = annual_saving_dict[self.commissioning_date.year + 1] self.annual_proforma_charge = annual_charge_dict + self.overall_saving = annual_saving_dict[self.commissioning_date.year + 1] / annual_charge[ + self.commissioning_date.year + 1] # def put_monthly_proforma_reg ?? # do we do saving projection here? actually we can, and maybe we should @@ -131,6 +155,14 @@ class Saving(): """ return self.proforma_saving_charge + def get_overall_saving(self): + """ + Get percentage saving on charge + Return: + float: overall percentage saving on charge + """ + return self.overall_saving + def get_first_year_saving_charge(self): """ Get first year saving diff --git a/bpfin/tests/test_financials/test_saving.py b/bpfin/tests/test_financials/test_saving.py index 21d6b72..feddb6c 100644 --- a/bpfin/tests/test_financials/test_saving.py +++ b/bpfin/tests/test_financials/test_saving.py @@ -2,37 +2,6 @@ import datetime from bpfin.financials.saving import Saving -# def test_Saving(): -# input_proforma_date = [ -# datetime.date(2017, 1, 31), -# datetime.date(2017, 2, 28), -# datetime.date(2017, 3, 31), -# datetime.date(2017, 4, 30), -# datetime.date(2017, 5, 31), -# datetime.date(2017, 6, 30), -# datetime.date(2017, 7, 31), -# datetime.date(2017, 8, 31), -# datetime.date(2017, 9, 30), -# datetime.date(2017, 10, 31), -# datetime.date(2017, 11, 30), -# datetime.date(2017, 12, 31), ] -# input_commissioning_date = datetime.date(2017, 3, 14) -# input_prior_list = [100] * 12 -# input_post_list = [100, 90, 80, 70, 60, 50, 40, 30, 40, 50, 60, 70] - -# output_saving = [0, 0, 0, 30, 40, 50, 60, 70, 60, 50, 40, 30] -# output_bill = [100, 100, 100, 70, 60, 50, 40, 30, 40, 50, 60, 70] -# elec_saving = Saving(input_commissioning_date, input_proforma_date, input_prior_list, input_post_list) -# result_saving = elec_saving.get_proforma_saving() -# result_bill = elec_saving.get_proforma_bill() -# assert output_saving == result_saving -# assert output_bill == result_bill -# assert elec_saving.get_first_year_saving() == 430 -# assert elec_saving.get_annual_bill() == {2017: 770} -# # print('1st yr saving =', elec_saving.get_first_year_saving()) -# # print('annual_bill =', elec_saving.get_annual_bill()) - - def test_Saving_put_monthly_proforma(): input_proforma_date = [ datetime.date(2017, 1, 31), @@ -52,20 +21,20 @@ def test_Saving_put_monthly_proforma(): input_post_charge = [100, 90, 80, 70, 60, 50, 40, 30, 40, 50, 60, 70] input_prior_usage = [15] * 12 input_post_usage = [10, 9, 8, 7, 6, 5, 4, 3, 4, 5, 6, 7] - output_saving = [0, 0, 0, 30, 40, 50, 60, 70, 60, 50, 40, 30] output_charge = [100, 100, 100, 70, 60, 50, 40, 30, 40, 50, 60, 70] + output_overall_saving = 0.4777777777777778 elec_saving = Saving(False, input_commissioning_date, input_proforma_date) elec_saving.put_monthly_proforma(input_prior_usage, input_post_usage, input_prior_charge, input_post_charge) result_saving = elec_saving.get_proforma_saving_charge() result_charge = elec_saving.get_proforma_charge() + assert output_saving == result_saving assert output_charge == result_charge assert elec_saving.get_first_year_saving_charge() == 430 assert elec_saving.get_annual_proforma_charge() == {2017: 770} - # print('1st yr saving =', elec_saving.get_first_year_saving()) - # print('annual_bill =', elec_saving.get_annual_bill()) + assert elec_saving.get_overall_saving() == output_overall_saving def test_Saving_put_annual_proforma(): @@ -97,16 +66,16 @@ def test_Saving_put_annual_proforma(): input_commissioning_date = datetime.date(2017, 3, 14) input_annual_charge = {2017: 100, 2018: 100} input_percent_saving = 0.20 - output_first_year_saving_charge = 20 output_annual_proforma_charge = {2017: 85, 2018: 80} + output_overall_saving = 0.20 elec_saving = Saving(True, input_commissioning_date, input_proforma_date) elec_saving.put_annual_proforma(input_annual_charge, input_percent_saving) - result_first_year_saving_charge = elec_saving.get_first_year_saving_charge() result_annual_proforma_charge = elec_saving.get_annual_proforma_charge() + result_overall_saving = elec_saving.get_overall_saving() + assert result_first_year_saving_charge == output_first_year_saving_charge assert result_annual_proforma_charge == output_annual_proforma_charge - # print('1st yr saving =', elec_saving.get_first_year_saving()) - # print('annual_bill =', elec_saving.get_annual_bill()) + assert result_overall_saving == output_overall_saving -- GitLab From c3ba0a45eed5773244eb1efa6afbeca216ba20dc Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Tue, 2 May 2017 18:55:41 -0400 Subject: [PATCH 06/15] Save temp work on Saving --- bpfin/financials/saving.py | 62 +++++++++++++++++++++++++++-- bpfin/tests/testdata/sample_data.py | 30 ++++++++++++++ 2 files changed, 88 insertions(+), 4 deletions(-) diff --git a/bpfin/financials/saving.py b/bpfin/financials/saving.py index 77df25d..e5e9bf9 100644 --- a/bpfin/financials/saving.py +++ b/bpfin/financials/saving.py @@ -2,6 +2,8 @@ import datetime from bpfin.utilbills.bill_lib import cal_last_day from bpfin.utilbills.bill_lib import annualizing_projection from bpfin.utilbills.bill_lib import form_year_calendar +from bpfin.utilbills.bill_lib import form_bill_calendar +from bpfin.tests.testdata import sample_data as db class Saving(): @@ -191,11 +193,63 @@ class Saving_Overview(): saving_percent_charge (dictionary): key is utility type, value is float {'electricity': float} total_first_year_saving (float): saving on charge for the first 12 month after commissioning total_saving_percent (float): percentage saving on charge for the first 12 month after commissioning + manual_input_dict(dictionary): key is utility type, value is boolean. True == mannual_input """ # input = bill_overview manual input lable, pass in none if manual input - def __init__(self): + def __init__(self, bill_overview): + """ + Initiate Saving_Overview. + Put values on manual_input_dict. + + Args: + bill_overview (dictionary): bill_overview from UI, with blank cells, for 4 utility_types + + Description: + bill_overview (dictionary): dict of a list, + list[0] = dict of annual bill, allow some year missing, for 4 utility_types + list[1] = boolean value, False == from manual input, True == from scraper + """ self.saving_percent_usage = {'electricity': None, 'gas': None, 'oil': None, 'water': None} self.saving_percent_charge = {'electricity': None, 'gas': None, 'oil': None, 'water': None} - self.total_first_year_saving = None - self.total_saving_percent = None - + self.total_first_year_saving = 0 # dollar + self.total_saving_percent = 0 + self.manual_input_dict = { + 'electricity': not bill_overview['electricity'][1], + 'gas': not bill_overview['gas'][1], + 'oil': not bill_overview['oil'][1], + 'water': not bill_overview['water'][1], + } + + def put_projection(self, annual_bill_table, month_saving_overview, analysis_date, commissioning_date, saving_dict): + """ + saving_dict + """ + utility_type_list = ['electricity', 'gas', 'oil', 'water'] + for utility in utility_type_list: + is_manual_input = self.manual_input_dict[utility] + proforma_date = form_bill_calendar(analysis_date['proforma_start'], analysis_date['proforma_duration']) + utility_saving = Saving(is_manual_input, commissioning_date, proforma_date) + # print(utility_saving.is_manual_input) + if utility_saving.is_manual_input is True: + utility_saving.put_annual_proforma(annual_bill_table[utility], saving_dict[utility]) + if utility_saving.is_manual_input is False: + utility_saving.put_monthly_proforma( + month_saving_overview[utility]['prior_usage'], + month_saving_overview[utility]['post_usage'], + month_saving_overview[utility]['prior_charge'], + month_saving_overview[utility]['post_charge'] + ) + print(utility_saving.get_first_year_saving_charge()) + + +# month_saving_overview = { +# 'electricity': { +# 'prior_usage': prior_proj_rough_usage, +# 'post_usage': post_proj_rough_usage, +# 'prior_charge': prior_proj_rough_charge, +# 'post_charge': post_proj_rough_charge}, + + +so = Saving_Overview(db.bill_overview) +so.put_projection(db.bill_overview_organized, db.month_saving_overview, db.analysis_date, datetime.date(2017, 3, 14), db.saving_dict) +# print(so.manual_input_dict) diff --git a/bpfin/tests/testdata/sample_data.py b/bpfin/tests/testdata/sample_data.py index 02cdd8f..c4cf415 100644 --- a/bpfin/tests/testdata/sample_data.py +++ b/bpfin/tests/testdata/sample_data.py @@ -1523,6 +1523,36 @@ post_bill_rough = { 'charge': post_proj_rough_charge, 'price': prior_proj_rough_price} +month_saving_overview = { + 'electricity': { + 'prior_usage': prior_proj_rough_usage, + 'post_usage': post_proj_rough_usage, + 'prior_charge': prior_proj_rough_charge, + 'post_charge': post_proj_rough_charge}, + 'gas': { + 'prior_usage': None, + 'post_usage': None, + 'prior_charge': None, + 'post_charge': None}, + 'oil': { + 'prior_usage': None, + 'post_usage': None, + 'prior_charge': None, + 'post_charge': None}, + 'water': { + 'prior_usage': None, + 'post_usage': None, + 'prior_charge': None, + 'post_charge': None} +} + +saving_dict = { + 'electricity': 0.25, + 'gas': 0.10, + 'oil': 0.80, + 'water': 0.0 +} + # global variables - # inflation coefficient dictionary. this is NOT inflation rate -- GitLab From 9a3612b852318b1371ef3e67ba50e7e6b1ef9dd3 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Tue, 2 May 2017 23:27:45 -0400 Subject: [PATCH 07/15] Create put_projection for Saving_Overview --- bpfin/financials/saving.py | 55 +++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/bpfin/financials/saving.py b/bpfin/financials/saving.py index e5e9bf9..fa76a4d 100644 --- a/bpfin/financials/saving.py +++ b/bpfin/financials/saving.py @@ -29,7 +29,8 @@ class Saving(): first_year_saving_charge (float) : first 12 months saving on charge. If data is annual, saving is on NEXT year annual_proforma_usage (dictionary) : key is year, value is float, annual usage annual_proforma_charge (dictionary) : key is year, value is float, annual charge - overall_saving (float): percentage saving on first year charge. 0.2 == 20% + first_year_prior_charge (float): first 12 months prior_saving charge. If data is annual, charge is for NEXT year + percent_saving (float): percentage saving on first year charge. 0.2 == 20% """ def __init__(self, is_manual_input, commissioning_date, proforma_date): """ @@ -50,7 +51,8 @@ class Saving(): self.first_year_saving_usage = None self.annual_proforma_usage = None self.annual_proforma_charge = None - self.overall_saving = 0 + self.first_year_prior_charge = None + self.percent_saving = 0 def put_monthly_proforma(self, prior_saving_usage, post_saving_usage, prior_saving_charge, post_saving_charge): """ @@ -107,7 +109,8 @@ class Saving(): self.first_year_saving_charge = first_year_saving_charge self.annual_proforma_usage = annualizing_projection(self.proforma_date, self.proforma_charge) self.annual_proforma_charge = annualizing_projection(self.proforma_date, self.proforma_charge) - self.overall_saving = first_year_saving_charge / first_year_prior_charge + self.first_year_prior_charge = first_year_prior_charge + self.percent_saving = first_year_saving_charge / first_year_prior_charge def put_annual_proforma(self, annual_charge, percent_saving): """ @@ -134,8 +137,12 @@ class Saving(): annual_charge_dict[year] = annual_charge[year] * (1 - effective_saving) self.first_year_saving_charge = annual_saving_dict[self.commissioning_date.year + 1] self.annual_proforma_charge = annual_charge_dict - self.overall_saving = annual_saving_dict[self.commissioning_date.year + 1] / annual_charge[ - self.commissioning_date.year + 1] + self.first_year_prior_charge = annual_charge[self.commissioning_date.year + 1] + if annual_charge[self.commissioning_date.year + 1] == 0: + self.percent_saving = 0 + else: + self.percent_saving = annual_saving_dict[self.commissioning_date.year + 1] / annual_charge[ + self.commissioning_date.year + 1] # def put_monthly_proforma_reg ?? # do we do saving projection here? actually we can, and maybe we should @@ -157,13 +164,13 @@ class Saving(): """ return self.proforma_saving_charge - def get_overall_saving(self): + def get_percent_saving(self): """ Get percentage saving on charge Return: float: overall percentage saving on charge """ - return self.overall_saving + return self.percent_saving def get_first_year_saving_charge(self): """ @@ -173,6 +180,14 @@ class Saving(): """ return self.first_year_saving_charge + def get_first_year_prior_charge(self): + """ + Get prior charge for first year after commissioning + Return: + float: prior charge for first year after commissioning + """ + return self.first_year_prior_charge + def get_annual_proforma_charge(self): """ Calculate and return annual pro-forma charge @@ -209,7 +224,6 @@ class Saving_Overview(): list[0] = dict of annual bill, allow some year missing, for 4 utility_types list[1] = boolean value, False == from manual input, True == from scraper """ - self.saving_percent_usage = {'electricity': None, 'gas': None, 'oil': None, 'water': None} self.saving_percent_charge = {'electricity': None, 'gas': None, 'oil': None, 'water': None} self.total_first_year_saving = 0 # dollar self.total_saving_percent = 0 @@ -217,19 +231,20 @@ class Saving_Overview(): 'electricity': not bill_overview['electricity'][1], 'gas': not bill_overview['gas'][1], 'oil': not bill_overview['oil'][1], - 'water': not bill_overview['water'][1], - } + 'water': not bill_overview['water'][1]} def put_projection(self, annual_bill_table, month_saving_overview, analysis_date, commissioning_date, saving_dict): """ saving_dict """ utility_type_list = ['electricity', 'gas', 'oil', 'water'] + total_first_year_saving = 0 + total_first_year_prior_charge = 0 for utility in utility_type_list: is_manual_input = self.manual_input_dict[utility] - proforma_date = form_bill_calendar(analysis_date['proforma_start'], analysis_date['proforma_duration']) + proforma_date = form_bill_calendar(analysis_date['proforma_start'], analysis_date['proforma_duration'])[1] utility_saving = Saving(is_manual_input, commissioning_date, proforma_date) - # print(utility_saving.is_manual_input) + if utility_saving.is_manual_input is True: utility_saving.put_annual_proforma(annual_bill_table[utility], saving_dict[utility]) if utility_saving.is_manual_input is False: @@ -239,8 +254,14 @@ class Saving_Overview(): month_saving_overview[utility]['prior_charge'], month_saving_overview[utility]['post_charge'] ) - print(utility_saving.get_first_year_saving_charge()) - + total_first_year_saving += utility_saving.get_first_year_saving_charge() + total_first_year_prior_charge += utility_saving.get_first_year_prior_charge() + self.saving_percent_charge[utility] = utility_saving.get_percent_saving() + self.total_first_year_saving = total_first_year_saving + if total_first_year_prior_charge != 0: + self.total_saving_percent = total_first_year_saving / total_first_year_prior_charge + else: + self.total_saving_percent = 0 # month_saving_overview = { # 'electricity': { @@ -249,7 +270,11 @@ class Saving_Overview(): # 'prior_charge': prior_proj_rough_charge, # 'post_charge': post_proj_rough_charge}, +# def form_analysis_calendar(analysis_date): +# return form_bill_calendar(analysis_date['proforma_start'], analysis_date['proforma_duration']) + so = Saving_Overview(db.bill_overview) so.put_projection(db.bill_overview_organized, db.month_saving_overview, db.analysis_date, datetime.date(2017, 3, 14), db.saving_dict) -# print(so.manual_input_dict) +print(so.saving_percent_charge) +print(so.total_first_year_saving) -- GitLab From 74c05fae4fa65c560b47b5f8d0c98df5e2617733 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Wed, 3 May 2017 00:06:30 -0400 Subject: [PATCH 08/15] Add comment and structural draft --- bpfin/financials/saving.py | 82 ++++++++++++++++++++++++++++---------- 1 file changed, 61 insertions(+), 21 deletions(-) diff --git a/bpfin/financials/saving.py b/bpfin/financials/saving.py index fa76a4d..dc5ca2f 100644 --- a/bpfin/financials/saving.py +++ b/bpfin/financials/saving.py @@ -135,14 +135,13 @@ class Saving(): effective_saving = (12 - self.commissioning_date.month) / 12 * percent_saving # partial year saving annual_saving_dict[year] = annual_charge[year] * effective_saving annual_charge_dict[year] = annual_charge[year] * (1 - effective_saving) - self.first_year_saving_charge = annual_saving_dict[self.commissioning_date.year + 1] + + first_year = self.commissioning_date.year + 1 + self.first_year_saving_charge = annual_saving_dict[first_year] self.annual_proforma_charge = annual_charge_dict - self.first_year_prior_charge = annual_charge[self.commissioning_date.year + 1] - if annual_charge[self.commissioning_date.year + 1] == 0: - self.percent_saving = 0 - else: - self.percent_saving = annual_saving_dict[self.commissioning_date.year + 1] / annual_charge[ - self.commissioning_date.year + 1] + self.first_year_prior_charge = annual_charge[first_year] + self.percent_saving = ( + annual_saving_dict[first_year] / annual_charge[first_year] if annual_charge[first_year] != 0 else 0) # def put_monthly_proforma_reg ?? # do we do saving projection here? actually we can, and maybe we should @@ -209,16 +208,27 @@ class Saving_Overview(): total_first_year_saving (float): saving on charge for the first 12 month after commissioning total_saving_percent (float): percentage saving on charge for the first 12 month after commissioning manual_input_dict(dictionary): key is utility type, value is boolean. True == mannual_input + utility_saving_dict (dictionary): !!! """ - # input = bill_overview manual input lable, pass in none if manual input - def __init__(self, bill_overview): - """ + + # saving_input == saving_dict, or == eng_input + def __init__( + self, + bill_overview, + annual_bill_table, + month_saving_overview, + analysis_date, + commissioning_date, + saving_dict): + """!!!!!!! Initiate Saving_Overview. - Put values on manual_input_dict. + Take in manual_input_dict, annual and monthly bills, commissioning_date and percentage savings + Generate saving Args: bill_overview (dictionary): bill_overview from UI, with blank cells, for 4 utility_types + Description: bill_overview (dictionary): dict of a list, list[0] = dict of annual bill, allow some year missing, for 4 utility_types @@ -232,12 +242,10 @@ class Saving_Overview(): 'gas': not bill_overview['gas'][1], 'oil': not bill_overview['oil'][1], 'water': not bill_overview['water'][1]} + self.utility_saving_dict = {'electricity': None, 'gas': None, 'oil': None, 'water': None} - def put_projection(self, annual_bill_table, month_saving_overview, analysis_date, commissioning_date, saving_dict): - """ - saving_dict - """ utility_type_list = ['electricity', 'gas', 'oil', 'water'] + total_first_year_saving = 0 total_first_year_prior_charge = 0 for utility in utility_type_list: @@ -257,11 +265,34 @@ class Saving_Overview(): total_first_year_saving += utility_saving.get_first_year_saving_charge() total_first_year_prior_charge += utility_saving.get_first_year_prior_charge() self.saving_percent_charge[utility] = utility_saving.get_percent_saving() + self.utility_saving_dict[utility] = utility_saving + self.total_first_year_saving = total_first_year_saving - if total_first_year_prior_charge != 0: - self.total_saving_percent = total_first_year_saving / total_first_year_prior_charge - else: - self.total_saving_percent = 0 + self.total_saving_percent = ( + total_first_year_saving / total_first_year_prior_charge if total_first_year_prior_charge != 0 else 0) + + def get_utility_saving_dict(self): + """ + """ + pass + + def get_total_first_year_saving(self): + """ + This is used for: loan allocation, simple_payback calculation + """ + return self.total_first_year_saving + + def get_simple_payback(self, cost): + """ + for UI showcase + """ + return float(cost / self.total_first_year_saving if self.total_first_year_saving != 0 else 0) + + def get_total_saving_percent(self): + """ + for UI showcase + """ + return self.total_saving_percent # month_saving_overview = { # 'electricity': { @@ -274,7 +305,16 @@ class Saving_Overview(): # return form_bill_calendar(analysis_date['proforma_start'], analysis_date['proforma_duration']) -so = Saving_Overview(db.bill_overview) -so.put_projection(db.bill_overview_organized, db.month_saving_overview, db.analysis_date, datetime.date(2017, 3, 14), db.saving_dict) +so = Saving_Overview(db.bill_overview, db.bill_overview_organized, db.month_saving_overview, db.analysis_date, datetime.date(2017, 3, 14), db.saving_dict) +# so.put_projection(db.bill_overview_organized, db.month_saving_overview, db.analysis_date, datetime.date(2017, 3, 14), db.saving_dict) print(so.saving_percent_charge) print(so.total_first_year_saving) + + +#***** draft*** +rough vs reg -> prior only +all prelim analysis == percent saving +full analysis == reg and/or persent + +1. judge manul_input == annual percent +2. judge prelim vs full == generate post_month_bill -- GitLab From 59a277036ebea53965437bd9bb8326885a1b9459 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Wed, 3 May 2017 12:09:00 -0400 Subject: [PATCH 09/15] Restructure Saving_Table mindset --- bpfin/financials/saving.py | 78 +++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/bpfin/financials/saving.py b/bpfin/financials/saving.py index dc5ca2f..895f0bf 100644 --- a/bpfin/financials/saving.py +++ b/bpfin/financials/saving.py @@ -8,29 +8,29 @@ from bpfin.tests.testdata import sample_data as db class Saving(): """ - Calculate savings and project bills with commissioning date considered. + Calculate savings and project bills with commissioning date considered. For one utility type Attributes: - is_manual_input (boolean): lable indicating is bill input by scraper or manual. Yes == manual input - commissioning_date (date): the date that construction work finished, saving starts at NEXT month - proforma_date (list): list of dates, months of pro-forma time period - proforma_usage (list) : list of monthly usage, for pro-forma period - Data before commissioning date == historical - Data after commissioning date == post saving data - proforma_charge (list) : list of monthly charge, for pro-forma period - Data before commissioning date == historical - Data after commissioning date == post saving data - proforma_saving_usage (list) : monthly savings on usage, for pro-forma period - Data before commissioning date == historical - Data after commissioning date == post saving data - proforma_saving_charge (list) : monthly savings on usage, for pro-forma period + is_manual_input (boolean): lable indicating is bill input by scraper or manual. Yes == manual input + commissioning_date (date): the date that construction work finished, saving starts at NEXT month + proforma_date (list): list of dates, months of pro-forma time period + proforma_usage (list) : list of monthly usage, for pro-forma period + Data before commissioning date == historical + Data after commissioning date == post saving data + proforma_charge (list) : list of monthly charge, for pro-forma period + Data before commissioning date == historical + Data after commissioning date == post saving data + proforma_saving_usage (list) : monthly savings on usage, for pro-forma period Data before commissioning date == historical Data after commissioning date == post saving data - first_year_saving_usage (float) : first 12 months saving on usage. - first_year_saving_charge (float) : first 12 months saving on charge. If data is annual, saving is on NEXT year - annual_proforma_usage (dictionary) : key is year, value is float, annual usage - annual_proforma_charge (dictionary) : key is year, value is float, annual charge - first_year_prior_charge (float): first 12 months prior_saving charge. If data is annual, charge is for NEXT year - percent_saving (float): percentage saving on first year charge. 0.2 == 20% + proforma_saving_charge (list) : monthly savings on usage, for pro-forma period + Data before commissioning date == historical + Data after commissioning date == post saving data + first_year_saving_usage (float) : first 12 months saving on usage. + first_year_saving_charge (float) : first 12 months saving on charge. If data is annual, saving is on NEXT year + annual_proforma_usage (dictionary) : key is year, value is float, annual usage + annual_proforma_charge (dictionary) : key is year, value is float, annual charge + first_year_prior_charge (float): first 12 months prior_saving charge. If data is annual, charge is for NEXT year + percent_saving (float): percentage saving on first year charge. 0.2 == 20% """ def __init__(self, is_manual_input, commissioning_date, proforma_date): """ @@ -211,15 +211,12 @@ class Saving_Overview(): utility_saving_dict (dictionary): !!! """ - # saving_input == saving_dict, or == eng_input def __init__( self, bill_overview, annual_bill_table, - month_saving_overview, analysis_date, - commissioning_date, - saving_dict): + commissioning_date): """!!!!!!! Initiate Saving_Overview. Take in manual_input_dict, annual and monthly bills, commissioning_date and percentage savings @@ -243,19 +240,26 @@ class Saving_Overview(): 'oil': not bill_overview['oil'][1], 'water': not bill_overview['water'][1]} self.utility_saving_dict = {'electricity': None, 'gas': None, 'oil': None, 'water': None} + self.proforma_date = form_bill_calendar(analysis_date['proforma_start'], analysis_date['proforma_duration'])[1] + def put_prelim_saving(self, saving_dict, month_saving_overview): + # saving_input == saving_dict, or == eng_input + # if manual_input == True, which means we only have annual bill, we do percentage saving + # if month_saving == None, which means we do percentage saving calculation, use post_proj_percent to get post_usage, pose_charge...dict + # if month_saving != None, which means engienering analysis is available, we use regression method utility_type_list = ['electricity', 'gas', 'oil', 'water'] total_first_year_saving = 0 total_first_year_prior_charge = 0 for utility in utility_type_list: is_manual_input = self.manual_input_dict[utility] - proforma_date = form_bill_calendar(analysis_date['proforma_start'], analysis_date['proforma_duration'])[1] + utility_saving = Saving(is_manual_input, commissioning_date, proforma_date) if utility_saving.is_manual_input is True: utility_saving.put_annual_proforma(annual_bill_table[utility], saving_dict[utility]) if utility_saving.is_manual_input is False: + # !!!! generate post usage, post charge, and so utility_saving.put_monthly_proforma( month_saving_overview[utility]['prior_usage'], month_saving_overview[utility]['post_usage'], @@ -271,6 +275,10 @@ class Saving_Overview(): self.total_saving_percent = ( total_first_year_saving / total_first_year_prior_charge if total_first_year_prior_charge != 0 else 0) + def put_full_saving(self, saving_dict): + # saving_input == saving_dict, or == eng_input + pass + def get_utility_saving_dict(self): """ """ @@ -305,16 +313,18 @@ class Saving_Overview(): # return form_bill_calendar(analysis_date['proforma_start'], analysis_date['proforma_duration']) -so = Saving_Overview(db.bill_overview, db.bill_overview_organized, db.month_saving_overview, db.analysis_date, datetime.date(2017, 3, 14), db.saving_dict) -# so.put_projection(db.bill_overview_organized, db.month_saving_overview, db.analysis_date, datetime.date(2017, 3, 14), db.saving_dict) -print(so.saving_percent_charge) -print(so.total_first_year_saving) +so = Saving_Overview(db.bill_overview, db.bill_overview_organized, db.analysis_date, datetime.date(2017, 3, 14)) +# db.month_saving_overview, +# , db.saving_dict +# # so.put_projection(db.bill_overview_organized, db.month_saving_overview, db.analysis_date, datetime.date(2017, 3, 14), db.saving_dict) +# print(so.saving_percent_charge) +# print(so.total_first_year_saving) #***** draft*** -rough vs reg -> prior only -all prelim analysis == percent saving -full analysis == reg and/or persent +# rough vs reg -> prior only +# all prelim analysis == percent saving +# full analysis == reg and/or persent -1. judge manul_input == annual percent -2. judge prelim vs full == generate post_month_bill +# 1. judge manul_input == annual percent +# 2. judge prelim vs full == generate post_month_bill -- GitLab From 36ff15f403576423ac92d908f93a1ed91b442890 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Wed, 3 May 2017 15:10:36 -0400 Subject: [PATCH 10/15] Create put_saving for Saving_Table --- bpfin/financials/financial_lib.py | 20 +++++----- bpfin/financials/saving.py | 54 ++++++++++++++------------- bpfin/tests/testdata/sample_data.py | 58 ++++++++++++++++++----------- 3 files changed, 75 insertions(+), 57 deletions(-) diff --git a/bpfin/financials/financial_lib.py b/bpfin/financials/financial_lib.py index 787d4c1..3f8107d 100644 --- a/bpfin/financials/financial_lib.py +++ b/bpfin/financials/financial_lib.py @@ -182,9 +182,9 @@ class Income_Statement(): def convert_income_statement_class(income_statement_class): """ - Convert single year income statement objective into a dictionary format + Convert single year income statement object into a dictionary format Args: - income_statement_class (objective): single year income statement objective + income_statement_class (object): single year income statement object Return: income_statement_dict (dictionary) """ @@ -207,7 +207,7 @@ def convert_income_statement_class(income_statement_class): class Income_Statement_Next(): """ - Create single year income_statement objective, + Create single year income_statement object, with input of last year data, income statement characters, and projected annual bill """ def __init__(self, year, last_revenue, growth_rate_flag, characters, annual_bill_table): @@ -219,7 +219,7 @@ class Income_Statement_Next(): growth_rate_flag (float): indicating assumed growth rate, -2.0 == cagr, -1.0 == historical average characters (dictionary): 6 characters calculated from historical income statements annual_bill_table (dictionary): dictionary of dictionary of annual bills, for 4 utility_types - Final instance is a single year income_statement objective + Final instance is a single year income_statement object Description: characters = { @@ -261,8 +261,8 @@ class Income_Statement_Table(): """ Create a income statement table, containing multiple years, including historical and projected data Key Attributes are: - hist_table (list): list of single year income_statement objectives, containing historical data - table(list): list of single year income_statement objectives, containing historical and projected data + hist_table (list): list of single year income_statement objects, containing historical data + table(list): list of single year income_statement objects, containing historical and projected data """ def __init__(self, raw_income_input, annual_bill_table): """ @@ -275,8 +275,8 @@ class Income_Statement_Table(): cagr (float): compound annual growth rate other_utility_percent (float): percentage, (average other_utility / average revenue) non_utility_expense_percent (float): percentage, (average non_utility_expense_percent / average revenue) - hist_table (list): list of single year income_statement objectives, containing historical data - table(list): list of single year income_statement objectives, containing historical and projected data + hist_table (list): list of single year income_statement objects, containing historical data + table(list): list of single year income_statement objects, containing historical and projected data characters (dictionary): contains key characters determined from historical data. Is used to project Description: @@ -339,13 +339,13 @@ class Income_Statement_Table(): def project(self, growth_rate_flag, analysis_date, annual_bill_table): """ - Project future income statement. Append multiple single year income_statement objectives to self.table + Project future income statement. Append multiple single year income_statement objects to self.table Args: growth_rate_flag (float): indicating assumed growth rate, -2.0 == cagr, -1.0 == historical average analysis_date (dictionary): proforma's starting date and the years of proforma annual_bill_table (dictionary): dictionary of dictionary of annual bills, for 4 utility_types Return: - list: list of single year income_statement objectives, containing historical and projection + list: list of single year income_statement objects, containing historical and projection Note: project() overwrites existing projection data """ diff --git a/bpfin/financials/saving.py b/bpfin/financials/saving.py index 895f0bf..17f5a62 100644 --- a/bpfin/financials/saving.py +++ b/bpfin/financials/saving.py @@ -4,6 +4,7 @@ from bpfin.utilbills.bill_lib import annualizing_projection from bpfin.utilbills.bill_lib import form_year_calendar from bpfin.utilbills.bill_lib import form_bill_calendar from bpfin.tests.testdata import sample_data as db +from bpfin.utilbills.bill_post_proj_rough import bill_post_proj_rough class Saving(): @@ -214,7 +215,7 @@ class Saving_Overview(): def __init__( self, bill_overview, - annual_bill_table, + prior_annual_bill_table, analysis_date, commissioning_date): """!!!!!!! @@ -231,18 +232,20 @@ class Saving_Overview(): list[0] = dict of annual bill, allow some year missing, for 4 utility_types list[1] = boolean value, False == from manual input, True == from scraper """ - self.saving_percent_charge = {'electricity': None, 'gas': None, 'oil': None, 'water': None} - self.total_first_year_saving = 0 # dollar - self.total_saving_percent = 0 self.manual_input_dict = { 'electricity': not bill_overview['electricity'][1], 'gas': not bill_overview['gas'][1], 'oil': not bill_overview['oil'][1], 'water': not bill_overview['water'][1]} - self.utility_saving_dict = {'electricity': None, 'gas': None, 'oil': None, 'water': None} + self.prior_annual_bill_table = prior_annual_bill_table # bill_overview_organized, which is annual bill prior 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} # dict of Saving objects + self.saving_percent_charge = {'electricity': None, 'gas': None, 'oil': None, 'water': None} + self.total_first_year_saving = 0 # dollar + self.total_saving_percent = 0 # dollar percentage - def put_prelim_saving(self, saving_dict, month_saving_overview): + def put_saving(self, prior_month_bill, saving_dict, full_saving_dict): # saving_input == saving_dict, or == eng_input # if manual_input == True, which means we only have annual bill, we do percentage saving # if month_saving == None, which means we do percentage saving calculation, use post_proj_percent to get post_usage, pose_charge...dict @@ -254,18 +257,23 @@ class Saving_Overview(): for utility in utility_type_list: is_manual_input = self.manual_input_dict[utility] - utility_saving = Saving(is_manual_input, commissioning_date, proforma_date) + utility_saving = Saving(is_manual_input, self.commissioning_date, self.proforma_date) + + if utility_saving.is_manual_input is True: # bill is from manual input, monthly bill not available + utility_saving.put_annual_proforma(self.prior_annual_bill_table[utility], saving_dict[utility]) + + if utility_saving.is_manual_input is False: # bill is from scraper, monthly bill is available + if full_saving_dict[utility] is None: # engineering saving is not available, use percentage saving + post_month_bill = bill_post_proj_rough(prior_month_bill[utility], saving_dict[utility]) + # else: # engineering saving is available. Project monthly_bill with regression. not finished yet + # post_month_bill = bill_proj_reg(prior_utility, full_saving_dict[utility], HDD, CDD, occupancy) - if utility_saving.is_manual_input is True: - utility_saving.put_annual_proforma(annual_bill_table[utility], saving_dict[utility]) - if utility_saving.is_manual_input is False: - # !!!! generate post usage, post charge, and so utility_saving.put_monthly_proforma( - month_saving_overview[utility]['prior_usage'], - month_saving_overview[utility]['post_usage'], - month_saving_overview[utility]['prior_charge'], - month_saving_overview[utility]['post_charge'] - ) + prior_month_bill[utility]['usage'], + post_month_bill['usage'], + prior_month_bill[utility]['charge'], + post_month_bill['charge']) + total_first_year_saving += utility_saving.get_first_year_saving_charge() total_first_year_prior_charge += utility_saving.get_first_year_prior_charge() self.saving_percent_charge[utility] = utility_saving.get_percent_saving() @@ -275,10 +283,6 @@ class Saving_Overview(): self.total_saving_percent = ( total_first_year_saving / total_first_year_prior_charge if total_first_year_prior_charge != 0 else 0) - def put_full_saving(self, saving_dict): - # saving_input == saving_dict, or == eng_input - pass - def get_utility_saving_dict(self): """ """ @@ -315,13 +319,13 @@ class Saving_Overview(): so = Saving_Overview(db.bill_overview, db.bill_overview_organized, db.analysis_date, datetime.date(2017, 3, 14)) # db.month_saving_overview, -# , db.saving_dict -# # so.put_projection(db.bill_overview_organized, db.month_saving_overview, db.analysis_date, datetime.date(2017, 3, 14), db.saving_dict) -# print(so.saving_percent_charge) -# print(so.total_first_year_saving) +# , db.percent_saving_dict +so.put_saving(db.prior_month_bill, db.percent_saving_dict, db.full_saving_dict) +print(so.saving_percent_charge) +print(so.total_first_year_saving) -#***** draft*** +# ***** draft*** # rough vs reg -> prior only # all prelim analysis == percent saving # full analysis == reg and/or persent diff --git a/bpfin/tests/testdata/sample_data.py b/bpfin/tests/testdata/sample_data.py index c4cf415..12947de 100644 --- a/bpfin/tests/testdata/sample_data.py +++ b/bpfin/tests/testdata/sample_data.py @@ -1523,36 +1523,50 @@ post_bill_rough = { 'charge': post_proj_rough_charge, 'price': prior_proj_rough_price} -month_saving_overview = { - 'electricity': { - 'prior_usage': prior_proj_rough_usage, - 'post_usage': post_proj_rough_usage, - 'prior_charge': prior_proj_rough_charge, - 'post_charge': post_proj_rough_charge}, - 'gas': { - 'prior_usage': None, - 'post_usage': None, - 'prior_charge': None, - 'post_charge': None}, - 'oil': { - 'prior_usage': None, - 'post_usage': None, - 'prior_charge': None, - 'post_charge': None}, - 'water': { - 'prior_usage': None, - 'post_usage': None, - 'prior_charge': None, - 'post_charge': None} +# month_saving_overview = { +# 'electricity': { +# 'prior_usage': prior_proj_rough_usage, +# 'post_usage': post_proj_rough_usage, +# 'prior_charge': prior_proj_rough_charge, +# 'post_charge': post_proj_rough_charge}, +# 'gas': { +# 'prior_usage': None, +# 'post_usage': None, +# 'prior_charge': None, +# 'post_charge': None}, +# 'oil': { +# 'prior_usage': None, +# 'post_usage': None, +# 'prior_charge': None, +# 'post_charge': None}, +# 'water': { +# 'prior_usage': None, +# 'post_usage': None, +# 'prior_charge': None, +# 'post_charge': None} +# } + +prior_month_bill = { + 'electricity': prior_bill_rough, + 'gas': None, + 'oil': None, + 'water': None, } -saving_dict = { +percent_saving_dict = { 'electricity': 0.25, 'gas': 0.10, 'oil': 0.80, 'water': 0.0 } +full_saving_dict = { + 'electricity': None, # dict of engineering analysis, {'date_from': [], 'date_to': [], 'heating': [], 'cooling': [], 'other': []} + 'gas': None, + 'oil': None, + 'water': None +} + # global variables - # inflation coefficient dictionary. this is NOT inflation rate -- GitLab From cefeb6a8a351bc0b3610f9cb6c919f7691888288 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Wed, 3 May 2017 15:52:33 -0400 Subject: [PATCH 11/15] Stack --- bpfin/financials/saving.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/bpfin/financials/saving.py b/bpfin/financials/saving.py index 17f5a62..a52ccbb 100644 --- a/bpfin/financials/saving.py +++ b/bpfin/financials/saving.py @@ -144,10 +144,6 @@ class Saving(): self.percent_saving = ( annual_saving_dict[first_year] / annual_charge[first_year] if annual_charge[first_year] != 0 else 0) - # def put_monthly_proforma_reg ?? - # do we do saving projection here? actually we can, and maybe we should - # it is not developed in front end yet - def get_proforma_charge(self): """ Get proforma_charge -- GitLab From 51a6b41928cc92316ab33385c409f8f9e1882cb9 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Wed, 3 May 2017 16:48:26 -0400 Subject: [PATCH 12/15] Create comments for Saving and Saving_Table class --- bpfin/financials/saving.py | 93 +++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 42 deletions(-) diff --git a/bpfin/financials/saving.py b/bpfin/financials/saving.py index a52ccbb..0851973 100644 --- a/bpfin/financials/saving.py +++ b/bpfin/financials/saving.py @@ -1,4 +1,5 @@ import datetime +import copy from bpfin.utilbills.bill_lib import cal_last_day from bpfin.utilbills.bill_lib import annualizing_projection from bpfin.utilbills.bill_lib import form_year_calendar @@ -198,14 +199,20 @@ class Saving_Overview(): Generate saving schedule, annual usages and charges for 4 utility types Also calculate percentage saving on usages and charges. If rate plan applies, usage % saving can be different from charge % saving - Saving_Overview should be scenario based, aka it is an "attribute" of a scenario + Saving_Overview should be scenario based, it is an "attribute" of a scenario + Attributes: - saving_percent_usage (dictionary): key is utility type, value is float {'electricity': float} + manual_input_dict(dictionary): key is utility type, value is boolean. True == mannual_input + prior_annual_bill_table (dictionary): annual bill, for 4 utility_types + proforma_date (list): list of dates, months of pro-forma time period + commissioning_date (date): the date that construction work finished, saving starts at NEXT month + utility_saving_dict (dictionary): dict of Saving objects, for 4 utility types saving_percent_charge (dictionary): key is utility type, value is float {'electricity': float} - total_first_year_saving (float): saving on charge for the first 12 month after commissioning + 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 - manual_input_dict(dictionary): key is utility type, value is boolean. True == mannual_input - utility_saving_dict (dictionary): !!! + + Description: + prior_annual_bill_table = {'electricity': electricity_bill, 'oil': oil_bill, 'gas': gas_bill, 'water': water_bill} """ def __init__( @@ -214,14 +221,16 @@ class Saving_Overview(): prior_annual_bill_table, analysis_date, commissioning_date): - """!!!!!!! + """ Initiate Saving_Overview. Take in manual_input_dict, annual and monthly bills, commissioning_date and percentage savings - Generate saving + Generate Saving objects, pro-forma date period Args: bill_overview (dictionary): bill_overview from UI, with blank cells, for 4 utility_types - + prior_annual_bill_table (dictionary): annual bill, for 4 utility_types + analysis_date (dictionary): proforma's starting date and the years of proforma + commissioning_date (date): the date that construction work finished, saving starts at NEXT month Description: bill_overview (dictionary): dict of a list, @@ -233,19 +242,15 @@ class Saving_Overview(): 'gas': not bill_overview['gas'][1], 'oil': not bill_overview['oil'][1], 'water': not bill_overview['water'][1]} - self.prior_annual_bill_table = prior_annual_bill_table # bill_overview_organized, which is annual bill prior + 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} # dict of Saving objects + self.utility_saving_dict = {'electricity': None, 'gas': None, 'oil': None, 'water': None} self.saving_percent_charge = {'electricity': None, 'gas': None, 'oil': None, 'water': None} self.total_first_year_saving = 0 # dollar self.total_saving_percent = 0 # dollar percentage def put_saving(self, prior_month_bill, saving_dict, full_saving_dict): - # saving_input == saving_dict, or == eng_input - # if manual_input == True, which means we only have annual bill, we do percentage saving - # if month_saving == None, which means we do percentage saving calculation, use post_proj_percent to get post_usage, pose_charge...dict - # if month_saving != None, which means engienering analysis is available, we use regression method utility_type_list = ['electricity', 'gas', 'oil', 'water'] total_first_year_saving = 0 @@ -279,52 +284,56 @@ class Saving_Overview(): self.total_saving_percent = ( total_first_year_saving / total_first_year_prior_charge if total_first_year_prior_charge != 0 else 0) - def get_utility_saving_dict(self): - """ - """ - pass - def get_total_first_year_saving(self): """ + Get first year total dollar saving This is used for: loan allocation, simple_payback calculation + Retrun: + float: a dollar number """ return self.total_first_year_saving def get_simple_payback(self, cost): """ - for UI showcase + Get the simple payback for a given project cost. cost / first year dollar saving + Args: + cost (float): project cost, estimated or quoted + Return: + float: simple paback, in year """ return float(cost / self.total_first_year_saving if self.total_first_year_saving != 0 else 0) def get_total_saving_percent(self): """ - for UI showcase + Get the total saving percentage. First dollar saving / First year prior_saving charge + Return: + float: total dollar saving percentage """ return self.total_saving_percent -# month_saving_overview = { -# 'electricity': { -# 'prior_usage': prior_proj_rough_usage, -# 'post_usage': post_proj_rough_usage, -# 'prior_charge': prior_proj_rough_charge, -# 'post_charge': post_proj_rough_charge}, + def get_total_annual_saving_charge(self): + """ + """ + pass -# def form_analysis_calendar(analysis_date): -# return form_bill_calendar(analysis_date['proforma_start'], analysis_date['proforma_duration']) + def get_utility_annual_saving_charge(self, utility_type): + """ + Get the proforma annual saving on charge for a utility_type + Args: + utility_type: string. 'electricity', 'gas', 'oil', 'water' + Return: + dictionary: {year: saving on charge} + """ + prior_charge_dict = copy.deepcopy(self.prior_annual_bill_table[utility_type]) + post_charge_dict = copy.deepcopy(self.utility_saving_dict[utility_type].get_annual_proforma_charge()) + saving_dict = {} + for year in prior_charge_dict: + saving_dict[year] = prior_charge_dict[year] - post_charge_dict[year] + return saving_dict so = Saving_Overview(db.bill_overview, db.bill_overview_organized, db.analysis_date, datetime.date(2017, 3, 14)) -# db.month_saving_overview, -# , db.percent_saving_dict so.put_saving(db.prior_month_bill, db.percent_saving_dict, db.full_saving_dict) -print(so.saving_percent_charge) -print(so.total_first_year_saving) - - -# ***** draft*** -# rough vs reg -> prior only -# all prelim analysis == percent saving -# full analysis == reg and/or persent - -# 1. judge manul_input == annual percent -# 2. judge prelim vs full == generate post_month_bill +print('\n total saving percent =', so.get_total_saving_percent()) +# print(so.get_utility_annual_saving_charge('electricity')) +print('\n simple payback =', so.get_simple_payback(50000)) -- GitLab From c935069e9061c8a570b633fe621dcae2c56b88c2 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Wed, 3 May 2017 17:09:45 -0400 Subject: [PATCH 13/15] Fix test files for Saving class --- bpfin/financials/saving.py | 4 ++-- bpfin/tests/test_financials/test_saving.py | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/bpfin/financials/saving.py b/bpfin/financials/saving.py index 0851973..cd52bff 100644 --- a/bpfin/financials/saving.py +++ b/bpfin/financials/saving.py @@ -147,7 +147,7 @@ class Saving(): def get_proforma_charge(self): """ - Get proforma_charge + Get proforma_charge, for monthly pro-forma, not available for annual Return: list: proforma_charge """ @@ -155,7 +155,7 @@ class Saving(): def get_proforma_saving_charge(self): """ - Get proforma_saving_charge + Get proforma_saving_charge, for monthly pro-forma, not available for annual Return: list: proforma_saving_charge """ diff --git a/bpfin/tests/test_financials/test_saving.py b/bpfin/tests/test_financials/test_saving.py index feddb6c..a5f1c61 100644 --- a/bpfin/tests/test_financials/test_saving.py +++ b/bpfin/tests/test_financials/test_saving.py @@ -34,7 +34,7 @@ def test_Saving_put_monthly_proforma(): assert output_charge == result_charge assert elec_saving.get_first_year_saving_charge() == 430 assert elec_saving.get_annual_proforma_charge() == {2017: 770} - assert elec_saving.get_overall_saving() == output_overall_saving + assert elec_saving.get_percent_saving() == output_overall_saving def test_Saving_put_annual_proforma(): @@ -72,9 +72,10 @@ def test_Saving_put_annual_proforma(): elec_saving = Saving(True, input_commissioning_date, input_proforma_date) elec_saving.put_annual_proforma(input_annual_charge, input_percent_saving) + result_first_year_saving_charge = elec_saving.get_first_year_saving_charge() result_annual_proforma_charge = elec_saving.get_annual_proforma_charge() - result_overall_saving = elec_saving.get_overall_saving() + result_overall_saving = elec_saving.get_percent_saving() assert result_first_year_saving_charge == output_first_year_saving_charge assert result_annual_proforma_charge == output_annual_proforma_charge -- GitLab From f6335e505660e6ad9e213e412bac5eb9d6861fff Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Wed, 3 May 2017 17:55:49 -0400 Subject: [PATCH 14/15] Create test file for Saving_Overview --- bpfin/financials/saving.py | 36 ++++++++++++-- bpfin/tests/test_financials/test_saving.py | 58 ++++++++++++++++++++++ 2 files changed, 89 insertions(+), 5 deletions(-) diff --git a/bpfin/financials/saving.py b/bpfin/financials/saving.py index cd52bff..0feec0c 100644 --- a/bpfin/financials/saving.py +++ b/bpfin/financials/saving.py @@ -250,7 +250,30 @@ class Saving_Overview(): self.total_first_year_saving = 0 # dollar self.total_saving_percent = 0 # dollar percentage - def put_saving(self, prior_month_bill, saving_dict, full_saving_dict): + def put_saving(self, prior_month_bill, percent_saving_dict, full_saving_dict): + """ + Put inputs to generage saving data. + Also calculate overall saving on charge, and percentage saving + + Args: + prior_month_bill (dictionary): dict of dict of lists, projected energy bill for prior_saving + percent_saving_dict (dictionary): dict of float, percentage saving for 4 utility types + full_saving_dict (dictionary): dict of undefined saving, from engineering saving analysis. can be None + + Description: + prior_month_bill = { + 'electricity': electricity_prior_bill_rough, + 'gas': None, + 'oil': None, + 'water': None} + + electricity_prior_bill_rough = { + 'date_from': list, + 'date_to': list, + 'usage': list, + 'charge': list, + 'price': list} + """ utility_type_list = ['electricity', 'gas', 'oil', 'water'] total_first_year_saving = 0 @@ -261,11 +284,11 @@ class Saving_Overview(): utility_saving = Saving(is_manual_input, self.commissioning_date, self.proforma_date) if utility_saving.is_manual_input is True: # bill is from manual input, monthly bill not available - utility_saving.put_annual_proforma(self.prior_annual_bill_table[utility], saving_dict[utility]) + utility_saving.put_annual_proforma(self.prior_annual_bill_table[utility], percent_saving_dict[utility]) if utility_saving.is_manual_input is False: # bill is from scraper, monthly bill is available if full_saving_dict[utility] is None: # engineering saving is not available, use percentage saving - post_month_bill = bill_post_proj_rough(prior_month_bill[utility], saving_dict[utility]) + post_month_bill = bill_post_proj_rough(prior_month_bill[utility], percent_saving_dict[utility]) # else: # engineering saving is available. Project monthly_bill with regression. not finished yet # post_month_bill = bill_proj_reg(prior_utility, full_saving_dict[utility], HDD, CDD, occupancy) @@ -334,6 +357,9 @@ class Saving_Overview(): so = Saving_Overview(db.bill_overview, db.bill_overview_organized, db.analysis_date, datetime.date(2017, 3, 14)) so.put_saving(db.prior_month_bill, db.percent_saving_dict, db.full_saving_dict) -print('\n total saving percent =', so.get_total_saving_percent()) -# print(so.get_utility_annual_saving_charge('electricity')) + +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')) + diff --git a/bpfin/tests/test_financials/test_saving.py b/bpfin/tests/test_financials/test_saving.py index a5f1c61..bc1c48c 100644 --- a/bpfin/tests/test_financials/test_saving.py +++ b/bpfin/tests/test_financials/test_saving.py @@ -1,5 +1,7 @@ import datetime from bpfin.financials.saving import Saving +from bpfin.financials.saving import Saving_Overview +from bpfin.tests.testdata import sample_data as db def test_Saving_put_monthly_proforma(): @@ -80,3 +82,59 @@ def test_Saving_put_annual_proforma(): assert result_first_year_saving_charge == output_first_year_saving_charge assert result_annual_proforma_charge == output_annual_proforma_charge assert result_overall_saving == output_overall_saving + + +def test_Saving_Overview(): + input_bill_overview = db.bill_overview + input_prior_annual_bill_table = db.bill_overview_organized + input_analysis_date = db.analysis_date + input_commissioning_date = datetime.date(2017, 3, 14) + + input_prior_month_bill = db.prior_month_bill + input_percent_saving_dict = db.percent_saving_dict + input_full_saving_dict = db.full_saving_dict + + output_first_year_saving = 10479.289108609044 + output_simple_payback = 4.771316019797902 + output_total_saving_percent = 0.2624163752635955 + output_electricity_annual_saving_charge = { + 2012: 0.0, + 2013: 0.0, + 2014: 0.0, + 2015: 0.0, + 2016: 0.0, + 2017: 6757.962319199603, + 2018: 8846.241570765102, + 2019: 9062.872690379008, + 2020: 9275.049342309605, + 2021: 9471.770503408214, + 2022: 9650.941259401636, + 2023: 9826.981304138018, + 2024: 10007.019419843535, + 2025: 10193.107315596935, + 2026: 10393.916746353145, + 2027: 10609.979647682601, + 2028: 10831.30886589543, + 2029: 11052.82469894908, + 2030: 11274.416949194128, + 2031: 11496.666332412671, + 2032: 11721.576357170983, + 2033: 11951.64472721766, + 2034: 12187.887773507784, + 2035: 12430.56386264111, + 2036: 12679.70824604718 + } + + saving_overview = Saving_Overview( + input_bill_overview, input_prior_annual_bill_table, input_analysis_date, input_commissioning_date) + saving_overview.put_saving(input_prior_month_bill, input_percent_saving_dict, input_full_saving_dict) + + result_first_year_saving = saving_overview.get_total_first_year_saving() + result_simple_payback = saving_overview.get_simple_payback(50000) + result_total_saving_percent = saving_overview.get_total_saving_percent() + result_electricity_annual_saving_charge = saving_overview.get_utility_annual_saving_charge('electricity') + + assert result_first_year_saving == output_first_year_saving + assert result_simple_payback == output_simple_payback + assert result_total_saving_percent == output_total_saving_percent + assert result_electricity_annual_saving_charge == output_electricity_annual_saving_charge -- GitLab From 5d652774522f76f92bb7ae5bf770f2d107672606 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Wed, 3 May 2017 18:02:31 -0400 Subject: [PATCH 15/15] Clean saving file comments --- bpfin/financials/saving.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/bpfin/financials/saving.py b/bpfin/financials/saving.py index 0feec0c..02aa18e 100644 --- a/bpfin/financials/saving.py +++ b/bpfin/financials/saving.py @@ -212,7 +212,8 @@ class Saving_Overview(): 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, 'gas': gas_bill, 'water': water_bill} + prior_annual_bill_table = {'electricity': electricity_bill, 'oil': oil_bill, ...} + electricity_bill = {2014: 100, 2015:200, ...} """ def __init__( @@ -228,7 +229,7 @@ class Saving_Overview(): Args: bill_overview (dictionary): bill_overview from UI, with blank cells, for 4 utility_types - prior_annual_bill_table (dictionary): annual bill, for 4 utility_types + prior_annual_bill_table (dictionary): dict of dict of annual charge, for 4 utility_types analysis_date (dictionary): proforma's starting date and the years of proforma commissioning_date (date): the date that construction work finished, saving starts at NEXT month @@ -236,6 +237,8 @@ class Saving_Overview(): bill_overview (dictionary): dict of a list, list[0] = dict of annual bill, allow some year missing, for 4 utility_types list[1] = boolean value, False == from manual input, True == from scraper + prior_annual_bill_table = {'electricity': electricity_bill, 'oil': oil_bill, ...} + electricity_bill = {2014: 100, 2015:200, ...} """ self.manual_input_dict = { 'electricity': not bill_overview['electricity'][1], @@ -355,11 +358,12 @@ class Saving_Overview(): return saving_dict -so = Saving_Overview(db.bill_overview, db.bill_overview_organized, db.analysis_date, datetime.date(2017, 3, 14)) -so.put_saving(db.prior_month_bill, db.percent_saving_dict, db.full_saving_dict) +# **** ugly test **** +# so = Saving_Overview(db.bill_overview, db.bill_overview_organized, db.analysis_date, datetime.date(2017, 3, 14)) +# so.put_saving(db.prior_month_bill, db.percent_saving_dict, db.full_saving_dict) -print('\n first_year_dollar_saving =',so.get_total_first_year_saving()) -print('\n simple payback =', so.get_simple_payback(50000)) -print('\n total saving percent =', so.get_total_saving_percent()) -print('\n electricity_annual_saving_charge',so.get_utility_annual_saving_charge('electricity')) +# print('\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')) -- GitLab