move future bills into bills.py, away from calc.py for file content consistency
This commit is contained in:
102
bills.py
102
bills.py
@@ -88,6 +88,18 @@ def find_next_bill( bill_type, bill_info, bill_date ):
|
|||||||
return None
|
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
|
# find the bill just before the date given
|
||||||
def find_previous_bill( bill_type, bill_info, bill_date ):
|
def find_previous_bill( bill_type, bill_info, bill_date ):
|
||||||
wanted_year = int(bill_date[:4])
|
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['bill_date']=new_date
|
bill['bill_date']=new_date
|
||||||
bill['amount']=amt
|
bill['amount']=amt
|
||||||
|
bill['bill_type']=bill_type
|
||||||
bill['estimated']=1
|
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
|
# 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)
|
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)
|
# 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_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_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)
|
# 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}
|
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
|
# 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
|
# a bill_info[bill_id] with first_bill, last_bill, [yr] with matching bills to process
|
||||||
bill_info={}
|
bill_info={}
|
||||||
|
future_car_bills=[]
|
||||||
|
future_D_quit_bills=[]
|
||||||
|
|
||||||
for bill in bd:
|
for bill in bd:
|
||||||
bill_type = bill['bill_type']
|
bill_type = bill['bill_type']
|
||||||
if bill['bill_date'] == 'future':
|
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
|
continue
|
||||||
|
|
||||||
yr= int(bill['bill_date'][:4])
|
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
|
# now process the bill_info from yr of first bill to yr of last bill
|
||||||
for bill_type in bill_info:
|
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
|
# 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]]
|
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:
|
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
|
continue
|
||||||
add_missing_bills_for_yr( bill_type, bill_info, yr )
|
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
|
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
|
# 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
|
# terms of min/avg/max - uses qtr data for qtrly bills, or just normal totals
|
||||||
# for other bill types
|
# 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)
|
# just do up to now so we stop earlier than looking at other estimated (just an optimisation)
|
||||||
now_yr = datetime.date.today().year
|
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
|
# use new derived qtr, slightly more accurate
|
||||||
total[yr]=tot
|
total[yr]=tot
|
||||||
|
|
||||||
|
|
||||||
# once we have all yr totals:
|
# once we have all yr totals:
|
||||||
growth = {}
|
growth = {}
|
||||||
min_growth = 999
|
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
|
# had to round to 2 decimal here to get sensible totals
|
||||||
total[bt['id']][yr] = round( total[bt['id']][yr], 2 )
|
total[bt['id']][yr] = round( total[bt['id']][yr], 2 )
|
||||||
return total
|
return total
|
||||||
|
|
||||||
|
|||||||
62
calc.py
62
calc.py
@@ -117,35 +117,15 @@ def calculate_savings_depletion(finance, bill_data, bill_type):
|
|||||||
# main loop range -- start from now, and simulate till D is 60 (April 2031)
|
# main loop range -- start from now, and simulate till D is 60 (April 2031)
|
||||||
current_date = datetime.today()
|
current_date = datetime.today()
|
||||||
|
|
||||||
# work out which bill_types relate to future bills
|
|
||||||
for bt in bill_type:
|
|
||||||
if 'Hyundai' in bt['name']:
|
|
||||||
if 'Car Ins' in bt['name']:
|
|
||||||
ioniq6_ins_bt = bt
|
|
||||||
if 'Car Rego' in bt['name']:
|
|
||||||
ioniq6_rego_bt = bt
|
|
||||||
if 'Health Ins' in bt['name']:
|
|
||||||
health_ins_bt = bt
|
|
||||||
if 'Phone' in bt['name'] and 'Damien' in bt['name']:
|
|
||||||
phone_d_bt = bt
|
|
||||||
|
|
||||||
# TODO: need to refactor Living_Expenses to exclude bills
|
# TODO: need to refactor Living_Expenses to exclude bills
|
||||||
total=0
|
total=0
|
||||||
yr=str(current_date.year)
|
yr=str(current_date.year)
|
||||||
for b in bill_data:
|
for b in bill_data:
|
||||||
if b['bill_type'] == ioniq6_rego_bt['id']:
|
|
||||||
ioniq6_rego = b['amount']
|
|
||||||
if b['bill_type'] == ioniq6_ins_bt['id']:
|
|
||||||
ioniq6_ins = b['amount']
|
|
||||||
if b['bill_type'] == health_ins_bt['id']:
|
|
||||||
health_ins = b['amount']
|
|
||||||
if b['bill_type'] == phone_d_bt['id']:
|
|
||||||
phone_d = b['amount']
|
|
||||||
|
|
||||||
if yr in b['bill_date']:
|
if yr in b['bill_date']:
|
||||||
total += b['amount']
|
total += b['amount']
|
||||||
|
|
||||||
print( f"this yr={current_date.year} - total={total} -- hi={health_ins}, phone_d={phone_d}" )
|
print( f"this yr={current_date.year} - total={total}" )
|
||||||
Living_Expenses -= total
|
Living_Expenses -= total
|
||||||
print( f"LE is now={Living_Expenses}" )
|
print( f"LE is now={Living_Expenses}" )
|
||||||
|
|
||||||
@@ -187,19 +167,6 @@ def calculate_savings_depletion(finance, bill_data, bill_type):
|
|||||||
# if we have a bill for today, pay for it
|
# if we have a bill for today, pay for it
|
||||||
current_savings -= bill_amount_today( finance, current_date, bill_data, bt_id_name, current_savings )
|
current_savings -= bill_amount_today( finance, current_date, bill_data, bt_id_name, current_savings )
|
||||||
|
|
||||||
# KLUDGE for future bills for now:
|
|
||||||
# if I have quit, pay monthly future bills - assume 1st day of month for health ins
|
|
||||||
if D_has_quit and current_date.day == 1:
|
|
||||||
health_ins = health_ins * 1+((health_ins_bt['ann_growth_simple'])/100)*12
|
|
||||||
current_savings -= health_ins
|
|
||||||
|
|
||||||
# once a year from when I quit, pay the phone bill (year I quit comes below)
|
|
||||||
if D_has_quit and current_date.month == D_quit_date.month and current_date.day == D_quit_date.day:
|
|
||||||
amt=phone_d
|
|
||||||
for y in range( D_quit_date.year, current_date.year):
|
|
||||||
amt = amt * (1+phone_d_bt['ann_growth_simple']/100)
|
|
||||||
current_savings -= amt
|
|
||||||
|
|
||||||
# Calculate daily interest but apply at the end of the month
|
# Calculate daily interest but apply at the end of the month
|
||||||
monthly_interest += current_savings * daily_interest_rate
|
monthly_interest += current_savings * daily_interest_rate
|
||||||
|
|
||||||
@@ -230,8 +197,6 @@ def calculate_savings_depletion(finance, bill_data, bill_type):
|
|||||||
current_savings += D_leave_after_tax
|
current_savings += D_leave_after_tax
|
||||||
add_annotation(finance, current_date, current_savings, D_leave_after_tax, "D quit" )
|
add_annotation(finance, current_date, current_savings, D_leave_after_tax, "D quit" )
|
||||||
D_leave_after_tax = 0
|
D_leave_after_tax = 0
|
||||||
# pay for 1st year of phone for Damien
|
|
||||||
current_savings -= phone_d
|
|
||||||
|
|
||||||
# its end of 'next' fin year, if tax_diff > 0, then ddp quit after new tax year and gets back the overpaid tax
|
# its end of 'next' fin year, if tax_diff > 0, then ddp quit after new tax year and gets back the overpaid tax
|
||||||
if current_date > new_fin_year_26 and claim_tax_on_leave:
|
if current_date > new_fin_year_26 and claim_tax_on_leave:
|
||||||
@@ -281,30 +246,6 @@ def calculate_savings_depletion(finance, bill_data, bill_type):
|
|||||||
add_annotation(finance, current_date, current_savings, -Car_buyout, "car buyout")
|
add_annotation(finance, current_date, current_savings, -Car_buyout, "car buyout")
|
||||||
print(f"{current_date}: car buyout - ${Car_buyout}" )
|
print(f"{current_date}: car buyout - ${Car_buyout}" )
|
||||||
|
|
||||||
# Anniversary of Car purchase/balloon so potentially insurance/rego
|
|
||||||
# when I quit, the if we haven't paid the car outright, then need to add rego, but not insurance
|
|
||||||
# if we pay-out the car, then add insurace and rego
|
|
||||||
if current_date.month == car_balloon_date.month and current_date.day == car_balloon_date.day:
|
|
||||||
# staying with the lease (0), if I have quit, then pay monthly rego only up to lease date, but full cost after car balloon date
|
|
||||||
if Ioniq6_future == LEASE:
|
|
||||||
if current_date.year >= car_balloon_date.year:
|
|
||||||
ins_amt=ioniq6_ins
|
|
||||||
for y in range( car_balloon_date.year, current_date.year):
|
|
||||||
ins_amt = ins_amt * (1+ioniq6_ins_bt['ann_growth_simple']/100)
|
|
||||||
rego_amt=ioniq6_rego
|
|
||||||
for y in range( car_balloon_date.year, current_date.year):
|
|
||||||
rego_amt = rego_amt * (1+ioniq6_rego_bt['ann_growth_simple']/100)
|
|
||||||
current_savings -= (ins_amt+rego_amt)
|
|
||||||
add_annotation(finance, current_date, current_savings, -(ins_amt+rego_amt), "IONIQ 6 ins/rego" )
|
|
||||||
# if we buy car outright, then as long as this anniversary is after buyout date, pay ins and rego
|
|
||||||
elif current_date.year >= car_buyout_date.year:
|
|
||||||
current_savings -= (ioniq6_ins + ioniq6_rego)
|
|
||||||
add_annotation(finance, current_date, current_savings, -(ioniq6_ins+ioniq6_rego), "IONIQ 6 ins/rego" )
|
|
||||||
|
|
||||||
# if current_date.date() == overseas_trip_date.date():
|
|
||||||
# current_savings -= Overseas_trip
|
|
||||||
# add_annotation(finance, current_date, current_savings, -Overseas_trip, "O/S trip")
|
|
||||||
|
|
||||||
if current_date.date() == mich_present_date.date():
|
if current_date.date() == mich_present_date.date():
|
||||||
current_savings -= Mich_present
|
current_savings -= Mich_present
|
||||||
add_annotation(finance, current_date, current_savings, -Mich_present, "Mich's present" )
|
add_annotation(finance, current_date, current_savings, -Mich_present, "Mich's present" )
|
||||||
@@ -358,7 +299,6 @@ def calculate_savings_depletion(finance, bill_data, bill_type):
|
|||||||
finance['CBA']=D_CBA_shares
|
finance['CBA']=D_CBA_shares
|
||||||
finance['TLS']=D_TLS_shares+M_TLS_shares
|
finance['TLS']=D_TLS_shares+M_TLS_shares
|
||||||
|
|
||||||
|
|
||||||
return depletion_date, savings_per_fortnight, current_savings
|
return depletion_date, savings_per_fortnight, current_savings
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|||||||
Reference in New Issue
Block a user