fixed a few bugs, annual growth was just broken, dont add another estimate bill when we have one for that year or in that quarter, removed lots of debugs, fixed a few bugs where the first data point in a new year/qtr would not have arrays initialised properly first, apportion quarterly data in future real bills - it happens with Rates

This commit is contained in:
2025-08-28 19:49:41 +10:00
parent 91ebc227b6
commit 2bdd1348b8

View File

@@ -1,4 +1,4 @@
from db import get_bill_data, get_bill_types, get_bill_freqs, set_bill_type_growth, new_bill
from db import set_bill_type_growth, new_bill
from defines import END_YEAR
import datetime
from datetime import date, timedelta
@@ -51,6 +51,8 @@ def allocate_by_quarter( bill_info, bill_type, yr, prev_bill, bill):
bill_info[bill_type]['qtr'][q_start.year] = {}
for i in range(1,5):
bill_info[bill_type]['qtr'][q_start.year][i]=0
if q not in bill_info[bill_type]['qtr'][q_start.year]:
bill_info[bill_type]['qtr'][q_start.year][q]=0
bill_info[bill_type]['qtr'][q_start.year][q] += days*cost_per_day
# next quarter
cur = q_end + timedelta(days=1)
@@ -139,14 +141,17 @@ def new_estimated_bill( bill_info, yr, bill_type, amt, new_date ):
if bill_info[bill_type]['num_ann_bills'] == 4:
q = qtr( new_date )
# new bill in this qtr of this year, so set arrays up
if yr not in bill_info[bill_type]['qtr']:
bill_info[bill_type]['qtr'][yr]={}
pb = find_previous_bill( bill_type, bill_info, new_date )
if pb['estimated'] == 0:
print( f" FIXFIXFIX - have a prev real bill={pb['bill_date']} & this is first est - likely need to better apportion this bill into the quarters" )
allocate_by_quarter( bill_info, bill_type, yr, pb, bill )
bill_info[bill_type]['qtr'][yr][q]=amt
else:
if not q in bill_info[bill_type]['qtr'][yr]:
# first in this year, just init it...
bill_info[bill_type]['qtr'][yr][q]=0
bill_info[bill_type]['qtr'][yr][q]+=amt
return
@@ -155,12 +160,16 @@ def new_estimated_bill( bill_info, yr, bill_type, amt, new_date ):
# NOTE: only ever called when there is a need to add a new bill
def add_missing_annual_bill_in_yr( bill_type, bill_info, yr ):
mm_dd = bill_info[bill_type]['last_bill']['bill_date'][5:]
amt = bill_info[bill_type]['last_bill']['amount']
new_date= f'{yr}-{mm_dd}'
pb=find_previous_bill( bill_type, bill_info, new_date )
if pb:
amt = pb['amount']
else:
amt = bill_info[bill_type]['last_bill']['amount']
# okay the missing bill is before the first bill...
for i in range( bill_info[bill_type]['last_bill_year'], yr ):
amt += amt * bill_info[bill_type]['growth']/100
amt += amt * bill_info[bill_type]['growth']/100
new_estimated_bill( bill_info, yr, bill_type, amt, f'{yr}-{mm_dd}' )
new_estimated_bill( bill_info, yr, bill_type, amt, new_date )
return
# missing quarterly bill, find date based on MM-DD and ??? - can have missing bilsl in first year
@@ -248,6 +257,8 @@ def get_growth_value( bt, bill_type ):
return el['ann_growth_avg']
elif which == 'min':
return el['ann_growth_min']
elif which == 'simple':
return el['ann_growth_simple']
else:
return el['ann_growth_max']
@@ -313,7 +324,8 @@ def process_bill_data(bd, bt, bf):
# go from first_bill year until reach end year
for yr in range( yr_min, END_YEAR+1 ):
# we have all the bills needed for yr - but dont be cute with qtrly, gas bills suck can have missing with 4 bills
if yr in bill_info[bill_type]['year'] and len(bill_info[bill_type]['year'][yr]) == bill_info[bill_type]['num_ann_bills'] and bill_info[bill_type]['num_ann_bills'] !=4:
# > can occur when we add a real bill "on top of" an estimate.
if yr in bill_info[bill_type]['year'] and len(bill_info[bill_type]['year'][yr]) >= bill_info[bill_type]['num_ann_bills'] and bill_info[bill_type]['num_ann_bills'] !=4:
continue
add_missing_bills_for_yr( bill_type, bill_info, yr )
derive_ann_growth( bill_type, bill_info )
@@ -333,7 +345,7 @@ def add_missing_bills_for_yr( bill_type, bill_info, yr ):
################################################################################
# Takes qtrly bills and start from 2nd year of bills (so we can estimate growth)
# and go through each bill allocating hte proportion of each bill to each
# and go through each bill allocating the proportion of each bill to each
# relevant quarter - to build more accurate totals. Would be mostly marginal
# accept when Gas qtrly bills have 6 per year, and we need to guess say qtr4 in
# the future, we can't easily find corresponding bill form previous year, so
@@ -344,12 +356,13 @@ def ProportionQtrlyData( bill_type, bill_info ):
now_yr = datetime.date.today().year
# FIX UP CRAPPY QUARTERLY BILLING PROPORTIONS (only useful as some gas bills are 6 / year!)
if bill_info[bill_type]['num_ann_bills']==4:
for yr in range( bill_info[bill_type]['first_bill_year'], now_yr+1):
for b in bill_info[bill_type]['year'][yr]:
pb = find_previous_bill( bill_type, bill_info, b['bill_date'] )
if not pb:
continue
allocate_by_quarter( bill_info, bill_type, yr, pb, b )
for yr in range( bill_info[bill_type]['first_bill_year'], END_YEAR+1):
if yr in bill_info[bill_type]['year']:
for b in bill_info[bill_type]['year'][yr]:
pb = find_previous_bill( bill_type, bill_info, b['bill_date'] )
if not pb:
continue
allocate_by_quarter( bill_info, bill_type, yr, pb, b )
return
################################################################################
@@ -368,7 +381,7 @@ def derive_ann_growth( bill_type, bill_info ):
continue;
# just going to make sure we dont use estimated data in the last year of real data - can skew growths
if yr == bill_info[bill_type]['last_real_bill_year']:
if yr == bill_info[bill_type]['last_real_bill_year'] or bill_info[bill_type]['num_ann_bills'] ==1:
skip_yr=False
for b in bill_info[bill_type]['year'][yr]:
if b['estimated']:
@@ -397,24 +410,37 @@ def derive_ann_growth( bill_type, bill_info ):
avg_growth = 0
max_growth = 0
count = 0
simple_first_yr=0
simple_last_yr=0
# start from year after first bill, so we can see annual growth from the following year onwards
for yr in range( bill_info[bill_type]['first_bill_year']+1, now_yr+1):
# if full data sets for consecutive years, work out annual growth stats
if yr-1 in total and yr in total:
if simple_first_yr==0:
simple_first_yr=yr
growth = (total[yr] - total[yr-1]) / total[yr-1] * 100
avg_growth += growth
count += 1
simple_last_yr=yr
if growth < min_growth:
min_growth = growth
if growth > max_growth:
max_growth = growth
# data to work with
if count:
## print( f"Before sanity check, min={min_growth}, avg={avg_growth/count}, max_growth={max_growth}" )
# HACK FOR SANITY SAKE NOW - bills wont decrease normally, and 10% is unlikely for sustained growth
if min_growth< 0: min_growth=0
if avg_growth< 0 or avg_growth > 10: avg_growth = 3*count
if max_growth>10 : max_growth = 9.99
set_bill_type_growth( bill_type, min_growth, avg_growth/count, max_growth )
if simple_first_yr != simple_last_yr:
# calculate a simple growth with full year consecutive totals -> last - first / years
simple_growth=( ((total[simple_last_yr]-total[simple_first_yr])/(simple_last_yr-simple_first_yr)) / total[simple_first_yr] )*100.0
else:
# calculate a simple growth based on last - first / years - only 1 consecutive year I guess, so can't use it, use real first/last
if bill_info[bill_type]['first_bill_year'] != bill_info[bill_type]['last_real_bill_year']:
simple_growth=( ((total[bill_info[bill_type]['last_real_bill_year']]-total[bill_info[bill_type]['first_bill_year']])/(bill_info[bill_type]['last_real_bill_year']-bill_info[bill_type]['first_bill_year'])) / total[bill_info[bill_type]['first_bill_year']] )*100.0
set_bill_type_growth( bill_type, min_growth, avg_growth/count, max_growth, simple_growth )
else:
# failsafe (just in case fill bills failed to add enough bills to average out)
print( f"{bill_type}: Unable to calculate growth!" )
# okay use last - first / years to get a simple_growth, just need bills from different years
if bill_info[bill_type]['first_bill_year'] != bill_info[bill_type]['last_real_bill_year']:
simple_growth=( ((total[bill_info[bill_type]['last_real_bill_year']]-total[bill_info[bill_type]['first_bill_year']])/(bill_info[bill_type]['last_real_bill_year']-bill_info[bill_type]['first_bill_year'])) / total[bill_info[bill_type]['first_bill_year']] )*100.0
set_bill_type_growth( bill_type, 0, 0, 0, simple_growth )
else:
# failsafe (just in case fill bills failed to add enough bills to average out)
print( f"{bill_type}: Unable to calculate growth!" )