Compare commits
3 Commits
c49520af7a
...
4389045ed5
| Author | SHA1 | Date | |
|---|---|---|---|
| 4389045ed5 | |||
| b69ec82510 | |||
| 2bd39ab24c |
34
TODO
34
TODO
@@ -1,33 +1,11 @@
|
|||||||
UI:
|
UI:
|
||||||
|
* use key_dates to highlight when I quit, when we own car
|
||||||
|
|
||||||
For bills:
|
For bills:
|
||||||
Future bills:
|
[DONE] * calc quit date based on finance data
|
||||||
* longer-term: make the moment we quit / own car trigger new bill creation, and remove hard-coded logic on costs - just use bill_data created
|
[DONE] * calc date of car lease end or buyout
|
||||||
- this will then cover handling different bill_types or growth models
|
* use this to populate bill estimates, so this allows totals / year and simplifies calc.py
|
||||||
|
|
||||||
* 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)
|
* 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
|
- and even electricity, water, etc. for when we were away in Europe but mostly gas/elec
|
||||||
|
|
||||||
LONGER/HARDER:
|
|
||||||
* need to work out 'first bill' and 'last bill' to auto-fill missing bills based on
|
|
||||||
-- all missing bills follow varying growth models & its by choice -- therefore I need this in DB
|
|
||||||
- ANN: flat, min, avg, max, manual
|
|
||||||
- QTR: flat, qtrly seasonal: min/avg/max/manual, qtrly simple: min/avg/max/manual, annual: min/avg/max/manual
|
|
||||||
- MON: flat, monthly: min/avg/max/manual, annual: min/avg/max/manual
|
|
||||||
-- use this logic to add missing bills (date):
|
|
||||||
-- ANN: missing annual bill, find date based on MM-DD and add new year - given we start with first_bill anyway, will only be used for future bill predictions
|
|
||||||
-- QTR: missing quarterly bill, find date based on MM-DD and ??? - can have missing bilsl in first year
|
|
||||||
-- MON: missing monthly bills, find date based on DD and put in each missing month
|
|
||||||
-- use this logic to add missing bills (amount):
|
|
||||||
-- ANN: future only, so add ann_growth (based on drop-down) for each future year
|
|
||||||
-- QTR: add growth (based on drop-down) for each future year
|
|
||||||
-- MON: add growth (based on drop-down) for each future year
|
|
||||||
|
|
||||||
MUCH LONGER/HARDER:
|
|
||||||
potentially for each bill_type, there are unique extras - e.g. THIS feels too hard:
|
|
||||||
water has 2 fixed charges (water & sewerage) and then a consumption charge (per ML)
|
|
||||||
elec has 1 fixe charge (daily) and then consumption (per kwh) BUT, also daily solar rate
|
|
||||||
gas has fixed charge and consumption
|
|
||||||
internet, kayo is monthly fixed (but can go up sometimes)
|
|
||||||
eweka is annual fixed
|
|
||||||
phone is messier again.
|
|
||||||
|
|||||||
3
bills.py
3
bills.py
@@ -291,7 +291,7 @@ def get_growth_value( bt, bill_type ):
|
|||||||
# and I didn't want to input 12 of them at the same price), and it always
|
# and I didn't want to input 12 of them at the same price), and it always
|
||||||
# occurs for future bills
|
# occurs for future bills
|
||||||
################################################################################
|
################################################################################
|
||||||
def process_bill_data(bd, bt, bf):
|
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}
|
||||||
@@ -495,3 +495,4 @@ 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
|
||||||
|
|
||||||
|
|||||||
40
calc.py
40
calc.py
@@ -5,6 +5,15 @@ from defines import END_YEAR
|
|||||||
# GLOBAL CONSTANTS
|
# GLOBAL CONSTANTS
|
||||||
LEASE = 0
|
LEASE = 0
|
||||||
|
|
||||||
|
# Dates that don't change
|
||||||
|
car_balloon_date = datetime(2026, 11, 15)
|
||||||
|
new_fin_year_25 = datetime(2025, 7, 1)
|
||||||
|
new_fin_year_26 = datetime(2026, 7, 1)
|
||||||
|
end_date = datetime(END_YEAR, 4, 15)
|
||||||
|
school_fees_date = datetime(2025, 12, 5)
|
||||||
|
mich_present_date = datetime(2026,10,15)
|
||||||
|
first_pay_date = datetime(2025,1,8)
|
||||||
|
|
||||||
def bill_amount_today(finance, day, bill_data, bt_id_name, total ):
|
def bill_amount_today(finance, day, bill_data, bt_id_name, total ):
|
||||||
amt=0
|
amt=0
|
||||||
day_str = day.strftime("%Y-%m-%d")
|
day_str = day.strftime("%Y-%m-%d")
|
||||||
@@ -100,8 +109,6 @@ def calculate_savings_depletion(finance, bill_data, bill_type):
|
|||||||
D_has_quit = False
|
D_has_quit = False
|
||||||
D_quit_year = 0
|
D_quit_year = 0
|
||||||
claim_tax_on_leave = False
|
claim_tax_on_leave = False
|
||||||
new_fin_year_25 = datetime(2025, 7, 1)
|
|
||||||
new_fin_year_26 = datetime(2026, 7, 1)
|
|
||||||
|
|
||||||
# Constants for interest calculations
|
# Constants for interest calculations
|
||||||
annual_interest_rate = Interest_Rate / 100.0
|
annual_interest_rate = Interest_Rate / 100.0
|
||||||
@@ -109,7 +116,6 @@ 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()
|
||||||
end_date = datetime(END_YEAR, 4, 15)
|
|
||||||
|
|
||||||
# work out which bill_types relate to future bills
|
# work out which bill_types relate to future bills
|
||||||
for bt in bill_type:
|
for bt in bill_type:
|
||||||
@@ -151,11 +157,6 @@ def calculate_savings_depletion(finance, bill_data, bill_type):
|
|||||||
depletion_date = None
|
depletion_date = None
|
||||||
savings_per_fortnight = []
|
savings_per_fortnight = []
|
||||||
|
|
||||||
# significant dates that are non-changeable
|
|
||||||
school_fees_date = datetime(2025, 12, 5)
|
|
||||||
car_balloon_date = datetime(2026, 11, 15)
|
|
||||||
mich_present_date = datetime(2026,10,15)
|
|
||||||
|
|
||||||
# significant dates - but who knows when? :)
|
# significant dates - but who knows when? :)
|
||||||
overseas_trip_date = datetime.strptime( finance['Overseas_trip_date'], "%Y-%m-%d")
|
overseas_trip_date = datetime.strptime( finance['Overseas_trip_date'], "%Y-%m-%d")
|
||||||
mark_reno_date = datetime.strptime( finance['Mark_reno_date'], "%Y-%m-%d")
|
mark_reno_date = datetime.strptime( finance['Mark_reno_date'], "%Y-%m-%d")
|
||||||
@@ -360,3 +361,26 @@ def calculate_savings_depletion(finance, bill_data, bill_type):
|
|||||||
|
|
||||||
return depletion_date, savings_per_fortnight, current_savings
|
return depletion_date, savings_per_fortnight, current_savings
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# work out the date D quits and when we own the car, so we can then use it to
|
||||||
|
# handle future bills
|
||||||
|
################################################################################
|
||||||
|
def calc_key_dates( finance ):
|
||||||
|
key_dates={}
|
||||||
|
now = datetime.today()
|
||||||
|
# this will be 0 to 13 days - how far into this fortnights pay cycle are we now
|
||||||
|
days_in_pay_fortnight= ( now - first_pay_date ).days % 14
|
||||||
|
|
||||||
|
# add 1 less fortnight than we continue to work, then add rest of pay cycle (14-days_in_pay_fortnight)
|
||||||
|
key_dates['D_quit_date'] = (now+timedelta(weeks=2*(finance['D_Num_fortnights_pay']-1))+timedelta(days=(14-days_in_pay_fortnight))).strftime('%Y-%m-%d')
|
||||||
|
|
||||||
|
# use lease date
|
||||||
|
if finance['Ioniq6_future'] == LEASE:
|
||||||
|
key_dates['D_hyundai_owned'] = car_balloon_date.strftime('%Y-%m-%d')
|
||||||
|
# use buyout date
|
||||||
|
else:
|
||||||
|
key_dates['D_hyundai_owned'] = finance['Car_buyout_date']
|
||||||
|
|
||||||
|
print( f"kd={key_dates}" )
|
||||||
|
return key_dates
|
||||||
|
|
||||||
|
|||||||
12
main.py
12
main.py
@@ -1,6 +1,6 @@
|
|||||||
# main.py
|
# main.py
|
||||||
from flask import Flask, render_template, request, redirect, url_for, Response, jsonify
|
from flask import Flask, render_template, request, redirect, url_for, Response, jsonify
|
||||||
from calc import calculate_savings_depletion
|
from calc import calculate_savings_depletion, calc_key_dates
|
||||||
from db import init_db, get_finance_data, update_finance, get_budget_data, insert_cset, get_comp_set_data, get_comp_set_options, get_bill_freqs
|
from db import init_db, get_finance_data, update_finance, get_budget_data, insert_cset, get_comp_set_data, get_comp_set_options, get_bill_freqs
|
||||||
from db import get_bill_data, new_bill, update_bill_data, delete_bill
|
from db import get_bill_data, new_bill, update_bill_data, delete_bill
|
||||||
from db import get_bill_ui, save_ui
|
from db import get_bill_ui, save_ui
|
||||||
@@ -145,14 +145,20 @@ def update():
|
|||||||
|
|
||||||
@app.route('/bills')
|
@app.route('/bills')
|
||||||
def DisplayBillData():
|
def DisplayBillData():
|
||||||
|
finance_data = get_finance_data()
|
||||||
|
# work out when D quits, when car is owned
|
||||||
|
key_dates = calc_key_dates( finance_data )
|
||||||
bill_data = get_bill_data("order_by_bill_type_then_date")
|
bill_data = get_bill_data("order_by_bill_type_then_date")
|
||||||
bill_types = get_bill_types()
|
bill_types = get_bill_types()
|
||||||
bill_freqs = get_bill_freqs()
|
bill_freqs = get_bill_freqs()
|
||||||
bill_ui = get_bill_ui()
|
bill_ui = get_bill_ui()
|
||||||
bill_info=process_bill_data(bill_data, bill_types, bill_freqs)
|
# take bill data, AND work out estimated future bills - process this into the bill_info array,
|
||||||
|
bill_info=process_bill_data(bill_data, bill_types, bill_freqs, key_dates)
|
||||||
|
# get an array of the total costs of bills each year - purely cosmetic (using bill_info)
|
||||||
total=calc_future_totals(bill_info, bill_types)
|
total=calc_future_totals(bill_info, bill_types)
|
||||||
|
# update/re-get bill_data now that new estimated bills have been added
|
||||||
bill_data = get_bill_data("order_by_bill_type_then_date")
|
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 )
|
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, key_dates=key_dates )
|
||||||
|
|
||||||
@app.route('/newbilltype', methods=['POST'])
|
@app.route('/newbilltype', methods=['POST'])
|
||||||
def InsertBillType():
|
def InsertBillType():
|
||||||
|
|||||||
@@ -152,7 +152,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<div class="row mt-4 highcharts-dark" id="container" style="width:100%; height:400px;"></div>
|
<div class="row mt-4 highcharts-dark" id="container" style="width:100%; height:800px;"></div>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
// make these global so we can also use them in the /save route (via modal)
|
// make these global so we can also use them in the /save route (via modal)
|
||||||
const savingsData = JSON.parse('{{ savings | tojson }}');
|
const savingsData = JSON.parse('{{ savings | tojson }}');
|
||||||
|
|||||||
Reference in New Issue
Block a user