move future bills into bills.py, away from calc.py for file content consistency

This commit is contained in:
2025-09-15 22:17:17 +10:00
parent 8274da0ce0
commit 1c112e6f6b
2 changed files with 97 additions and 67 deletions

102
bills.py
View File

@@ -88,6 +88,18 @@ def find_next_bill( bill_type, bill_info, bill_date ):
return None
# see if this bill exists (used to prevent adding more than once in future
# estimated bills)
def find_this_bill( bill_type, bill_info, bill_date ):
yr = int(bill_date[:4])
if not bill_type in bill_info or not 'year' in bill_info[bill_type] or not yr in bill_info[bill_type]['year']:
return None
for b in bill_info[bill_type]['year'][yr]:
if bill_type == b['bill_type'] and bill_date == b['bill_date']:
return b
return None
# find the bill just before the date given
def find_previous_bill( bill_type, bill_info, bill_date ):
wanted_year = int(bill_date[:4])
@@ -139,6 +151,7 @@ def new_estimated_bill( bill_info, yr, bill_type, amt, new_date ):
bill={}
bill['bill_date']=new_date
bill['amount']=amt
bill['bill_type']=bill_type
bill['estimated']=1
# need to insert(0,) to add this "newest" bill to start of the data for {yr} so that find_previous_bill can work - only need the above 3 fields
bill_info[bill_type]['year'][yr].insert(0,bill)
@@ -295,6 +308,8 @@ def process_bill_data(bd, bt, bf, key_dates):
# this maps a bill id to a freq id (e.g. bill #34 - has a frequency of #2 (which might be quarterly)
bt_id_freq = {row["id"]: row["freq"] for row in bt}
bt_id_ann_growth_avg = {row["id"]: row["ann_growth_avg"] for row in bt}
bt_id_name = {row["id"]: row["name"] for row in bt}
# this maps freq to bills per annum (e.g. id=2 to 4 bills per annum)
bf_id_num = {row["id"]: row["num_bills_per_annum"] for row in bf}
@@ -304,11 +319,23 @@ def process_bill_data(bd, bt, bf, key_dates):
# want to proces all bill data into easier to maniuplate structure, so make
# a bill_info[bill_id] with first_bill, last_bill, [yr] with matching bills to process
bill_info={}
future_car_bills=[]
future_D_quit_bills=[]
for bill in bd:
bill_type = bill['bill_type']
if bill['bill_date'] == 'future':
print("Having a future data - skip this one")
# Future bills, deal with them at the end - they have dynamic start dates
if 'Hyundai' in bt_id_name[bill_type]:
future_car_bills.insert( 0, bill )
else:
future_D_quit_bills.insert( 0, bill )
bill_info[bill_type]={}
bill_info[bill_type]['future'] = 1
bill_info[bill_type]['freq'] = bf_id_name[bt_id_freq[bill_type]]
bill_info[bill_type]['growth'] = get_growth_value( bt, bill_type )
bill_info[bill_type]['num_ann_bills'] = bf_id_num[bt_id_freq[bill_type]]
bill_info[bill_type]['year']={}
continue
yr= int(bill['bill_date'][:4])
@@ -339,6 +366,8 @@ def process_bill_data(bd, bt, bf, key_dates):
# now process the bill_info from yr of first bill to yr of last bill
for bill_type in bill_info:
if 'future' in bill_info[bill_type]:
continue
# find freq id based on bill_type id, then use that to find num bills by freq id
num = bf_id_num[bt_id_freq[bill_type]]
@@ -357,9 +386,72 @@ def process_bill_data(bd, bt, bf, key_dates):
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 )
derive_ann_growth( bill_type, bill_info, key_dates, future_car_bills, future_D_quit_bills )
deal_with_future_car_bills( key_dates, future_car_bills, bill_info )
deal_with_future_D_quit_bills( key_dates, future_D_quit_bills, bill_info )
return bill_info
################################################################################
# deal_with_future_car_bills - just add these estimate bills based on when we
# own the car (data can change if I buy it out)
################################################################################
def deal_with_future_car_bills( key_dates, future_car_bills, bill_info ):
car_yr=key_dates['D_hyundai_owned'][0:4]
car_mmdd=key_dates['D_hyundai_owned'][5:]
for fb in future_car_bills:
# deal with future bills due to their starting dates being dynamic
amt=fb['amount']
bt=fb['bill_type']
# factor in growth for next bill
for yr in range( int(car_yr), END_YEAR ):
new_date=f"{yr}-{car_mmdd}"
# if we dont already have an annual bill for this year (all car bills are annual)
if yr not in bill_info[bt]['year']:
print( f"amt of a car fb is: {amt}, car_yr={car_yr}, yr={yr}, nd={new_date}")
new_estimated_bill( bill_info, yr, fb['bill_type'], amt, new_date )
amt += amt * bill_info[bt]['growth']/100
################################################################################
# deal_with_future_D_quit_bills - just add these estimate bills based on when I
# quit
################################################################################
def deal_with_future_D_quit_bills( key_dates, future_D_quit_bills, bill_info ):
D_quit_yr = key_dates['D_quit_date'][0:4]
dq_mm=key_dates['D_quit_date'][5:7]
dq_dd=key_dates['D_quit_date'][8:]
if int(dq_dd) > 28: dq_dd=28
for fb in future_D_quit_bills:
# deal with future bills due to their starting dates being dynamic
amt=fb['amount']
bt=fb['bill_type']
if bill_info[bt]['num_ann_bills'] == 1:
# factor in growth for next bill
for yr in range( int(D_quit_yr), END_YEAR ):
new_date=f"{yr}-{dq_mm}-{dq_dd}"
# if we dont already have an annual bill for this year
if not find_this_bill( bt, bill_info, new_date ):
print( f"amt of a D_quit fb is: {amt}, dq_yr={D_quit_yr}, yr={yr}, nd={new_date}")
new_estimated_bill( bill_info, yr, bt, amt, new_date )
amt += amt * bill_info[bt]['growth']/100
elif bill_info[bt]['num_ann_bills'] == 12:
print( f"should be adding monthly future bill" )
# do rest of this year, then next years
for m in range( int(dq_mm), 13):
new_date=f"{D_quit_yr}-{m:02d}-{dq_dd}"
if not find_this_bill( bt, bill_info, new_date ):
print( f"amt of a D_quit fb is: {amt}, dq_yr={D_quit_yr}, nd={new_date}")
new_estimated_bill( bill_info, yr, bt, amt, new_date )
for yr in range( int(D_quit_yr)+1, END_YEAR ):
amt += amt * bill_info[bt]['growth']/100
for m in range( 1, 13):
new_date=f"{yr}-{m:02d}-{dq_dd}"
if not find_this_bill( bt, bill_info, new_date ):
print( f"amt of a D_quit fb is: {amt}, dq_yr={D_quit_yr}, yr={yr}, nd={new_date}")
new_estimated_bill( bill_info, yr, bt, amt, new_date )
################################################################################
# add_missing_bills_for_yr -- wrapper to call right func based on bill freq
################################################################################
@@ -400,7 +492,7 @@ def ProportionQtrlyData( bill_type, bill_info ):
# terms of min/avg/max - uses qtr data for qtrly bills, or just normal totals
# for other bill types
################################################################################
def derive_ann_growth( bill_type, bill_info ):
def derive_ann_growth( bill_type, bill_info, key_dates, future_car_bills, future_D_quit_bills ):
# just do up to now so we stop earlier than looking at other estimated (just an optimisation)
now_yr = datetime.date.today().year
@@ -433,7 +525,6 @@ def derive_ann_growth( bill_type, bill_info ):
# use new derived qtr, slightly more accurate
total[yr]=tot
# once we have all yr totals:
growth = {}
min_growth = 999
@@ -495,4 +586,3 @@ def calc_future_totals(bill_info, bill_types):
# had to round to 2 decimal here to get sensible totals
total[bt['id']][yr] = round( total[bt['id']][yr], 2 )
return total