incorporate bills for dates/amounts into calculations, still need to do future bills on triggers

This commit is contained in:
2025-09-03 22:35:24 +10:00
parent 4b63b8bd44
commit ebac4aaf66
4 changed files with 63 additions and 23 deletions

6
TODO
View File

@@ -5,9 +5,11 @@ For bills:
* estimate future bills/growth:
[DONE] - calculate pragmatic min/avg/max/simple
[DONE] - need to handle future only bills
- remove bills from Living_Expenses (carefully - but by hand)
[DONE] - remove bills from Living_Expenses
- fold future bills into calc so they are processed on the day of the bill
- inflation can then be put to a more realistic quarterly figure
==> need to factor in future bills based on events (such as health/phone when I quit), car when I settle it...
[DONE] ==> and remove hard-coded future costs (like Ioniq rego/ins) when we do above
- inflation can then be put to a more realistic quarterly figure, and fix up Int Rate, again
* might need to be able to mark a specific bill as an outlier - so we ignore the data somehow (think Gas is messing with my bills)
- and even electricity, water, etc. for when we were away in Europe but mostly gas/elec

60
calc.py
View File

@@ -5,6 +5,23 @@ from defines import END_YEAR
# GLOBAL CONSTANTS
LEASE = 0
def bill_amount_today(day, bill_data):
amt=0
day_str = day.strftime("%Y-%m-%d")
for b in bill_data:
# there may be more than one bill on this day, keep add amount and keep going in loop
if b['bill_date'] == day_str:
amt += b['amount']
# bills are desc order so if the bill is before the day we are after then stop looking
if b['bill_date'] < day_str:
if amt:
print( f"bill_amt_today for {day_str} has amt={amt}" )
return amt
#failsafe, doubt this even can occur with bills older than today
if amt:
print( f"bill_amt_today for {day} has amt={amt}" )
return amt
def add_annotation(finance, dt, total, delta, text):
# dont add an annotation for small changes (jic)
tm = dt.timestamp() * 1000
@@ -15,7 +32,7 @@ def add_annotation(finance, dt, total, delta, text):
finance['annotations'].append( { 'label': text, 'x': tm, 'y': total } )
return
def calculate_savings_depletion(finance):
def calculate_savings_depletion(finance, bill_data):
# Extract all the financial data from the database
D_Salary = finance['D_Salary']
D_Num_fortnights_pay = finance['D_Num_fortnights_pay']
@@ -93,6 +110,17 @@ def calculate_savings_depletion(finance):
current_date = datetime.today()
end_date = datetime(END_YEAR, 4, 15)
# TODO: need to refactor Living_Expenses to exclude bills
total=0
yr=str(current_date.year)
for b in bill_data:
if yr in b['bill_date']:
total += b['amount']
print( f"this yr={current_date.year} - total={total}" )
Living_Expenses -= total
print( f"LE is now={Living_Expenses}" )
# Calculate daily living expenses
daily_living_expenses = Living_Expenses / 365
@@ -134,6 +162,9 @@ def calculate_savings_depletion(finance):
# Subtract daily living expenses
current_savings -= daily_living_expenses
# TODO: need to see if a date matches a bill's date, if so subtract bill amount
current_savings -= bill_amount_today( current_date, bill_data )
# Calculate daily interest but apply at the end of the month
monthly_interest += current_savings * daily_interest_rate
@@ -191,6 +222,7 @@ def calculate_savings_depletion(finance):
current_savings += monthly_interest
#print(f"{current_date}: interest paid - ${monthly_interest}")
monthly_interest = 0
# monthly increase living expenses by a monthly inflation multiplier
Living_Expenses += (Inflation/100.0)/12 * Living_Expenses
daily_living_expenses = Living_Expenses / 365
@@ -213,20 +245,20 @@ def calculate_savings_depletion(finance):
# 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:
current_savings -= (ioniq6_ins + ioniq6_rego)
add_annotation(finance, current_date, current_savings, -(ioniq6_ins+ioniq6_rego), "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.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:
# current_savings -= (ioniq6_ins + ioniq6_rego)
# add_annotation(finance, current_date, current_savings, -(ioniq6_ins+ioniq6_rego), "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() == 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():
current_savings -= Mich_present

13
db.py
View File

@@ -271,12 +271,17 @@ def get_comp_set_options(finance):
conn.close()
return
def get_bill_data():
def get_bill_data(order_by):
conn = connect_db(True)
cur = conn.cursor()
cur.execute('''SELECT bd.id, bt.id as bill_type_id, bt.name, bd.amount, bd.bill_date, bd.estimated
FROM bill_type bt, bill_data bd
where bt.id = bd.bill_type order by bt.name, bd.bill_date desc''')
if order_by == "order_by_date_only":
cur.execute('''SELECT bd.id, bt.id as bill_type_id, bt.name, bd.amount, bd.bill_date, bd.estimated
FROM bill_type bt, bill_data bd
where bt.id = bd.bill_type order by bd.bill_date desc''')
else:
cur.execute('''SELECT bd.id, bt.id as bill_type_id, bt.name, bd.amount, bd.bill_date, bd.estimated
FROM bill_type bt, bill_data bd
where bt.id = bd.bill_type order by bt.name, bd.bill_date desc''')
bd = cur.fetchall()
conn.close()
return bd

View File

@@ -25,7 +25,8 @@ init_db()
def index():
finance_data = get_finance_data()
get_comp_set_options(finance_data)
depletion_date, savings_per_fortnight, final_savings = calculate_savings_depletion(finance_data)
bill_data = get_bill_data("order_by_date_only")
depletion_date, savings_per_fortnight, final_savings = calculate_savings_depletion(finance_data, bill_data)
BUDGET=get_budget_data(finance_data)
if depletion_date:
@@ -143,13 +144,13 @@ def update():
@app.route('/bills')
def DisplayBillData():
bill_data = get_bill_data()
bill_data = get_bill_data("order_by_bill_type_then_date")
bill_types = get_bill_types()
bill_freqs = get_bill_freqs()
bill_ui = get_bill_ui()
bill_info=process_bill_data(bill_data, bill_types, bill_freqs)
total=calc_future_totals(bill_info, bill_types)
bill_data = get_bill_data()
bill_data = get_bill_data("order_by_bill_type_then_date")
return render_template('bills.html', bill_data=bill_data, bill_types=bill_types, bill_freqs=bill_freqs, bill_ui=bill_ui, this_year=datetime.today().year, END_YEAR=END_YEAR, total=total )
@app.route('/newbilltype', methods=['POST'])