Compare commits

...

26 Commits

Author SHA1 Message Date
71606035fd fix bug where growth is not calculated properly for future bills / hangover from when I assumed only simple growth as that was all we had before I added new growth menu options 2026-02-11 19:29:07 +11:00
b8c1edc084 fixed bug where insert cset did not show it in menu until a full reload 2026-02-11 12:02:09 +11:00
f0fee15548 new bug when creating new cset 2026-02-10 21:47:43 +11:00
20239d72c8 put improved foreign key constraints on DB to fix bug where when I delete a cset, that was being used to compare_to, it breaks 2026-02-10 21:35:41 +11:00
e3d2d8ea08 remove jquery filter for nav-tabs now we are using nav-pills in vertical mode, it was unnecessary anyway, only one div had navlinks, so just using the rest of the filter, and this fixes the BUG too 2026-02-10 19:14:43 +11:00
8446f59740 can now scroll with wheel in graphs 2026-02-10 19:10:25 +11:00
3a04b8321c 3 x new BUGS 2026-02-10 19:10:02 +11:00
037a9c2d87 add scroll todo 2026-02-10 19:09:29 +11:00
e7a3cb3d7d change formatting of fields so that we cater for scroll-bar or no scroll-bar when we show graph or not in lower part of UI, this stops the fields wrapping onto the next line when the scroll bar appears 2026-02-06 12:12:58 +11:00
2ba2ece1d0 tried to be smarter with tax, decided in the end to use non-code to come up with a figure and hard-code, hopefully not an issue soon anyway :) 2026-02-06 12:12:06 +11:00
0a0a7b321b remove warning / use r"" for regexp string" 2026-02-06 12:11:15 +11:00
85a53c8c5f minor update for bills, this needs to be dynamic 2026-02-06 12:10:31 +11:00
8e2f0ae340 take into account ENV var for snapshots 2026-02-06 12:09:36 +11:00
1cf835b7e7 refined label positions, and tweaked current ME balance 2026-02-06 12:09:02 +11:00
e104dd8270 Applying several hacks to draw labels better -- still not close to great, but bearable now. First we consider 0 amts as non-negative for annotations so they go up not down on the graph :) Second, I am applying a rough approach of knowing where the last label was drawn and draw below that, only do this for negative amts, and even then the difference between y-coords in the y-axis scale and pixels for offsets of labels, just are too annoying 2026-01-18 22:23:04 +11:00
a46b8f895a sort annotations so the historical annotations are drawn first, so up/down labels are mostly working properly 2026-01-18 22:21:14 +11:00
09de41e093 updated BUGS 2026-01-18 00:33:56 +11:00
9c02bc94ff added a favicon, moved horizontal nav-tabs for bills to a vertical nav-pills 2026-01-18 00:33:13 +11:00
94f4108a3e add_historical_annotations() 2026-01-17 22:53:08 +11:00
8d2809fdd9 some minor clean-ups and make ANNOT_LIMIT constant, and then adding in historical annotations 2026-01-17 22:52:37 +11:00
2d1dcfffd9 use media to tweak fonts to even smaller when I am on my laptop 2026-01-17 22:51:19 +11:00
3b3c42caab putting this in the repo, so I dont have to reproduce it / jic 2026-01-17 21:20:57 +11:00
b81502e6db removed debug 2026-01-17 19:41:03 +11:00
7494c0ae16 extra clarification on FIRST_YEAR fix needed 2026-01-17 19:40:54 +11:00
e05b2c7b5b Major change: I have added finance_history
* pulled old values of data via restic backups
    * inserted them into a new finance_history table
    * added a finplan user, use of sudo & better ENV (container/production) & wrapper.sh into Dockerfile (like I do for other projects)
    * recalculate the bills / Living Expenses now we have real bills for a year
    * remove tax back for now (need to handle quit date vs. end of financial year better)
    * hard-coded / hacked in 2026 for pay cycle dates / should be dynamic, but not sure I'll work in 2027+
    * refactor front-end to handle 2026 as the current year / its more or less dynamic (via hard-coded FIRST_YEAR) variable - could not use datetime, as it was in late Dec. when I noticed the issue ('next pay' was in 2026, current year was 2025)
    * also added history to graphs, changed formatting to make the history /
    * savings projections to be orannge with circles, but historical is a solid line, future is a dash, also made all lines have lineWidth: 1 for aesthetics
2026-01-17 19:28:24 +11:00
2517f8e9b9 fix up inconsistent use of col-1 and col 2026-01-17 19:27:28 +11:00
15 changed files with 791 additions and 101 deletions

5
BUGS
View File

@@ -1,4 +1,9 @@
* can put in dumb dates - DO SOME INPUT VALIDATION, *sigh*
- e.g. 0026-02-19 for a Gas bill
* kayo bills are wrong in between normal bills * kayo bills are wrong in between normal bills
* added an electricity bill by accident for 2018, that kills lots :( * added an electricity bill by accident for 2018, that kills lots :(
- something to do with missing year of data in quarterly bills - still an issue - something to do with missing year of data in quarterly bills - still an issue
* if change a bill (like Amazon), then its future estimates don't update

View File

@@ -3,13 +3,15 @@ FROM python:latest
# this forces /code to be owned by the user specified in the docker-compose file, we could ignore issues without this (but I am writing log files to the current dir with gunicorn as a non-priv'd user) # this forces /code to be owned by the user specified in the docker-compose file, we could ignore issues without this (but I am writing log files to the current dir with gunicorn as a non-priv'd user)
ARG USERID ARG USERID
ARG GROUPID ARG GROUPID
RUN apt-get update && apt-get install sqlite3 && apt-get dist-upgrade -y RUN apt-get update && apt-get -y install cron sqlite3 sudo && apt-get dist-upgrade -y
WORKDIR /code WORKDIR /code
COPY requirements.txt . COPY requirements.txt .
RUN pip3 install -r requirements.txt COPY crontab /etc/crontab
RUN pip3 install --upgrade pip && pip3 install -r requirements.txt
RUN groupadd -g ${GROUPID} finplan && useradd -m -u ${USERID} -g ${GROUPID} finplan
COPY . . COPY . .
RUN chown -R ${USERID}:${GROUPID} /code RUN chown -R finplan:finplan /code
EXPOSE 8080 EXPOSE 80
CMD gunicorn --bind=0.0.0.0:8080 --workers=2 --threads=2 main:app --error-logfile /code/gunicorn.error.log --access-logfile /code/gunicorn.log --capture-output # NOTE, wrapper.sh will use sudo to work in PROD and DEV AS the correct
# comment out the gunicorn line & uncomment the sleep so you can run gunicorn by hand in case it does not start on init (via docker exec...) # BOOK_UID/BOOK_GID as pybook user and group
#CMD sleep 99999 CMD ["./wrapper.sh"]

19
TODO
View File

@@ -1,24 +1,17 @@
bills html, and growth types are very lame... could I do something more like: bills:
bill for the year (when removed from LE, should be dynamic)
bills html, and growth types are poor code repitition / lame... could I do something more like:
{% for gt in growth %} {% for gt in growth %}
{% if gt.name == 'Min' %} {% if gt.name == 'Min' %}
<option value='min' <option value='min'
{% if bt.which_growth == gt.name %}selected{% endif %} {% if bt.which_growth == gt.name %}selected{% endif %}
>{{'%.2f'|format(bt.ann_growth_min)}}% {{gt.name}}</option> >{{'%.2f'|format(bt.ann_growth_min)}}% {{gt.name}}</option>
CALC: CALC:
* if I quit at different times of the financial year, technically the amount I earn will be taxed * if I quit at different times of the financial year, technically the amount I earn will be taxed
differently, but hard to calc - slides around with tax brackets in future differently, but hard to calc - slides around with tax brackets in future
UI: * still get double health insurance bills sometimes (just viewing a new date might trigger this??? or at least when I changed years)
* to allow <yr> total on bill summary, need to re-work annual growth to a drop-down
- [DONE] mock-up
- need to change 'which growth' to accommodate new growth models (cpi, override*)
- [DONE] do this in DB with new table - then don't do crazy pattern matching/making up overrides in the UI code
- get UI to use bill_growth_types table
- get UseGrowth() to use bill_growth_types table
For bills: UI:
* 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

View File

@@ -304,7 +304,7 @@ def get_growth_value( bt, bill_type ):
finance_data = get_finance_data() finance_data = get_finance_data()
return finance_data['Inflation'] return finance_data['Inflation']
else: else:
match = re.match("flat-(\d+)", which ) match = re.match(r"flat-(\d+)", which )
if match: if match:
return int(match.group(1)) return int(match.group(1))
else: else:
@@ -643,8 +643,7 @@ def recalcFutureBills():
for fb in future_car_bills: for fb in future_car_bills:
amt=fb['amount'] amt=fb['amount']
bt=fb['bill_type'] bt=fb['bill_type']
# only can use simple growth as its a future bill growth = get_growth_value( bill_types, bt )
growth=bill_types[bt]['ann_growth_simple']
# factor in growth for next bills # factor in growth for next bills
for yr in range( int(car_yr), END_YEAR+1 ): for yr in range( int(car_yr), END_YEAR+1 ):
new_date=f"{yr}-{car_mmdd}" new_date=f"{yr}-{car_mmdd}"
@@ -661,7 +660,7 @@ def recalcFutureBills():
# deal with future bills due to their starting dates being dynamic # deal with future bills due to their starting dates being dynamic
amt=fb['amount'] amt=fb['amount']
bt=fb['bill_type'] bt=fb['bill_type']
growth=bill_types[bt]['ann_growth_simple'] growth = get_growth_value( bill_types, bt )
num_ann_bills= bf_id_num[bt_id_freq[bt]] num_ann_bills= bf_id_num[bt_id_freq[bt]]
if num_ann_bills == 1: if num_ann_bills == 1:
# factor in growth for next bill # factor in growth for next bill

80
calc.py
View File

@@ -1,12 +1,14 @@
# calc.py # calc.py
from datetime import datetime, timedelta from datetime import datetime, timedelta
from defines import END_YEAR from defines import END_YEAR
from db import get_historical_data
# GLOBAL CONSTANTS # GLOBAL CONSTANTS
LEASE = 0 LEASE = 0
ANNOT_LIMIT = 1000
# Dates that don't change # Dates that don't change
first_pay_date = datetime(2025,1,8) first_pay_date = datetime(2026,1,8)
school_fees_date = datetime(2025, 12, 5) school_fees_date = datetime(2025, 12, 5)
car_balloon_date = datetime(2026, 11, 15) car_balloon_date = datetime(2026, 11, 15)
mich_present_date = datetime(2026,10,15) mich_present_date = datetime(2026,10,15)
@@ -20,7 +22,7 @@ def bill_amount_today(finance, day, bill_data, bt_id_name, total ):
# there may be more than one bill on this day, keep add amount and keep going in loop # there may be more than one bill on this day, keep add amount and keep going in loop
if b['bill_date'] == day_str: if b['bill_date'] == day_str:
amt += b['amount'] amt += b['amount']
if b['amount'] > 1000: if b['amount'] > ANNOT_LIMIT:
n=bt_id_name[ b['bill_type'] ] n=bt_id_name[ b['bill_type'] ]
print( f"bill_amt_today {n} for {day_str} has amt={b['amount']}" ) print( f"bill_amt_today {n} for {day_str} has amt={b['amount']}" )
add_annotation(finance, day, total-b['amount'], -b['amount'], f"Pay {n}" ) add_annotation(finance, day, total-b['amount'], -b['amount'], f"Pay {n}" )
@@ -31,9 +33,8 @@ def bill_amount_today(finance, day, bill_data, bt_id_name, total ):
return amt return amt
def add_annotation(finance, dt, total, delta, text): def add_annotation(finance, dt, total, delta, text):
# dont add an annotation for small changes (jic)
tm = dt.timestamp() * 1000 tm = dt.timestamp() * 1000
if delta > 0: if delta >= 0:
text += f": ${int(abs(delta))}" text += f": ${int(abs(delta))}"
else: else:
text += f": -${int(abs(delta))}" text += f": -${int(abs(delta))}"
@@ -65,7 +66,7 @@ def calculate_savings_depletion(finance, bill_data, bill_type):
CBA_price = finance['CBA_price'] CBA_price = finance['CBA_price']
Ioniq6_future = finance['Ioniq6_future'] Ioniq6_future = finance['Ioniq6_future']
### COMPLEX tax implications with my leave I have not taken. It will be taxed in the year I 'quit' ### ### COMPLEX tax implications with my leave I have not taken. It will be taxed in the financial year I 'quit' ###
# leave in days, 10 business days to a fortnight, # leave in days, 10 business days to a fortnight,
# paid before tax I earn $7830.42 / fortnight. Tax on that will be at 37% or $4933.16 after tax # paid before tax I earn $7830.42 / fortnight. Tax on that will be at 37% or $4933.16 after tax
@@ -75,26 +76,32 @@ def calculate_savings_depletion(finance, bill_data, bill_type):
# this is what I now earn before-tax (and I *THINK* vehicle allowance won't be paid X 12 weeks) # this is what I now earn before-tax (and I *THINK* vehicle allowance won't be paid X 12 weeks)
pre_tax_D_earning = 8143.65 pre_tax_D_earning = 8143.65
# whenever I leave, I get 12 weeks (or 60 business days) + whatever leave they owe me # whenever I quit, I get my leave paid out and I get 12 weeks (or 6 pays) -- notice
payout = ((60+D_leave_owed_in_days)/bus_days_in_fortnight) * pre_tax_D_earning payout = ((D_leave_owed_in_days/bus_days_in_fortnight) + 6) * pre_tax_D_earning
# just use redundancy calc... # just use redundancy calc...
payout = 83115.84 # payout = 83115.84
print( f"leave payout gross={payout}" ) print( f"leave payout gross={payout}" )
# However, if I quit in the next fin year - tax for 2025 will be: $4,288 plus 30c for each $1 over $45,000 # However, if I quit in the next fin year - tax will be: $4,288 plus 30c for each $1 over $45,000
# (assuming the 7830.42 * ~90/bus_days_in_fortnight = ~ $64k - > 45k and < $135k bracket is 30%) # (assuming the 7830.42 * ~90/bus_days_in_fortnight = ~ $64k - > 45k and < $135k bracket is 30% OR .37c for $135->$190k)
# - IF I am close to $190k+, just wait a month and quit in new financial year
# Given, I probably can't stop Deakin doing PAYG deductions, I won't get # Given, I probably can't stop Deakin doing PAYG deductions, I won't get
# the tax back until the end of the financial year, so work out the # the tax back until the end of the financial year, so work out the
# amount of tax I will get back info: tax_diff_D_leave # amount of tax I will get back into: tax_diff_D_leave
tax_on_leave = (payout - 45000)*.37 + 4288 tax_on_leave = (payout - 45000)*.30 + 4288
D_leave_after_tax = payout - tax_on_leave D_leave_after_tax = payout - tax_on_leave
# just use redunancy calc... print(f"my calc would say D_leave_after_tax = {D_leave_after_tax}" )
D_leave_after_tax = 56518.77
# just use quick google/calc - it claims tax rules apply and are capped at 32% - its possible I get more like 75k then pay tax in July?
D_leave_after_tax = 59000
tax_diff_D_leave = payout - D_leave_after_tax tax_diff_D_leave = payout - D_leave_after_tax
### FIXME: for now, assume no tax back after leave - see above comment
tax_diff_D_leave = 0
print( f"tax_diff_D_leave: {tax_diff_D_leave}") print( f"tax_diff_D_leave: {tax_diff_D_leave}")
### leave / tax items finished ### ### leave / tax items finished ###
@@ -138,7 +145,7 @@ def calculate_savings_depletion(finance, bill_data, bill_type):
car_buyout_date = datetime.strptime( finance['Car_buyout_date'], "%Y-%m-%d") car_buyout_date = datetime.strptime( finance['Car_buyout_date'], "%Y-%m-%d")
# to force deakin pay cycles to match reality, we work from the 8th of Jan as our "day-zero" so we are paid on the 8/1/25, 22/1/25, etc. # to force deakin pay cycles to match reality, we work from the 8th of Jan as our "day-zero" so we are paid on the 8/1/25, 22/1/25, etc.
days_count = ( current_date - datetime(2025,1,1) ).days days_count = ( current_date - datetime(2026,1,1) ).days
# Track the fortnight, and monthly interest # Track the fortnight, and monthly interest
fortnight_income = 0 fortnight_income = 0
@@ -219,7 +226,7 @@ def calculate_savings_depletion(finance, bill_data, bill_type):
# monthly increase living expenses by a monthly inflation multiplier # monthly increase living expenses by a monthly inflation multiplier
Living_Expenses += (Inflation/100.0)/12 * Living_Expenses Living_Expenses += (Inflation/100.0)/12 * Living_Expenses
daily_living_expenses = Living_Expenses / 365 daily_living_expenses = Living_Expenses / 365
# print(f"{current_date}: Living Exp inceased - ${Living_Expenses}") print(f"{current_date}: Living Exp inceased - ${Living_Expenses}")
if current_date.date() == school_fees_date.date(): if current_date.date() == school_fees_date.date():
current_savings -= School_Fees current_savings -= School_Fees
@@ -312,3 +319,44 @@ def calc_key_dates( finance ):
return key_dates return key_dates
################################################################################
# go through finance_history table, find big items to make annoations from
################################################################################
def add_historical_annotations( finance ):
added={}
hist=get_historical_data()
day=hist[0]['M_payout_date'];
amt=hist[0]['M_payout'];
dt = datetime.strptime(day, "%Y-%m-%d")
# cover Mandys resignation
add_annotation(finance, dt, hist[0]['Savings']+amt, amt, "M Resigned" )
# cover O/S trip
for h in hist:
if 'Overseas_trip' in h and h['Overseas_trip']:
last_mpd=h['Overseas_trip_date']
last_mpd_savings=h['Savings']
snap_dt=datetime.strptime(h['snapshot_date'], "%Y-%m-%d")
# keep every savings value until we find the last one before the school fees are paid
if snap_dt < school_fees_date:
savings_b4_sfd = h['Savings']
dt = datetime.strptime(last_mpd, "%Y-%m-%d")
# HARDCODING this, based on post-analysis of CC charges (AND this dt is post most of the spend, so dont adjust)
amt = 33405.01
print( f"last_mpd_savings={last_mpd_savings}" )
add_annotation(finance, dt, last_mpd_savings, -amt, "O/S trip" )
print( f"should have added o/s trip (-{amt}) - lpd {last_mpd} == {dt}, savings = {last_mpd_savings}" )
# cover School Fees for 2025
amt = hist[0]['School_Fees']
print( f"savings_b4_sfd ={savings_b4_sfd}")
add_annotation(finance, school_fees_date, savings_b4_sfd-amt, -amt, "Pay school fees" )
# go through bills from oldest historical date until 'today' and add any > AMT_LIMIT
return

2
crontab Normal file
View File

@@ -0,0 +1,2 @@
# run once every 5 days or so
0 23 2-27/5 * * finplan cd /tmp && ENV="production" /code/snapshot.sh

14
db.py
View File

@@ -8,6 +8,8 @@ def connect_db(as_object):
conn = sqlite3.connect('/data/finance.db') conn = sqlite3.connect('/data/finance.db')
else: else:
conn = sqlite3.connect('./finance.db') conn = sqlite3.connect('./finance.db')
# allow deleting cset to clear our compare_to properly in finance table
conn.execute("PRAGMA foreign_keys = ON;")
if as_object: if as_object:
conn.row_factory = sqlite3.Row # This allows us to access columns by name conn.row_factory = sqlite3.Row # This allows us to access columns by name
return conn return conn
@@ -177,10 +179,20 @@ def get_finance_data():
conn.close() conn.close()
return dict(finance) return dict(finance)
def get_historical_data():
conn = connect_db(False)
# this treats the returns as dicts
conn.row_factory = sqlite3.Row
cur = conn.cursor()
cur.execute('SELECT * FROM finance_history order by snapshot_date')
hist = [dict(row) for row in cur.fetchall()]
conn.close()
return hist
def get_budget_data(finance_data): def get_budget_data(finance_data):
# annual bills - health ins (5k), rates (2.6), electricity (1.2), gas (2.1) - but 1.4 in 2025 due to EU trip, internet (1.6), car insurance (.7), rego (.8), house insurance (2.4), GFC (2.6), water (1.1), eweka (.1), phones (.5), melb. pollen (.03), nabu casa (.1) --- noting phone is elevated presuming I also go onto Aldi plan, but that there is no family discount, and health will be extra after stop working # annual bills - health ins (5k), rates (2.6), electricity (1.2), gas (2.1) - but 1.4 in 2025 due to EU trip, internet (1.6), car insurance (.7), rego (.8), house insurance (2.4), GFC (2.6), water (1.1), eweka (.1), phones (.5), melb. pollen (.03), nabu casa (.1) --- noting phone is elevated presuming I also go onto Aldi plan, but that there is no family discount, and health will be extra after stop working
# fudging below - its more like 15.2 + health, and really gas will be more than 2.1 than 1.4, so about 16+5 # fudging below - its more like 15.2 + health, and really gas will be more than 2.1 than 1.4, so about 16+5
bills = 21000 bills = 25321.03
BUDGET=[] BUDGET=[]
BUDGET.append( ('Bills', f"${bills:,.2f}") ) BUDGET.append( ('Bills', f"${bills:,.2f}") )
BUDGET.append( ('Buffer', f"${finance_data['CBA']*finance_data['CBA_price']+finance_data['TLS']*finance_data['TLS_price']:,.2f}") ) BUDGET.append( ('Buffer', f"${finance_data['CBA']*finance_data['CBA_price']+finance_data['TLS']*finance_data['TLS_price']:,.2f}") )

491
history.sql Normal file
View File

@@ -0,0 +1,491 @@
drop table finance_history;
create table finance_history (
snapshot_date NUM PRIMARY KEY,
D_Salary INT,
M_Salary INT,
D_Num_fortnights_pay INT,
M_Num_fortnights_pay INT,
M_payout INT,
School_Fees INT,
Car_loan_via_pay INT,
Car_loan INT,
Car_balloon INT,
Car_buyout INT,
Living_Expenses INT,
Savings INT,
Interest_Rate REAL,
Inflation REAL,
Mich_present INT,
Overseas_trip INT,
Mark_reno INT,
D_leave_owed_in_days REAL,
D_TLS_shares INT,
M_TLS_shares INT,
D_CBA_shares INT,
TLS_price REAL,
CBA_price REAL,
Overseas_trip_date NUM,
Mark_reno_date NUM,
Car_buyout_date NUM,
M_payout_date NUM,
Sell_shares INT,
compare_to INT,
Ioniq6_future INT
);
INSERT OR IGNORE INTO finance_history (snapshot_date) VALUES ('2024-12-31');
UPDATE finance_history SET D_Salary = '4762.29' WHERE snapshot_date = '2024-12-31';
UPDATE finance_history SET M_salary = '1962.56' WHERE snapshot_date = '2024-12-31';
UPDATE finance_history SET D_Num_fortnights_pay = '6' WHERE snapshot_date = '2024-12-31';
UPDATE finance_history SET M_Num_fortnights_pay = '1' WHERE snapshot_date = '2024-12-31';
UPDATE finance_history SET School_Fees = '22000' WHERE snapshot_date = '2024-12-31';
UPDATE finance_history SET Car_loan_via_pay = '620' WHERE snapshot_date = '2024-12-31';
UPDATE finance_history SET Car_loan = '1001.12' WHERE snapshot_date = '2024-12-31';
UPDATE finance_history SET Car_balloon = '45824.68' WHERE snapshot_date = '2024-12-31';
UPDATE finance_history SET Living_Expenses = '66000' WHERE snapshot_date = '2024-12-31';
UPDATE finance_history SET Savings = '296000' WHERE snapshot_date = '2024-12-31';
UPDATE finance_history SET Interest_Rate = '4.75' WHERE snapshot_date = '2024-12-31';
UPDATE finance_history SET Inflation = '3.9' WHERE snapshot_date = '2024-12-31';
UPDATE finance_history SET M_payout = '112000' WHERE snapshot_date = '2024-12-31';
UPDATE finance_history SET Mich_present = '10000' WHERE snapshot_date = '2024-12-31';
UPDATE finance_history SET Overseas_trip = '25000' WHERE snapshot_date = '2024-12-31';
UPDATE finance_history SET Mark_reno = '10000' WHERE snapshot_date = '2024-12-31';
UPDATE finance_history SET D_leave_owed_in_days = '90.6' WHERE snapshot_date = '2024-12-31';
UPDATE finance_history SET D_TLS_shares = '1000' WHERE snapshot_date = '2024-12-31';
UPDATE finance_history SET M_TLS_shares = '750' WHERE snapshot_date = '2024-12-31';
UPDATE finance_history SET D_CBA_shares = '1095' WHERE snapshot_date = '2024-12-31';
UPDATE finance_history SET TLS_price = '4.03' WHERE snapshot_date = '2024-12-31';
UPDATE finance_history SET CBA_price = '156.21' WHERE snapshot_date = '2024-12-31';
UPDATE finance_history SET Overseas_trip_date = '2025-06-01' WHERE snapshot_date = '2024-12-31';
UPDATE finance_history SET Mark_reno_date = '2025-06-01' WHERE snapshot_date = '2024-12-31';
UPDATE finance_history SET M_payout_date = '2025-01-20' WHERE snapshot_date = '2024-12-31';
UPDATE finance_history SET Sell_shares = '6' WHERE snapshot_date = '2024-12-31';
INSERT OR IGNORE INTO finance_history (snapshot_date) VALUES ('2025-01-31');
UPDATE finance_history SET D_Salary = '4762.29' WHERE snapshot_date = '2025-01-31';
UPDATE finance_history SET D_Num_fortnights_pay = '6' WHERE snapshot_date = '2025-01-31';
UPDATE finance_history SET School_Fees = '22000' WHERE snapshot_date = '2025-01-31';
UPDATE finance_history SET Car_loan_via_pay = '620' WHERE snapshot_date = '2025-01-31';
UPDATE finance_history SET Car_loan = '1001.12' WHERE snapshot_date = '2025-01-31';
UPDATE finance_history SET Car_balloon = '45824.68' WHERE snapshot_date = '2025-01-31';
UPDATE finance_history SET Living_Expenses = '83000' WHERE snapshot_date = '2025-01-31';
UPDATE finance_history SET Savings = '412000' WHERE snapshot_date = '2025-01-31';
UPDATE finance_history SET Interest_Rate = '5.0' WHERE snapshot_date = '2025-01-31';
UPDATE finance_history SET Inflation = '3.9' WHERE snapshot_date = '2025-01-31';
UPDATE finance_history SET Mich_present = '10000' WHERE snapshot_date = '2025-01-31';
UPDATE finance_history SET Overseas_trip = '32000' WHERE snapshot_date = '2025-01-31';
UPDATE finance_history SET Mark_reno = '10000' WHERE snapshot_date = '2025-01-31';
UPDATE finance_history SET D_leave_owed_in_days = '90.6' WHERE snapshot_date = '2025-01-31';
UPDATE finance_history SET D_TLS_shares = '1000' WHERE snapshot_date = '2025-01-31';
UPDATE finance_history SET M_TLS_shares = '750' WHERE snapshot_date = '2025-01-31';
UPDATE finance_history SET D_CBA_shares = '1095' WHERE snapshot_date = '2025-01-31';
UPDATE finance_history SET TLS_price = '3.99' WHERE snapshot_date = '2025-01-31';
UPDATE finance_history SET CBA_price = '160.61' WHERE snapshot_date = '2025-01-31';
UPDATE finance_history SET Overseas_trip_date = '2025-06-01' WHERE snapshot_date = '2025-01-31';
UPDATE finance_history SET Mark_reno_date = '2025-09-01' WHERE snapshot_date = '2025-01-31';
UPDATE finance_history SET Sell_shares = '6' WHERE snapshot_date = '2025-01-31';
INSERT OR IGNORE INTO finance_history (snapshot_date) VALUES ('2025-02-28');
UPDATE finance_history SET D_Salary = '4762.29' WHERE snapshot_date = '2025-02-28';
UPDATE finance_history SET D_Num_fortnights_pay = '10' WHERE snapshot_date = '2025-02-28';
UPDATE finance_history SET School_Fees = '22000' WHERE snapshot_date = '2025-02-28';
UPDATE finance_history SET Car_loan_via_pay = '620' WHERE snapshot_date = '2025-02-28';
UPDATE finance_history SET Car_loan = '2412' WHERE snapshot_date = '2025-02-28';
UPDATE finance_history SET Car_balloon = '45824.68' WHERE snapshot_date = '2025-02-28';
UPDATE finance_history SET Car_buyout = '83738.74' WHERE snapshot_date = '2025-02-28';
UPDATE finance_history SET Living_Expenses = '84000' WHERE snapshot_date = '2025-02-28';
UPDATE finance_history SET Savings = '421271.5' WHERE snapshot_date = '2025-02-28';
UPDATE finance_history SET Interest_Rate = '5.0' WHERE snapshot_date = '2025-02-28';
UPDATE finance_history SET Inflation = '3.0' WHERE snapshot_date = '2025-02-28';
UPDATE finance_history SET Mich_present = '10000' WHERE snapshot_date = '2025-02-28';
UPDATE finance_history SET Overseas_trip = '30000' WHERE snapshot_date = '2025-02-28';
UPDATE finance_history SET Mark_reno = '10000' WHERE snapshot_date = '2025-02-28';
UPDATE finance_history SET D_leave_owed_in_days = '103.0' WHERE snapshot_date = '2025-02-28';
UPDATE finance_history SET D_TLS_shares = '1000' WHERE snapshot_date = '2025-02-28';
UPDATE finance_history SET M_TLS_shares = '750' WHERE snapshot_date = '2025-02-28';
UPDATE finance_history SET D_CBA_shares = '1095' WHERE snapshot_date = '2025-02-28';
UPDATE finance_history SET TLS_price = '3.9' WHERE snapshot_date = '2025-02-28';
UPDATE finance_history SET CBA_price = '158.9' WHERE snapshot_date = '2025-02-28';
UPDATE finance_history SET Overseas_trip_date = '2025-06-01' WHERE snapshot_date = '2025-02-28';
UPDATE finance_history SET Mark_reno_date = '2025-09-01' WHERE snapshot_date = '2025-02-28';
UPDATE finance_history SET Car_buyout_date = '2025-02-23' WHERE snapshot_date = '2025-02-28';
UPDATE finance_history SET Sell_shares = '5' WHERE snapshot_date = '2025-02-28';
UPDATE finance_history SET compare_to = '0' WHERE snapshot_date = '2025-02-28';
UPDATE finance_history SET Ioniq6_future = '0' WHERE snapshot_date = '2025-02-28';
INSERT OR IGNORE INTO finance_history (snapshot_date) VALUES ('2025-03-31');
UPDATE finance_history SET D_Salary = '4762.29' WHERE snapshot_date = '2025-03-31';
UPDATE finance_history SET D_Num_fortnights_pay = '15' WHERE snapshot_date = '2025-03-31';
UPDATE finance_history SET School_Fees = '22000' WHERE snapshot_date = '2025-03-31';
UPDATE finance_history SET Car_loan_via_pay = '620' WHERE snapshot_date = '2025-03-31';
UPDATE finance_history SET Car_loan = '2412' WHERE snapshot_date = '2025-03-31';
UPDATE finance_history SET Car_balloon = '45824.68' WHERE snapshot_date = '2025-03-31';
UPDATE finance_history SET Car_buyout = '83738.74' WHERE snapshot_date = '2025-03-31';
UPDATE finance_history SET Living_Expenses = '80000' WHERE snapshot_date = '2025-03-31';
UPDATE finance_history SET Savings = '425318.76' WHERE snapshot_date = '2025-03-31';
UPDATE finance_history SET Interest_Rate = '4.75' WHERE snapshot_date = '2025-03-31';
UPDATE finance_history SET Inflation = '2.6' WHERE snapshot_date = '2025-03-31';
UPDATE finance_history SET Mich_present = '10000' WHERE snapshot_date = '2025-03-31';
UPDATE finance_history SET Overseas_trip = '50000' WHERE snapshot_date = '2025-03-31';
UPDATE finance_history SET Mark_reno = '10000' WHERE snapshot_date = '2025-03-31';
UPDATE finance_history SET D_leave_owed_in_days = '81.7' WHERE snapshot_date = '2025-03-31';
UPDATE finance_history SET D_TLS_shares = '1000' WHERE snapshot_date = '2025-03-31';
UPDATE finance_history SET M_TLS_shares = '750' WHERE snapshot_date = '2025-03-31';
UPDATE finance_history SET D_CBA_shares = '1095' WHERE snapshot_date = '2025-03-31';
UPDATE finance_history SET TLS_price = '4.15' WHERE snapshot_date = '2025-03-31';
UPDATE finance_history SET CBA_price = '151.0' WHERE snapshot_date = '2025-03-31';
UPDATE finance_history SET Overseas_trip_date = '2025-06-01' WHERE snapshot_date = '2025-03-31';
UPDATE finance_history SET Mark_reno_date = '2025-09-01' WHERE snapshot_date = '2025-03-31';
UPDATE finance_history SET Car_buyout_date = '2025-03-25' WHERE snapshot_date = '2025-03-31';
UPDATE finance_history SET Sell_shares = '4' WHERE snapshot_date = '2025-03-31';
UPDATE finance_history SET compare_to = '10' WHERE snapshot_date = '2025-03-31';
UPDATE finance_history SET Ioniq6_future = '0' WHERE snapshot_date = '2025-03-31';
INSERT OR IGNORE INTO finance_history (snapshot_date) VALUES ('2025-04-30');
UPDATE finance_history SET D_Salary = '4762.29' WHERE snapshot_date = '2025-04-30';
UPDATE finance_history SET D_Num_fortnights_pay = '10' WHERE snapshot_date = '2025-04-30';
UPDATE finance_history SET School_Fees = '24000' WHERE snapshot_date = '2025-04-30';
UPDATE finance_history SET Car_loan_via_pay = '620' WHERE snapshot_date = '2025-04-30';
UPDATE finance_history SET Car_loan = '2412' WHERE snapshot_date = '2025-04-30';
UPDATE finance_history SET Car_balloon = '45824.68' WHERE snapshot_date = '2025-04-30';
UPDATE finance_history SET Car_buyout = '83738.74' WHERE snapshot_date = '2025-04-30';
UPDATE finance_history SET Living_Expenses = '80000' WHERE snapshot_date = '2025-04-30';
UPDATE finance_history SET Savings = '424875.26' WHERE snapshot_date = '2025-04-30';
UPDATE finance_history SET Interest_Rate = '4.75' WHERE snapshot_date = '2025-04-30';
UPDATE finance_history SET Inflation = '2.4' WHERE snapshot_date = '2025-04-30';
UPDATE finance_history SET Mich_present = '10000' WHERE snapshot_date = '2025-04-30';
UPDATE finance_history SET Overseas_trip = '60000' WHERE snapshot_date = '2025-04-30';
UPDATE finance_history SET Mark_reno = '10000' WHERE snapshot_date = '2025-04-30';
UPDATE finance_history SET D_leave_owed_in_days = '76.85' WHERE snapshot_date = '2025-04-30';
UPDATE finance_history SET D_TLS_shares = '1000' WHERE snapshot_date = '2025-04-30';
UPDATE finance_history SET M_TLS_shares = '750' WHERE snapshot_date = '2025-04-30';
UPDATE finance_history SET D_CBA_shares = '1111' WHERE snapshot_date = '2025-04-30';
UPDATE finance_history SET TLS_price = '4.52' WHERE snapshot_date = '2025-04-30';
UPDATE finance_history SET CBA_price = '163.32' WHERE snapshot_date = '2025-04-30';
UPDATE finance_history SET Overseas_trip_date = '2025-06-01' WHERE snapshot_date = '2025-04-30';
UPDATE finance_history SET Mark_reno_date = '2025-09-01' WHERE snapshot_date = '2025-04-30';
UPDATE finance_history SET Car_buyout_date = '2025-03-25' WHERE snapshot_date = '2025-04-30';
UPDATE finance_history SET Sell_shares = '5' WHERE snapshot_date = '2025-04-30';
UPDATE finance_history SET compare_to = '6' WHERE snapshot_date = '2025-04-30';
UPDATE finance_history SET Ioniq6_future = '0' WHERE snapshot_date = '2025-04-30';
INSERT OR IGNORE INTO finance_history (snapshot_date) VALUES ('2025-05-31');
UPDATE finance_history SET D_Salary = '4762.29' WHERE snapshot_date = '2025-05-31';
UPDATE finance_history SET D_Num_fortnights_pay = '4' WHERE snapshot_date = '2025-05-31';
UPDATE finance_history SET School_Fees = '24000' WHERE snapshot_date = '2025-05-31';
UPDATE finance_history SET Car_loan_via_pay = '620' WHERE snapshot_date = '2025-05-31';
UPDATE finance_history SET Car_loan = '2412' WHERE snapshot_date = '2025-05-31';
UPDATE finance_history SET Car_balloon = '45824.68' WHERE snapshot_date = '2025-05-31';
UPDATE finance_history SET Car_buyout = '83738.74' WHERE snapshot_date = '2025-05-31';
UPDATE finance_history SET Living_Expenses = '80000' WHERE snapshot_date = '2025-05-31';
UPDATE finance_history SET Savings = '402637.26' WHERE snapshot_date = '2025-05-31';
UPDATE finance_history SET Interest_Rate = '4.5' WHERE snapshot_date = '2025-05-31';
UPDATE finance_history SET Inflation = '2.4' WHERE snapshot_date = '2025-05-31';
UPDATE finance_history SET Mich_present = '10000' WHERE snapshot_date = '2025-05-31';
UPDATE finance_history SET Overseas_trip = '30000' WHERE snapshot_date = '2025-05-31';
UPDATE finance_history SET Mark_reno = '10000' WHERE snapshot_date = '2025-05-31';
UPDATE finance_history SET D_leave_owed_in_days = '76.85' WHERE snapshot_date = '2025-05-31';
UPDATE finance_history SET D_TLS_shares = '1000' WHERE snapshot_date = '2025-05-31';
UPDATE finance_history SET M_TLS_shares = '750' WHERE snapshot_date = '2025-05-31';
UPDATE finance_history SET D_CBA_shares = '1111' WHERE snapshot_date = '2025-05-31';
UPDATE finance_history SET TLS_price = '4.75' WHERE snapshot_date = '2025-05-31';
UPDATE finance_history SET CBA_price = '173.84' WHERE snapshot_date = '2025-05-31';
UPDATE finance_history SET Overseas_trip_date = '2025-06-01' WHERE snapshot_date = '2025-05-31';
UPDATE finance_history SET Mark_reno_date = '2025-09-01' WHERE snapshot_date = '2025-05-31';
UPDATE finance_history SET Car_buyout_date = '2025-07-25' WHERE snapshot_date = '2025-05-31';
UPDATE finance_history SET Sell_shares = '4' WHERE snapshot_date = '2025-05-31';
UPDATE finance_history SET compare_to = '8' WHERE snapshot_date = '2025-05-31';
UPDATE finance_history SET Ioniq6_future = '0' WHERE snapshot_date = '2025-05-31';
INSERT OR IGNORE INTO finance_history (snapshot_date) VALUES ('2025-06-21');
UPDATE finance_history SET D_Salary = '4762.29' WHERE snapshot_date = '2025-06-21';
UPDATE finance_history SET D_Num_fortnights_pay = '3' WHERE snapshot_date = '2025-06-21';
UPDATE finance_history SET School_Fees = '24000' WHERE snapshot_date = '2025-06-21';
UPDATE finance_history SET Car_loan_via_pay = '620' WHERE snapshot_date = '2025-06-21';
UPDATE finance_history SET Car_loan = '2412' WHERE snapshot_date = '2025-06-21';
UPDATE finance_history SET Car_balloon = '45824.68' WHERE snapshot_date = '2025-06-21';
UPDATE finance_history SET Car_buyout = '83738.74' WHERE snapshot_date = '2025-06-21';
UPDATE finance_history SET Living_Expenses = '80000' WHERE snapshot_date = '2025-06-21';
UPDATE finance_history SET Savings = '408571.48' WHERE snapshot_date = '2025-06-21';
UPDATE finance_history SET Interest_Rate = '4.5' WHERE snapshot_date = '2025-06-21';
UPDATE finance_history SET Inflation = '2.4' WHERE snapshot_date = '2025-06-21';
UPDATE finance_history SET Mich_present = '10000' WHERE snapshot_date = '2025-06-21';
UPDATE finance_history SET Overseas_trip = '30000' WHERE snapshot_date = '2025-06-21';
UPDATE finance_history SET Mark_reno = '10000' WHERE snapshot_date = '2025-06-21';
UPDATE finance_history SET D_leave_owed_in_days = '76.85' WHERE snapshot_date = '2025-06-21';
UPDATE finance_history SET D_TLS_shares = '1000' WHERE snapshot_date = '2025-06-21';
UPDATE finance_history SET M_TLS_shares = '750' WHERE snapshot_date = '2025-06-21';
UPDATE finance_history SET D_CBA_shares = '1111' WHERE snapshot_date = '2025-06-21';
UPDATE finance_history SET TLS_price = '4.89' WHERE snapshot_date = '2025-06-21';
UPDATE finance_history SET CBA_price = '179.35' WHERE snapshot_date = '2025-06-21';
UPDATE finance_history SET Overseas_trip_date = '2025-07-01' WHERE snapshot_date = '2025-06-21';
UPDATE finance_history SET Mark_reno_date = '2025-09-01' WHERE snapshot_date = '2025-06-21';
UPDATE finance_history SET Car_buyout_date = '2025-07-25' WHERE snapshot_date = '2025-06-21';
UPDATE finance_history SET Sell_shares = '4' WHERE snapshot_date = '2025-06-21';
UPDATE finance_history SET compare_to = '10' WHERE snapshot_date = '2025-06-21';
UPDATE finance_history SET Ioniq6_future = '0' WHERE snapshot_date = '2025-06-21';
INSERT OR IGNORE INTO finance_history (snapshot_date) VALUES ('2025-07-30');
UPDATE finance_history SET D_Salary = '4929.97' WHERE snapshot_date = '2025-07-30';
UPDATE finance_history SET D_Num_fortnights_pay = '3' WHERE snapshot_date = '2025-07-30';
UPDATE finance_history SET School_Fees = '24000' WHERE snapshot_date = '2025-07-30';
UPDATE finance_history SET Car_loan_via_pay = '620' WHERE snapshot_date = '2025-07-30';
UPDATE finance_history SET Car_loan = '2412' WHERE snapshot_date = '2025-07-30';
UPDATE finance_history SET Car_balloon = '45824.68' WHERE snapshot_date = '2025-07-30';
UPDATE finance_history SET Car_buyout = '68000' WHERE snapshot_date = '2025-07-30';
UPDATE finance_history SET Living_Expenses = '80000' WHERE snapshot_date = '2025-07-30';
UPDATE finance_history SET Savings = '394692.74' WHERE snapshot_date = '2025-07-30';
UPDATE finance_history SET Interest_Rate = '4.5' WHERE snapshot_date = '2025-07-30';
UPDATE finance_history SET Inflation = '2.7' WHERE snapshot_date = '2025-07-30';
UPDATE finance_history SET Mich_present = '10000' WHERE snapshot_date = '2025-07-30';
UPDATE finance_history SET Overseas_trip = '50000' WHERE snapshot_date = '2025-07-30';
UPDATE finance_history SET Mark_reno = '10000' WHERE snapshot_date = '2025-07-30';
UPDATE finance_history SET D_leave_owed_in_days = '76.85' WHERE snapshot_date = '2025-07-30';
UPDATE finance_history SET D_TLS_shares = '1000' WHERE snapshot_date = '2025-07-30';
UPDATE finance_history SET M_TLS_shares = '750' WHERE snapshot_date = '2025-07-30';
UPDATE finance_history SET D_CBA_shares = '1111' WHERE snapshot_date = '2025-07-30';
UPDATE finance_history SET TLS_price = '4.95' WHERE snapshot_date = '2025-07-30';
UPDATE finance_history SET CBA_price = '174.29' WHERE snapshot_date = '2025-07-30';
UPDATE finance_history SET Overseas_trip_date = '2025-06-01' WHERE snapshot_date = '2025-07-30';
UPDATE finance_history SET Mark_reno_date = '2025-09-01' WHERE snapshot_date = '2025-07-30';
UPDATE finance_history SET Car_buyout_date = '2025-09-05' WHERE snapshot_date = '2025-07-30';
UPDATE finance_history SET Sell_shares = '4' WHERE snapshot_date = '2025-07-30';
UPDATE finance_history SET compare_to = '10' WHERE snapshot_date = '2025-07-30';
UPDATE finance_history SET Ioniq6_future = '0' WHERE snapshot_date = '2025-07-30';
INSERT OR IGNORE INTO finance_history (snapshot_date) VALUES ('2025-08-31');
UPDATE finance_history SET D_Salary = '4929.97' WHERE snapshot_date = '2025-08-31';
UPDATE finance_history SET D_Num_fortnights_pay = '2' WHERE snapshot_date = '2025-08-31';
UPDATE finance_history SET School_Fees = '24000' WHERE snapshot_date = '2025-08-31';
UPDATE finance_history SET Car_loan_via_pay = '620' WHERE snapshot_date = '2025-08-31';
UPDATE finance_history SET Car_loan = '2412' WHERE snapshot_date = '2025-08-31';
UPDATE finance_history SET Car_balloon = '45824.68' WHERE snapshot_date = '2025-08-31';
UPDATE finance_history SET Car_buyout = '68000' WHERE snapshot_date = '2025-08-31';
UPDATE finance_history SET Living_Expenses = '85000' WHERE snapshot_date = '2025-08-31';
UPDATE finance_history SET Savings = '395559.03' WHERE snapshot_date = '2025-08-31';
UPDATE finance_history SET Interest_Rate = '4.5' WHERE snapshot_date = '2025-08-31';
UPDATE finance_history SET Inflation = '2.7' WHERE snapshot_date = '2025-08-31';
UPDATE finance_history SET Mich_present = '10000' WHERE snapshot_date = '2025-08-31';
UPDATE finance_history SET Overseas_trip = '50000' WHERE snapshot_date = '2025-08-31';
UPDATE finance_history SET Mark_reno = '10000' WHERE snapshot_date = '2025-08-31';
UPDATE finance_history SET D_leave_owed_in_days = '76.85' WHERE snapshot_date = '2025-08-31';
UPDATE finance_history SET D_TLS_shares = '1000' WHERE snapshot_date = '2025-08-31';
UPDATE finance_history SET M_TLS_shares = '750' WHERE snapshot_date = '2025-08-31';
UPDATE finance_history SET D_CBA_shares = '1111' WHERE snapshot_date = '2025-08-31';
UPDATE finance_history SET TLS_price = '4.84' WHERE snapshot_date = '2025-08-31';
UPDATE finance_history SET CBA_price = '166.79' WHERE snapshot_date = '2025-08-31';
UPDATE finance_history SET Overseas_trip_date = '2025-06-01' WHERE snapshot_date = '2025-08-31';
UPDATE finance_history SET Mark_reno_date = '2025-09-01' WHERE snapshot_date = '2025-08-31';
UPDATE finance_history SET Car_buyout_date = '2025-09-05' WHERE snapshot_date = '2025-08-31';
UPDATE finance_history SET Sell_shares = '4' WHERE snapshot_date = '2025-08-31';
UPDATE finance_history SET compare_to = '1' WHERE snapshot_date = '2025-08-31';
UPDATE finance_history SET Ioniq6_future = '0' WHERE snapshot_date = '2025-08-31';
INSERT OR IGNORE INTO finance_history (snapshot_date) VALUES ('2025-09-25');
UPDATE finance_history SET D_Salary = '4929.97' WHERE snapshot_date = '2025-09-25';
UPDATE finance_history SET D_Num_fortnights_pay = '7' WHERE snapshot_date = '2025-09-25';
UPDATE finance_history SET School_Fees = '24000' WHERE snapshot_date = '2025-09-25';
UPDATE finance_history SET Car_loan_via_pay = '620' WHERE snapshot_date = '2025-09-25';
UPDATE finance_history SET Car_loan = '2412' WHERE snapshot_date = '2025-09-25';
UPDATE finance_history SET Car_balloon = '45824.68' WHERE snapshot_date = '2025-09-25';
UPDATE finance_history SET Car_buyout = '68000' WHERE snapshot_date = '2025-09-25';
UPDATE finance_history SET Living_Expenses = '80000' WHERE snapshot_date = '2025-09-25';
UPDATE finance_history SET Savings = '402929.63' WHERE snapshot_date = '2025-09-25';
UPDATE finance_history SET Interest_Rate = '4.25' WHERE snapshot_date = '2025-09-25';
UPDATE finance_history SET Inflation = '2.7' WHERE snapshot_date = '2025-09-25';
UPDATE finance_history SET Mich_present = '10000' WHERE snapshot_date = '2025-09-25';
UPDATE finance_history SET Overseas_trip = '50000' WHERE snapshot_date = '2025-09-25';
UPDATE finance_history SET Mark_reno = '10000' WHERE snapshot_date = '2025-09-25';
UPDATE finance_history SET D_leave_owed_in_days = '80.0' WHERE snapshot_date = '2025-09-25';
UPDATE finance_history SET D_TLS_shares = '1000' WHERE snapshot_date = '2025-09-25';
UPDATE finance_history SET M_TLS_shares = '750' WHERE snapshot_date = '2025-09-25';
UPDATE finance_history SET D_CBA_shares = '1111' WHERE snapshot_date = '2025-09-25';
UPDATE finance_history SET TLS_price = '4.87' WHERE snapshot_date = '2025-09-25';
UPDATE finance_history SET CBA_price = '163.74' WHERE snapshot_date = '2025-09-25';
UPDATE finance_history SET Overseas_trip_date = '2025-06-01' WHERE snapshot_date = '2025-09-25';
UPDATE finance_history SET Mark_reno_date = '2026-02-27' WHERE snapshot_date = '2025-09-25';
UPDATE finance_history SET Car_buyout_date = '2025-09-05' WHERE snapshot_date = '2025-09-25';
UPDATE finance_history SET Sell_shares = '4' WHERE snapshot_date = '2025-09-25';
UPDATE finance_history SET compare_to = '10' WHERE snapshot_date = '2025-09-25';
UPDATE finance_history SET Ioniq6_future = '0' WHERE snapshot_date = '2025-09-25';
INSERT OR IGNORE INTO finance_history (snapshot_date) VALUES ('2025-10-31');
UPDATE finance_history SET D_Salary = '4929.97' WHERE snapshot_date = '2025-10-31';
UPDATE finance_history SET D_Num_fortnights_pay = '6' WHERE snapshot_date = '2025-10-31';
UPDATE finance_history SET School_Fees = '24000' WHERE snapshot_date = '2025-10-31';
UPDATE finance_history SET Car_loan_via_pay = '620' WHERE snapshot_date = '2025-10-31';
UPDATE finance_history SET Car_loan = '2412' WHERE snapshot_date = '2025-10-31';
UPDATE finance_history SET Car_balloon = '45824.68' WHERE snapshot_date = '2025-10-31';
UPDATE finance_history SET Car_buyout = '68000' WHERE snapshot_date = '2025-10-31';
UPDATE finance_history SET Living_Expenses = '80000' WHERE snapshot_date = '2025-10-31';
UPDATE finance_history SET Savings = '412499.22' WHERE snapshot_date = '2025-10-31';
UPDATE finance_history SET Interest_Rate = '4.25' WHERE snapshot_date = '2025-10-31';
UPDATE finance_history SET Inflation = '3.0' WHERE snapshot_date = '2025-10-31';
UPDATE finance_history SET Mich_present = '10000' WHERE snapshot_date = '2025-10-31';
UPDATE finance_history SET Overseas_trip = '50000' WHERE snapshot_date = '2025-10-31';
UPDATE finance_history SET Mark_reno = '10000' WHERE snapshot_date = '2025-10-31';
UPDATE finance_history SET D_leave_owed_in_days = '77.04' WHERE snapshot_date = '2025-10-31';
UPDATE finance_history SET D_TLS_shares = '1000' WHERE snapshot_date = '2025-10-31';
UPDATE finance_history SET M_TLS_shares = '750' WHERE snapshot_date = '2025-10-31';
UPDATE finance_history SET D_CBA_shares = '1111' WHERE snapshot_date = '2025-10-31';
UPDATE finance_history SET TLS_price = '4.92' WHERE snapshot_date = '2025-10-31';
UPDATE finance_history SET CBA_price = '170.4' WHERE snapshot_date = '2025-10-31';
UPDATE finance_history SET Overseas_trip_date = '2025-06-01' WHERE snapshot_date = '2025-10-31';
UPDATE finance_history SET Mark_reno_date = '2026-02-27' WHERE snapshot_date = '2025-10-31';
UPDATE finance_history SET Car_buyout_date = '2025-09-05' WHERE snapshot_date = '2025-10-31';
UPDATE finance_history SET Sell_shares = '4' WHERE snapshot_date = '2025-10-31';
UPDATE finance_history SET compare_to = '11' WHERE snapshot_date = '2025-10-31';
UPDATE finance_history SET Ioniq6_future = '0' WHERE snapshot_date = '2025-10-31';
INSERT OR IGNORE INTO finance_history (snapshot_date) VALUES ('2025-11-28');
UPDATE finance_history SET D_Salary = '4929.97' WHERE snapshot_date = '2025-11-28';
UPDATE finance_history SET D_Num_fortnights_pay = '6' WHERE snapshot_date = '2025-11-28';
UPDATE finance_history SET School_Fees = '24000' WHERE snapshot_date = '2025-11-28';
UPDATE finance_history SET Car_loan_via_pay = '620' WHERE snapshot_date = '2025-11-28';
UPDATE finance_history SET Car_loan = '2412' WHERE snapshot_date = '2025-11-28';
UPDATE finance_history SET Car_balloon = '45824.68' WHERE snapshot_date = '2025-11-28';
UPDATE finance_history SET Car_buyout = '68000' WHERE snapshot_date = '2025-11-28';
UPDATE finance_history SET Living_Expenses = '80000' WHERE snapshot_date = '2025-11-28';
UPDATE finance_history SET Savings = '426882.95' WHERE snapshot_date = '2025-11-28';
UPDATE finance_history SET Interest_Rate = '4.25' WHERE snapshot_date = '2025-11-28';
UPDATE finance_history SET Inflation = '3.3' WHERE snapshot_date = '2025-11-28';
UPDATE finance_history SET Mich_present = '10000' WHERE snapshot_date = '2025-11-28';
UPDATE finance_history SET Overseas_trip = '50000' WHERE snapshot_date = '2025-11-28';
UPDATE finance_history SET Mark_reno = '10000' WHERE snapshot_date = '2025-11-28';
UPDATE finance_history SET D_leave_owed_in_days = '77.04' WHERE snapshot_date = '2025-11-28';
UPDATE finance_history SET D_TLS_shares = '1000' WHERE snapshot_date = '2025-11-28';
UPDATE finance_history SET M_TLS_shares = '750' WHERE snapshot_date = '2025-11-28';
UPDATE finance_history SET D_CBA_shares = '1111' WHERE snapshot_date = '2025-11-28';
UPDATE finance_history SET TLS_price = '4.92' WHERE snapshot_date = '2025-11-28';
UPDATE finance_history SET CBA_price = '153.28' WHERE snapshot_date = '2025-11-28';
UPDATE finance_history SET Overseas_trip_date = '2025-06-01' WHERE snapshot_date = '2025-11-28';
UPDATE finance_history SET Mark_reno_date = '2026-02-27' WHERE snapshot_date = '2025-11-28';
UPDATE finance_history SET Car_buyout_date = '2025-09-05' WHERE snapshot_date = '2025-11-28';
UPDATE finance_history SET Sell_shares = '4' WHERE snapshot_date = '2025-11-28';
UPDATE finance_history SET compare_to = '11' WHERE snapshot_date = '2025-11-28';
UPDATE finance_history SET Ioniq6_future = '0' WHERE snapshot_date = '2025-11-28';
INSERT OR IGNORE INTO finance_history (snapshot_date) VALUES ('2025-12-16');
UPDATE finance_history SET D_Salary = '4929.97' WHERE snapshot_date = '2025-12-16';
UPDATE finance_history SET D_Num_fortnights_pay = '6' WHERE snapshot_date = '2025-12-16';
UPDATE finance_history SET School_Fees = '24000' WHERE snapshot_date = '2025-12-16';
UPDATE finance_history SET Car_loan_via_pay = '620' WHERE snapshot_date = '2025-12-16';
UPDATE finance_history SET Car_loan = '2412' WHERE snapshot_date = '2025-12-16';
UPDATE finance_history SET Car_balloon = '45824.68' WHERE snapshot_date = '2025-12-16';
UPDATE finance_history SET Car_buyout = '68000' WHERE snapshot_date = '2025-12-16';
UPDATE finance_history SET Living_Expenses = '80000' WHERE snapshot_date = '2025-12-16';
UPDATE finance_history SET Savings = '403181.28' WHERE snapshot_date = '2025-12-16';
UPDATE finance_history SET Interest_Rate = '4.25' WHERE snapshot_date = '2025-12-16';
UPDATE finance_history SET Inflation = '3.3' WHERE snapshot_date = '2025-12-16';
UPDATE finance_history SET Mich_present = '10000' WHERE snapshot_date = '2025-12-16';
UPDATE finance_history SET Overseas_trip = '50000' WHERE snapshot_date = '2025-12-16';
UPDATE finance_history SET Mark_reno = '10000' WHERE snapshot_date = '2025-12-16';
UPDATE finance_history SET D_leave_owed_in_days = '80.09' WHERE snapshot_date = '2025-12-16';
UPDATE finance_history SET D_TLS_shares = '1000' WHERE snapshot_date = '2025-12-16';
UPDATE finance_history SET M_TLS_shares = '750' WHERE snapshot_date = '2025-12-16';
UPDATE finance_history SET D_CBA_shares = '1128' WHERE snapshot_date = '2025-12-16';
UPDATE finance_history SET TLS_price = '4.9' WHERE snapshot_date = '2025-12-16';
UPDATE finance_history SET CBA_price = '154.24' WHERE snapshot_date = '2025-12-16';
UPDATE finance_history SET Overseas_trip_date = '2025-06-01' WHERE snapshot_date = '2025-12-16';
UPDATE finance_history SET Mark_reno_date = '2026-02-27' WHERE snapshot_date = '2025-12-16';
UPDATE finance_history SET Car_buyout_date = '2025-09-05' WHERE snapshot_date = '2025-12-16';
UPDATE finance_history SET Sell_shares = '4' WHERE snapshot_date = '2025-12-16';
UPDATE finance_history SET compare_to = '11' WHERE snapshot_date = '2025-12-16';
UPDATE finance_history SET Ioniq6_future = '0' WHERE snapshot_date = '2025-12-16';
INSERT OR IGNORE INTO finance_history (snapshot_date) VALUES ('2025-12-27');
UPDATE finance_history SET D_Salary = '4929.97' WHERE snapshot_date = '2025-12-27';
UPDATE finance_history SET D_Num_fortnights_pay = '6' WHERE snapshot_date = '2025-12-27';
UPDATE finance_history SET School_Fees = '24000' WHERE snapshot_date = '2025-12-27';
UPDATE finance_history SET Car_loan_via_pay = '620' WHERE snapshot_date = '2025-12-27';
UPDATE finance_history SET Car_loan = '2412' WHERE snapshot_date = '2025-12-27';
UPDATE finance_history SET Car_balloon = '45824.68' WHERE snapshot_date = '2025-12-27';
UPDATE finance_history SET Car_buyout = '68000' WHERE snapshot_date = '2025-12-27';
UPDATE finance_history SET Living_Expenses = '80000' WHERE snapshot_date = '2025-12-27';
UPDATE finance_history SET Savings = '403823.76' WHERE snapshot_date = '2025-12-27';
UPDATE finance_history SET Interest_Rate = '4.25' WHERE snapshot_date = '2025-12-27';
UPDATE finance_history SET Inflation = '3.3' WHERE snapshot_date = '2025-12-27';
UPDATE finance_history SET Mich_present = '10000' WHERE snapshot_date = '2025-12-27';
UPDATE finance_history SET Overseas_trip = '50000' WHERE snapshot_date = '2025-12-27';
UPDATE finance_history SET Mark_reno = '10000' WHERE snapshot_date = '2025-12-27';
UPDATE finance_history SET D_leave_owed_in_days = '81.11' WHERE snapshot_date = '2025-12-27';
UPDATE finance_history SET D_TLS_shares = '1000' WHERE snapshot_date = '2025-12-27';
UPDATE finance_history SET M_TLS_shares = '750' WHERE snapshot_date = '2025-12-27';
UPDATE finance_history SET D_CBA_shares = '1128' WHERE snapshot_date = '2025-12-27';
UPDATE finance_history SET TLS_price = '4.88' WHERE snapshot_date = '2025-12-27';
UPDATE finance_history SET CBA_price = '161.38' WHERE snapshot_date = '2025-12-27';
UPDATE finance_history SET Overseas_trip_date = '2025-06-01' WHERE snapshot_date = '2025-12-27';
UPDATE finance_history SET Mark_reno_date = '2026-02-27' WHERE snapshot_date = '2025-12-27';
UPDATE finance_history SET Car_buyout_date = '2025-09-05' WHERE snapshot_date = '2025-12-27';
UPDATE finance_history SET Sell_shares = '4' WHERE snapshot_date = '2025-12-27';
UPDATE finance_history SET compare_to = '12' WHERE snapshot_date = '2025-12-27';
UPDATE finance_history SET Ioniq6_future = '0' WHERE snapshot_date = '2025-12-27';
INSERT OR IGNORE INTO finance_history (snapshot_date) VALUES ('2026-01-04');
UPDATE finance_history SET D_Salary = '4929.97' WHERE snapshot_date = '2026-01-04';
UPDATE finance_history SET D_Num_fortnights_pay = '6' WHERE snapshot_date = '2026-01-04';
UPDATE finance_history SET School_Fees = '24000' WHERE snapshot_date = '2026-01-04';
UPDATE finance_history SET Car_loan_via_pay = '620' WHERE snapshot_date = '2026-01-04';
UPDATE finance_history SET Car_loan = '2412' WHERE snapshot_date = '2026-01-04';
UPDATE finance_history SET Car_balloon = '45824.68' WHERE snapshot_date = '2026-01-04';
UPDATE finance_history SET Car_buyout = '68000' WHERE snapshot_date = '2026-01-04';
UPDATE finance_history SET Living_Expenses = '80000' WHERE snapshot_date = '2026-01-04';
UPDATE finance_history SET Savings = '403042.77' WHERE snapshot_date = '2026-01-04';
UPDATE finance_history SET Interest_Rate = '4.25' WHERE snapshot_date = '2026-01-04';
UPDATE finance_history SET Inflation = '3.3' WHERE snapshot_date = '2026-01-04';
UPDATE finance_history SET Mich_present = '10000' WHERE snapshot_date = '2026-01-04';
UPDATE finance_history SET Overseas_trip = '50000' WHERE snapshot_date = '2026-01-04';
UPDATE finance_history SET Mark_reno = '10000' WHERE snapshot_date = '2026-01-04';
UPDATE finance_history SET D_leave_owed_in_days = '81.11' WHERE snapshot_date = '2026-01-04';
UPDATE finance_history SET D_TLS_shares = '1000' WHERE snapshot_date = '2026-01-04';
UPDATE finance_history SET M_TLS_shares = '750' WHERE snapshot_date = '2026-01-04';
UPDATE finance_history SET D_CBA_shares = '1128' WHERE snapshot_date = '2026-01-04';
UPDATE finance_history SET TLS_price = '4.87' WHERE snapshot_date = '2026-01-04';
UPDATE finance_history SET CBA_price = '161.12' WHERE snapshot_date = '2026-01-04';
UPDATE finance_history SET Overseas_trip_date = '2025-06-01' WHERE snapshot_date = '2026-01-04';
UPDATE finance_history SET Mark_reno_date = '2026-02-27' WHERE snapshot_date = '2026-01-04';
UPDATE finance_history SET Car_buyout_date = '2025-09-05' WHERE snapshot_date = '2026-01-04';
UPDATE finance_history SET Sell_shares = '4' WHERE snapshot_date = '2026-01-04';
UPDATE finance_history SET compare_to = '11' WHERE snapshot_date = '2026-01-04';
UPDATE finance_history SET Ioniq6_future = '0' WHERE snapshot_date = '2026-01-04';
INSERT OR IGNORE INTO finance_history (snapshot_date) VALUES ('2026-01-08');
UPDATE finance_history SET D_Salary = '4929.97' WHERE snapshot_date = '2026-01-08';
UPDATE finance_history SET D_Num_fortnights_pay = '6' WHERE snapshot_date = '2026-01-08';
UPDATE finance_history SET School_Fees = '24000' WHERE snapshot_date = '2026-01-08';
UPDATE finance_history SET Car_loan_via_pay = '620' WHERE snapshot_date = '2026-01-08';
UPDATE finance_history SET Car_loan = '2412' WHERE snapshot_date = '2026-01-08';
UPDATE finance_history SET Car_balloon = '45824.68' WHERE snapshot_date = '2026-01-08';
UPDATE finance_history SET Car_buyout = '68000' WHERE snapshot_date = '2026-01-08';
UPDATE finance_history SET Living_Expenses = '84000' WHERE snapshot_date = '2026-01-08';
UPDATE finance_history SET Savings = '407559.56' WHERE snapshot_date = '2026-01-08';
UPDATE finance_history SET Interest_Rate = '4.25' WHERE snapshot_date = '2026-01-08';
UPDATE finance_history SET Inflation = '3.2' WHERE snapshot_date = '2026-01-08';
UPDATE finance_history SET Mich_present = '10000' WHERE snapshot_date = '2026-01-08';
UPDATE finance_history SET Overseas_trip = '50000' WHERE snapshot_date = '2026-01-08';
UPDATE finance_history SET Mark_reno = '10000' WHERE snapshot_date = '2026-01-08';
UPDATE finance_history SET D_leave_owed_in_days = '81.11' WHERE snapshot_date = '2026-01-08';
UPDATE finance_history SET D_TLS_shares = '1000' WHERE snapshot_date = '2026-01-08';
UPDATE finance_history SET M_TLS_shares = '750' WHERE snapshot_date = '2026-01-08';
UPDATE finance_history SET D_CBA_shares = '1128' WHERE snapshot_date = '2026-01-08';
UPDATE finance_history SET TLS_price = '4.8' WHERE snapshot_date = '2026-01-08';
UPDATE finance_history SET CBA_price = '152.8' WHERE snapshot_date = '2026-01-08';
UPDATE finance_history SET Overseas_trip_date = '2025-06-01' WHERE snapshot_date = '2026-01-08';
UPDATE finance_history SET Mark_reno_date = '2026-02-27' WHERE snapshot_date = '2026-01-08';
UPDATE finance_history SET Car_buyout_date = '2025-09-05' WHERE snapshot_date = '2026-01-08';
UPDATE finance_history SET Sell_shares = '4' WHERE snapshot_date = '2026-01-08';
UPDATE finance_history SET compare_to = '11' WHERE snapshot_date = '2026-01-08';
UPDATE finance_history SET Ioniq6_future = '0' WHERE snapshot_date = '2026-01-08';
INSERT OR IGNORE INTO finance_history (snapshot_date) VALUES ('2026-01-14');
UPDATE finance_history SET D_Salary = '4929.97' WHERE snapshot_date = '2026-01-14';
UPDATE finance_history SET D_Num_fortnights_pay = '6' WHERE snapshot_date = '2026-01-14';
UPDATE finance_history SET School_Fees = '24000' WHERE snapshot_date = '2026-01-14';
UPDATE finance_history SET Car_loan_via_pay = '620' WHERE snapshot_date = '2026-01-14';
UPDATE finance_history SET Car_loan = '2412' WHERE snapshot_date = '2026-01-14';
UPDATE finance_history SET Car_balloon = '45824.68' WHERE snapshot_date = '2026-01-14';
UPDATE finance_history SET Car_buyout = '68000' WHERE snapshot_date = '2026-01-14';
UPDATE finance_history SET Living_Expenses = '80000' WHERE snapshot_date = '2026-01-14';
UPDATE finance_history SET Savings = '407559.56' WHERE snapshot_date = '2026-01-14';
UPDATE finance_history SET Interest_Rate = '4.25' WHERE snapshot_date = '2026-01-14';
UPDATE finance_history SET Inflation = '3.2' WHERE snapshot_date = '2026-01-14';
UPDATE finance_history SET Mich_present = '10000' WHERE snapshot_date = '2026-01-14';
UPDATE finance_history SET Overseas_trip = '50000' WHERE snapshot_date = '2026-01-14';
UPDATE finance_history SET Mark_reno = '10000' WHERE snapshot_date = '2026-01-14';
UPDATE finance_history SET D_leave_owed_in_days = '81.11' WHERE snapshot_date = '2026-01-14';
UPDATE finance_history SET D_TLS_shares = '1000' WHERE snapshot_date = '2026-01-14';
UPDATE finance_history SET M_TLS_shares = '750' WHERE snapshot_date = '2026-01-14';
UPDATE finance_history SET D_CBA_shares = '1128' WHERE snapshot_date = '2026-01-14';
UPDATE finance_history SET TLS_price = '4.8' WHERE snapshot_date = '2026-01-14';
UPDATE finance_history SET CBA_price = '152.8' WHERE snapshot_date = '2026-01-14';
UPDATE finance_history SET Overseas_trip_date = '2025-06-01' WHERE snapshot_date = '2026-01-14';
UPDATE finance_history SET Mark_reno_date = '2026-02-27' WHERE snapshot_date = '2026-01-14';
UPDATE finance_history SET Car_buyout_date = '2025-09-05' WHERE snapshot_date = '2026-01-14';
UPDATE finance_history SET Sell_shares = '4' WHERE snapshot_date = '2026-01-14';
UPDATE finance_history SET compare_to = '11' WHERE snapshot_date = '2026-01-14';
UPDATE finance_history SET Ioniq6_future = '0' WHERE snapshot_date = '2026-01-14';

35
main.py
View File

@@ -1,7 +1,7 @@
# 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, calc_key_dates from calc import calculate_savings_depletion, calc_key_dates, add_historical_annotations
from db import init_db, get_finance_data, update_finance, get_budget_data from db import init_db, get_historical_data, get_finance_data, update_finance, get_budget_data
from db import insert_cset, get_comp_set_data, get_comp_set_options, delete_cset from db import insert_cset, get_comp_set_data, get_comp_set_options, delete_cset
from db import get_bill_freqs, get_bill_growth_types from db import get_bill_freqs, get_bill_growth_types
from db import get_bill_data, new_bill, update_bill_data, delete_bill, delete_estimated_bills, delete_estimated_bills_for from db import get_bill_data, new_bill, update_bill_data, delete_bill, delete_estimated_bills, delete_estimated_bills_for
@@ -26,18 +26,25 @@ init_db()
@app.route('/') @app.route('/')
def index(): def index():
hist = get_historical_data()
finance_data = get_finance_data() finance_data = get_finance_data()
get_comp_set_options(finance_data) get_comp_set_options(finance_data)
bill_data = get_bill_data("order_by_date_only") bill_data = get_bill_data("order_by_date_only")
bill_types = get_bill_types() bill_types = get_bill_types()
depletion_date, savings_per_fortnight, final_savings = calculate_savings_depletion(finance_data, bill_data, bill_types) depletion_date, savings_per_fortnight, final_savings = calculate_savings_depletion(finance_data, bill_data, bill_types)
add_historical_annotations( finance_data )
# now sort this by X, then Y, to get the historical ones in the right order
finance_data['annotations'].sort(key=lambda item: (item['x'], item['y']))
BUDGET=get_budget_data(finance_data) BUDGET=get_budget_data(finance_data)
if depletion_date: if depletion_date:
depletion_date=depletion_date.date(); # just show date depletion_date=depletion_date.date(); # just show date
# if we are comparing...(compare_to will be 0 / None to start with, and then COMP will be None # if we are comparing...(compare_to will be 0 / None to start with, and then COMP will be None
if finance_data['compare_to']:
COMP=get_comp_set_data(finance_data['compare_to']) COMP=get_comp_set_data(finance_data['compare_to'])
else:
COMP={}
DISP=[] DISP=[]
# Row 1 # Row 1
@@ -46,7 +53,7 @@ def index():
r.append( FP_VAR( 'Savings', 'Savings' ) ) r.append( FP_VAR( 'Savings', 'Savings' ) )
r.append( FP_VAR( 'Car Loan via Pay', 'Car_loan_via_pay', 'readonly' ) ) r.append( FP_VAR( 'Car Loan via Pay', 'Car_loan_via_pay', 'readonly' ) )
r.append( FP_VAR( 'Living Expenses', 'Living_Expenses' ) ) r.append( FP_VAR( 'Living Expenses', 'Living_Expenses' ) )
r.append( FP_VAR( 'Overseas Trip', 'Overseas_trip', 'date', 'col-auto', 'Overseas_trip_date' ) ) r.append( FP_VAR( 'Overseas Trip', 'Overseas_trip', 'date', 'col', 'Overseas_trip_date' ) )
DISP.append(r) DISP.append(r)
# Row 2 # Row 2
@@ -55,7 +62,7 @@ def index():
r.append( FP_VAR( 'Interest Rate', 'Interest_Rate' ) ) r.append( FP_VAR( 'Interest Rate', 'Interest_Rate' ) )
r.append( FP_VAR( 'Car Loan (monthly)', 'Car_loan', 'readonly' ) ) r.append( FP_VAR( 'Car Loan (monthly)', 'Car_loan', 'readonly' ) )
r.append( FP_VAR( 'Inflation', 'Inflation' ) ) r.append( FP_VAR( 'Inflation', 'Inflation' ) )
r.append( FP_VAR( 'Reno Costs', 'Mark_reno', 'date', 'col-auto', 'Mark_reno_date' ) ) r.append( FP_VAR( 'Reno Costs', 'Mark_reno', 'date', 'col', 'Mark_reno_date' ) )
DISP.append(r) DISP.append(r)
# Row 2 # Row 2
@@ -68,7 +75,7 @@ def index():
ss_opt.append( { 'val': el, 'label': f'{el} years' } ) ss_opt.append( { 'val': el, 'label': f'{el} years' } )
r.append( FP_VAR( 'Sell Shares for:', 'Sell_shares', 'select', 'col-auto', '', ss_opt ) ) r.append( FP_VAR( 'Sell Shares for:', 'Sell_shares', 'select', 'col-auto', '', ss_opt ) )
r.append( FP_VAR( 'Car Buyout', 'Car_buyout', 'date', 'col-auto', 'Car_buyout_date' ) ) r.append( FP_VAR( 'Car Buyout', 'Car_buyout', 'date', 'col', 'Car_buyout_date' ) )
DISP.append(r) DISP.append(r)
# Row 3 # Row 3
@@ -106,18 +113,22 @@ def index():
# now work out how much padding we need in the first year to align the last dates for all years # now work out how much padding we need in the first year to align the last dates for all years
padding=second_count - first_count padding=second_count - first_count
key_dates = calc_key_dates( finance_data ) key_dates = calc_key_dates( finance_data )
return render_template('index.html', now=now, first_yr=first_yr, padding=padding, finance=finance_data, depletion_date=depletion_date, savings=savings_per_fortnight, BUDGET=BUDGET, COMP=COMP, DISP=DISP, key_dates=key_dates) return render_template('index.html', now=now, first_yr=first_yr, padding=padding, finance=finance_data, depletion_date=depletion_date, savings=savings_per_fortnight, BUDGET=BUDGET, COMP=COMP, DISP=DISP, key_dates=key_dates, hist=hist)
@app.route('/save', methods=['POST']) @app.route('/save', methods=['POST'])
def save(): def save():
insert_cset( request.get_json() ) cset_id=insert_cset( request.get_json() )
return "200" name = request.get_json()['vars']['name']
return jsonify( cset_id=cset_id, name=name )
@app.route('/update', methods=['POST']) @app.route('/update', methods=['POST'])
def update(): def update():
old_finance_data = get_finance_data() old_finance_data = get_finance_data()
raw_compare_to = request.form.get('compare_to')
compare_to_value = None if raw_compare_to == "0" else int(raw_compare_to)
finance_data = ( finance_data = (
request.form['D_Salary'], request.form['D_Salary'],
request.form['D_Num_fortnights_pay'], request.form['D_Num_fortnights_pay'],
@@ -143,9 +154,10 @@ def update():
request.form['Mark_reno_date'], request.form['Mark_reno_date'],
request.form['Car_buyout_date'], request.form['Car_buyout_date'],
request.form['Sell_shares'], request.form['Sell_shares'],
request.form['compare_to'], compare_to_value,
request.form['Ioniq6_future'] request.form['Ioniq6_future']
) )
update_finance(finance_data) update_finance(finance_data)
new_finance_data = get_finance_data() new_finance_data = get_finance_data()
# changed Ioniq6_future, Car_buyout_date or D_Num_fortnights_pay, so lets force recalc key_dates, and therefore estimated bills # changed Ioniq6_future, Car_buyout_date or D_Num_fortnights_pay, so lets force recalc key_dates, and therefore estimated bills
@@ -185,7 +197,10 @@ def DisplayBillData():
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 # 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, key_dates=key_dates, growth=bill_growth_types, cpi=finance_data['Inflation'] ) finance_data = get_finance_data()
# FIXME: really need to do this better, but for now, hard code til I quit seems okay to me
FIRST_YEAR=2026
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, FIRST_YEAR=FIRST_YEAR, END_YEAR=END_YEAR, total=total, key_dates=key_dates, growth=bill_growth_types, cpi=finance_data['Inflation'] )
@app.route('/newbilltype', methods=['POST']) @app.route('/newbilltype', methods=['POST'])
def InsertBillType(): def InsertBillType():

45
snapshot.sh Executable file
View File

@@ -0,0 +1,45 @@
#!/bin/bash
if [ "$ENV" == "production" ]; then
DB_FILE="/data/finance.db"
else
DB_FILE="./finance.db"
fi
HISTORY_TABLE="finance_history"
# Current date in the format you've been using
DATE_STR=$(date +%Y-%m-%d)
# 1. Identify which table exists (finance or finance_data)
SRC_TABLE=finance
if [ -z "$SRC_TABLE" ]; then
echo "Error: Source table not found."
exit 1
fi
# 2. Get columns dynamically (excluding 'id')
COLS=$(sqlite3 "$DB_FILE" "PRAGMA table_info($SRC_TABLE);" | cut -d'|' -f2 | grep -v '^id$' | xargs | tr ' ' ',')
# 3. Change Detection Logic
# We grab the latest row from history and compare it to the current source data
CURRENT_VALS=$(sqlite3 "$DB_FILE" "SELECT $COLS FROM $SRC_TABLE ORDER BY id DESC LIMIT 1;")
LAST_VALS=$(sqlite3 "$DB_FILE" "SELECT $COLS FROM $HISTORY_TABLE ORDER BY snapshot_date DESC LIMIT 1;")
if [ "$CURRENT_VALS" == "$LAST_VALS" ]; then
echo "Data identical to last snapshot ($DATE_STR). Skipping."
exit 0
fi
# 4. Auto-Migration
# Ensure any new columns in 'finance' also exist in 'finance_history'
for col in ${COLS//,/ }; do
sqlite3 "$DB_FILE" "ALTER TABLE $HISTORY_TABLE ADD COLUMN $col NUMERIC;" 2>/dev/null
done
# 5. The Snapshot Insert
# INSERT OR IGNORE ensures that if Docker restarts today, we don't duplicate the row.
echo "Changes detected. Recording snapshot for $DATE_STR..."
sqlite3 "$DB_FILE" <<EOF
INSERT OR IGNORE INTO $HISTORY_TABLE (snapshot_date, $COLS)
SELECT '$DATE_STR', $COLS FROM $SRC_TABLE ORDER BY id DESC LIMIT 1;
EOF

11
static/favicon.svg Normal file
View File

@@ -0,0 +1,11 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="16" cy="16" r="16" fill="#1B2E3C"/>
<rect x="9" y="17" width="4" height="7" rx="1" fill="white"/>
<rect x="15" y="14" width="4" height="10" rx="1" fill="white"/>
<rect x="21" y="10" width="4" height="14" rx="1" fill="white"/>
<path d="M8 14L14 9L18 11L25 4" stroke="lightblue" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M21 4H25V8" stroke="lightblue" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 585 B

View File

@@ -14,7 +14,8 @@
<script src="https://code.highcharts.com/modules/accessibility.js"></script> <script src="https://code.highcharts.com/modules/accessibility.js"></script>
<style> <style>
.col-form-label { width:140px; } .col-form-label { width:140px; }
html { font-size: 80%; } html { font-size: 75% !important; }
@media (max-width: 2000px) { html { font-size: 70% !important; } }
</style> </style>
</head> </head>
<body> <body>
@@ -25,7 +26,7 @@
<table> <table>
{% for bt in total %} {% for bt in total %}
<tr><td></td><td>&nbsp;{{bt}}:</td> <tr><td></td><td>&nbsp;{{bt}}:</td>
{% for yr in range( 2025, 2032 ) %} {% for yr in range( FIRST_YEAR, END_YEAR+1 ) %}
{% if yr in total[bt] %} {% if yr in total[bt] %}
<td> <td>
{{total[bt][yr]}} {{total[bt][yr]}}
@@ -62,7 +63,7 @@
<div class="px-0 col"><label class="form-control d-flex <div class="px-0 col"><label class="form-control d-flex
align-items-end justify-content-center h-100 border-0 fw-bold align-items-end justify-content-center h-100 border-0 fw-bold
bg-body-tertiary rounded-0">Annual Growth</ ></div> bg-body-tertiary rounded-0">Annual Growth</ ></div>
{% for yr in range( 2025, 2032 ) %} {% for yr in range( FIRST_YEAR, END_YEAR+1 ) %}
<div class="px-0 col"><label class="form-control d-flex <div class="px-0 col"><label class="form-control d-flex
align-items-end justify-content-center h-100 border-0 align-items-end justify-content-center h-100 border-0
fw-bold bg-body-tertiary rounded-0">{{yr}} Total</ ></div> fw-bold bg-body-tertiary rounded-0">{{yr}} Total</ ></div>
@@ -119,7 +120,7 @@
</select> </select>
</div> </div>
</div> </div>
{% for yr in range( 2025, 2032 ) %} {% for yr in range( FIRST_YEAR, END_YEAR+1 ) %}
<div class="px-0 col"><input type="text" class="bill-type-total-{{bt.id}} form-control text-center" id="bill-type-total-{{bt.id}}" value="${{'%.2f'|format(total[bt.id][yr])}}" disabled> </div> <div class="px-0 col"><input type="text" class="bill-type-total-{{bt.id}} form-control text-center" id="bill-type-total-{{bt.id}}" value="${{'%.2f'|format(total[bt.id][yr])}}" disabled> </div>
{% endfor %} {% endfor %}
<button id="bill-type-chg-{{bt.id}}" class="px-0 col btn btn-success bg-success-subtle text-success" onClick="StartUpdateBillType( {{bt.id}} )"><span class="bi bi-pencil-square"> Change</button> <button id="bill-type-chg-{{bt.id}}" class="px-0 col btn btn-success bg-success-subtle text-success" onClick="StartUpdateBillType( {{bt.id}} )"><span class="bi bi-pencil-square"> Change</button>
@@ -129,8 +130,8 @@
</div> </div>
{% endfor %} {% endfor %}
<div class="row"> <div class="row">
<div class="px-0 col"></div> <div class="px-0 col-1"></div>
<div class="px-0 col"></div> <div class="px-0 col-1"></div>
<div class="px-0 col"><input type="text" class="form-control text-end text-primary fs-5" value="TOTAL:"></div> <div class="px-0 col"><input type="text" class="form-control text-end text-primary fs-5" value="TOTAL:"></div>
{% for yr in range( this_year, END_YEAR+1) %} {% for yr in range( this_year, END_YEAR+1) %}
{% set tot=namespace( sum=0 ) %} {% set tot=namespace( sum=0 ) %}
@@ -193,15 +194,17 @@
<span class="bi bi-x"> Cancel</span> </button> <span class="bi bi-x"> Cancel</span> </button>
</div> </div>
<div class="d-flex align-items-start">
<!-- create tabbed view for each bill type --> <!-- create tabbed view for each bill type -->
<nav id="bills-nav" class="nav nav-tabs"> <nav id="bills-nav" class="nav flex-column nav-pills me-3">
{% for bt in bill_types %} {% for bt in bill_types %}
<button class="nav-link" id="tab-but-{{bt.id}}" data-bs-toggle="tab" data-bs-target="#tab-{{bt.id}}" type="button" role="tab" aria-controls="tab1" aria-selected="true" onClick="SaveTab('{{bt.id}}')">{{bt.name}}</button> <button class="nav-link w-100 text-end col px-1 py-2" id="tab-but-{{bt.id}}" data-bs-toggle="tab" data-bs-target="#tab-{{bt.id}}" type="button" role="tab" aria-controls="tab1" aria-selected="true" onClick="SaveTab('{{bt.id}}')">{{bt.name}}</button>
{% endfor %} {% endfor %}
</nav> </nav>
<div class="tab-content"> <div class="tab-content">
<div class="col-2 form-check form-switch form-check-inline"> <div class="col form-check form-switch form-check-inline">
<input class="form-check-input" type="checkbox" value="" id="showEstimated" onChange="ToggleEstimated()"> <input class="form-check-input" type="checkbox" value="" id="showEstimated" onChange="ToggleEstimated()">
<label class="form-check-label" for="flexCheckDefault">Show Estimates</label> <label class="form-check-label" for="flexCheckDefault">Show Estimates</label>
</div> </div>
@@ -214,8 +217,7 @@
{% for bd in bill_data %} {% for bd in bill_data %}
{% if loop.first %} {% if loop.first %}
<div class="row pt-2"> <div class="row pt-2">
<div class="p-0 col-2"><label class="form-control text-center border-0 fw-bold bg-body-tertiary rounded-0">Name</ ></div> <div class="p-0 col"><label class="form-control text-center border-0 fw-bold bg-body-tertiary rounded-0">Date</ ></div>
<div class="p-0 col-2"><label class="form-control text-center border-0 fw-bold bg-body-tertiary rounded-0">Date</ ></div>
<div class="p-0 col"><label class="form-control text-center border-0 fw-bold bg-body-tertiary rounded-0">Amount</ ></div> <div class="p-0 col"><label class="form-control text-center border-0 fw-bold bg-body-tertiary rounded-0">Amount</ ></div>
<div class="px-0 col"><label class="form-control text-center border-0 fw-bold bg-body-tertiary rounded-0">Actions</ ></div> <div class="px-0 col"><label class="form-control text-center border-0 fw-bold bg-body-tertiary rounded-0">Actions</ ></div>
<div class="px-0 col"><label class="form-control text-center border-0 fw-bold bg-body-tertiary rounded-0 h-100"></ ></div> <div class="px-0 col"><label class="form-control text-center border-0 fw-bold bg-body-tertiary rounded-0 h-100"></ ></div>
@@ -229,11 +231,11 @@
<div class="row"> <div class="row">
{% set classes="form-control text-center" %} {% set classes="form-control text-center" %}
{% endif %} {% endif %}
<div class="px-0 col-2"> <input type="text" class="{{classes}}" id="bill-data-type-{{bd.id}}" value="{{ bd.name }}" disabled> </div> <input type="hidden" id="bill-data-type-{{bd.id}}" value="{{ bd.name }}"> </input>
{% if bd.bill_date == 'future' %} {% if bd.bill_date == 'future' %}
<div class="px-0 col-2"> <input type="text" class="{{classes}}" id="bill-data-date-{{bd.id}}" value="{{ bd.bill_date }}" disabled> </div> <div class="px-0 col"> <input type="text" class="{{classes}}" id="bill-data-date-{{bd.id}}" value="{{ bd.bill_date }}" disabled> </div>
{% else %} {% else %}
<div class="px-0 col-2"> <input type="date" class="{{classes}}" id="bill-data-date-{{bd.id}}" value="{{ bd.bill_date }}" disabled> </div> <div class="px-0 col"> <input type="date" class="{{classes}}" id="bill-data-date-{{bd.id}}" value="{{ bd.bill_date }}" disabled> </div>
<script> <script>
if( typeof future_id !== 'undefined' && future_id>0) { if( typeof future_id !== 'undefined' && future_id>0) {
first_col_id={{bd.id}} first_col_id={{bd.id}}
@@ -259,6 +261,7 @@
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
</div>
<script> <script>
function ToggleEstimated() function ToggleEstimated()
@@ -453,7 +456,7 @@
function SaveTab( last_tab ) function SaveTab( last_tab )
{ {
// set the drop-down for new bill to be this tab now... // set the drop-down for new bill to be this tab now...
$("#new-bill-data-type").val( $('.nav-tabs .nav-link.active').prop('id').replace("tab-but-", "") ) $("#new-bill-data-type").val( $('.nav-link.active').prop('id').replace("tab-but-", "") )
$.ajax( { type: 'POST', url: '/saveui', contentType: 'application/json', data: JSON.stringify( { 'last_tab': last_tab } ), success: function() { } } ) $.ajax( { type: 'POST', url: '/saveui', contentType: 'application/json', data: JSON.stringify( { 'last_tab': last_tab } ), success: function() { } } )
} }

View File

@@ -14,7 +14,8 @@
<script src="https://code.highcharts.com/modules/accessibility.js"></script> <script src="https://code.highcharts.com/modules/accessibility.js"></script>
<style> <style>
.col-form-label { width:140px; } .col-form-label { width:140px; }
html { font-size: 80%; } html { font-size: 75% !important; }
@media (max-width: 2000px) { html { font-size: 70% !important; } }
</style> </style>
</head> </head>
<body> <body>

View File

@@ -5,18 +5,20 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
<link rel="icon" type="image/svg+xml" href="{{ url_for('static', filename='favicon.svg') }}">
<title>Finance Form</title> <title>Finance Form</title>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script> <script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
<script src="https://code.highcharts.com/highcharts.js"></script> <script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/mouse-wheel-zoom.js"></script>
<script src="https://code.highcharts.com/modules/annotations.js"></script> <script src="https://code.highcharts.com/modules/annotations.js"></script>
<script src="https://code.highcharts.com/modules/accessibility.js"></script> <script src="https://code.highcharts.com/modules/accessibility.js"></script>
<script src="https://code.highcharts.com/themes/adaptive.js"></script> <script src="https://code.highcharts.com/themes/adaptive.js"></script>
<style> <style>
.col-form-label { width:140px; } .col-form-label { width:140px; }
html { font-size: 80%; } html { font-size: 75% !important; }
@media (max-width: 2000px) { html { font-size: 69% !important; } }
</style> </style>
</head> </head>
<body> <body>
@@ -33,7 +35,7 @@
<ul> <ul>
<li>Savings (<a href='https://online.macquarie.com.au/personal/#/login'>Macquarie</a> <li>Savings (<a href='https://online.macquarie.com.au/personal/#/login'>Macquarie</a>
+<a href='https://ib.mebank.com.au/authR5/ib/login.jsp'>ME bank</a> +<a href='https://ib.mebank.com.au/authR5/ib/login.jsp'>ME bank</a>
+<a href='https://ib.nab.com.au/login'>NAB</a>) -- noting ME bank is: $1000</li> +<a href='https://ib.nab.com.au/login'>NAB</a>) -- noting ME bank is: $934.07</li>
<li><a href='https://www.google.com/search?q=asx+tls'>TLS</a>/<a href='https://www.google.com/search?q=asx+cba'>CBA</a> prices</li> <li><a href='https://www.google.com/search?q=asx+tls'>TLS</a>/<a href='https://www.google.com/search?q=asx+cba'>CBA</a> prices</li>
<li>Macq <a href='https://www.macquarie.com.au/everyday-banking/savings-account.html'>Interest rate</a></li> <li>Macq <a href='https://www.macquarie.com.au/everyday-banking/savings-account.html'>Interest rate</a></li>
<li><a href='https://deakinpeople.deakin.edu.au/psc/HCMP/EMPLOYEE/HRMS/c/NUI_FRAMEWORK.PT_AGSTARTPAGE_NUI.GBL?CONTEXTIDPARAMS=TEMPLATE_ID%3aPTPPNAVCOL&scname=ADMN_LEAVE&PTPPB_GROUPLET_ID=DU_LEAVE&CRefName=ADMN_NAVCOLL_3'>D_leave_owed_in_days</a> by: {{key_dates['D_quit_date']}}</li> <li><a href='https://deakinpeople.deakin.edu.au/psc/HCMP/EMPLOYEE/HRMS/c/NUI_FRAMEWORK.PT_AGSTARTPAGE_NUI.GBL?CONTEXTIDPARAMS=TEMPLATE_ID%3aPTPPNAVCOL&scname=ADMN_LEAVE&PTPPB_GROUPLET_ID=DU_LEAVE&CRefName=ADMN_NAVCOLL_3'>D_leave_owed_in_days</a> by: {{key_dates['D_quit_date']}}</li>
@@ -222,11 +224,18 @@
// 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 }}');
const vars = JSON.parse('{{ finance | tojson }}'); const vars = JSON.parse('{{ finance | tojson }}');
const rawHistData = JSON.parse('{{ hist | tojson }}');
const histData = rawHistData.map(entry => [ new Date(entry.snapshot_date).getTime(), parseFloat(entry.Savings || 0) ]);
$(function() { $('[data-bs-toggle="popover"]').popover(); }); $(function() { $('[data-bs-toggle="popover"]').popover(); });
window.onload = function() { window.onload = function() {
$('#Sell_shares').val( {{finance['Sell_shares']}} ) $('#Sell_shares').val( {{finance['Sell_shares']}} )
{% if finance['compare_to'] %}
$('#compare_to').val( {{finance['compare_to']}} ) $('#compare_to').val( {{finance['compare_to']}} )
{% else %}
// set this to Nothing by default
$('#compare_to').val( 0 )
{% endif %}
$('#Ioniq6_future').val( {{finance['Ioniq6_future']}} ) $('#Ioniq6_future').val( {{finance['Ioniq6_future']}} )
if( $("#Ioniq6_future option:selected"). text() == 'lease' ) if( $("#Ioniq6_future option:selected"). text() == 'lease' )
@@ -259,6 +268,7 @@
$('#tab-but-findata').click() $('#tab-but-findata').click()
// Parse the savings_data from Flask // Parse the savings_data from Flask
const chartData = savingsData.map(entry => [new Date(entry[0]).getTime(), parseFloat(entry[1])]); const chartData = savingsData.map(entry => [new Date(entry[0]).getTime(), parseFloat(entry[1])]);
const histChartData = histData.map(entry => [new Date(entry[0]).getTime(), parseFloat(entry[1])]);
{% if COMP %} {% if COMP %}
const compSavingsData = JSON.parse('{{ COMP['savings_data'] | tojson }}'); const compSavingsData = JSON.parse('{{ COMP['savings_data'] | tojson }}');
const compChartData = compSavingsData.map(entry => [new Date(entry[0]).getTime(), parseFloat(entry[1])]); const compChartData = compSavingsData.map(entry => [new Date(entry[0]).getTime(), parseFloat(entry[1])]);
@@ -298,11 +308,43 @@
}); });
const annotations = []; const annotations = [];
// offset is used to make the next annotation be on slightly different vertical offsets (size is based on $'s) // this annotation stuff is painful, its in y-coords for the point
// HACK: start at 13, later we adjust in steps of 50s allowing 4 steps, then we go back to top // (based on graphs y-axis, but then needs an offset in absolute pixels) so this two coord systems makes it hard to keep the labels going, there
var offset=13 // are a few hacks below that probably will break if the data changes too much
var last_y = {{finance['annotations'][0]['y']}}
var how_many_up = 0
var how_many_down = 0
var offset_y = 0
var offset_x = 0
// Add annotations for changes greater than 5000 // Add annotations for changes greater than 5000
{% for a in finance['annotations'] %} {% for a in finance['annotations'] %}
{% if '-$' in a['label'] %}
how_many_down += 1
offset_y = ({{a['y']}} - last_y)/650 + 25*how_many_down
offset_x = -60-10*how_many_down
if( how_many_down > 12 )
how_many_down =0
// console.log( "{{a['label']}} U:" + how_many_up + ", D: " + how_many_down + ", last_y=" + last_y + ", y={{a['y']}}, offset_y=" + offset_y + ", offset_x=" + offset_x )
last_y = {{a['y']}}
{% else %}
how_many_up += 1
offset_y = -25
{% if a['y'] > 400000 %}
offset_x = -80 -30*(6-how_many_up)
{% else %}
offset_x = -50 -10*how_many_up
{% endif %}
if( how_many_up > 3 )
how_many_up=0
{% endif %}
{% if a['y'] < 250000 %}
offset_y -= 350
{% endif %}
{% if a['y'] < 250000 and a['y'] > 200000 %}
offset_x += 100
{% endif %}
annotations.push({ annotations.push({
labels: [{ labels: [{
point: { point: {
@@ -312,31 +354,23 @@
xAxis: 0, xAxis: 0,
yAxis: 0 yAxis: 0
}, },
x: -70, x: offset_x,
{% if '-$' in a['label'] %} y: offset_y,
y: offset,
{% else %}
y: -20,
{% endif %}
text: '{{a['label']}}' text: '{{a['label']}}'
}], labelOptions: { allowOverlap: true } }], labelOptions: { allowOverlap: true }
}); });
{% if a['y'] > 200000 %}
offset = ({{loop.index}} * 50 % 200) +50
{% else %}
offset = -100
{% endif %}
{% endfor %} {% endfor %}
document.keep = annotations document.keep = annotations
// Highcharts configuration // Highcharts configuration
Highcharts.chart('graph', { Highcharts.chart('graph', {
chart: { type: 'line' }, chart: { type: 'line', zooming: { type: 'x' } },
colors: [ 'orange' ], colors: [ 'orange' ],
title: { text: 'Savings Over Time' }, title: { text: 'Savings Over Time' },
xAxis: { xAxis: {
type: 'datetime', type: 'datetime',
title: { text: 'Date' }, title: { text: 'Date' },
min: Date.UTC(2024, 6, 1),
plotBands: plotBands // Alternating background for years plotBands: plotBands // Alternating background for years
}, },
yAxis: { title: { text: 'Amount ($)' } }, yAxis: { title: { text: 'Amount ($)' } },
@@ -348,13 +382,16 @@
}, shared:true }, shared:true
}, },
annotations: annotations, // Add annotations annotations: annotations, // Add annotations
series: [ { name: "Savings", data: chartData, marker: { radius: 2 } } ] series: [
{ name: "Savings", data: chartData, marker: { enabled: true, symbol: 'circle', radius: 2}, lineWidth:1, dashStyle: 'ShortDash', color: 'orange' },
{ name: "Historical", data: histChartData, marker: { enabled: true, symbol: 'circle', radius: 2 }, lineWidth:1 }
]
}); });
{% if COMP %} {% if COMP %}
// Highcharts configuration // Highcharts configuration
Highcharts.chart('graph-comp', { Highcharts.chart('graph-comp', {
chart: { type: 'line' }, chart: { type: 'line', zooming: { type: 'x' } },
colors: [ colors: [
'orange', // Custom color 1 'orange', // Custom color 1
'cyan', // Custom color 2 'cyan', // Custom color 2
@@ -374,8 +411,9 @@
}, shared:true }, shared:true
}, },
series: [ series: [
{ name: "Savings", data: chartData, marker: { radius: 2 } } { name: "Savings", data: chartData, marker: { enabled: true, symbol: 'circle', radius: 2}, lineWidth:1, dashStyle: 'ShortDash', color: 'orange' }
,{ name: "{{COMP['vars']['name']}}", data: compChartData, marker: { radius: 2 } } ,{ name: "{{COMP['vars']['name']}}", data: compChartData, marker: { enabled: true, symbol: 'diamond', radius: 2 }, lineWidth:1, color: 'cyan' },
{ name: "Historical", data: histChartData, marker: { enabled: true, symbol: 'circle', radius: 2 }, lineWidth:1 }
] ]
}); });
{% endif %} {% endif %}
@@ -401,13 +439,17 @@
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-info" <button type="button" class="btn btn-info"
onClick=" onClick="
vars['name']=$('#save_name').val(); vars['name'] = $('#save_name').val();
$.ajax( { $.ajax({
type: 'POST', type: 'POST',
url: '/save', url: '/save',
contentType: 'application/json', contentType: 'application/json',
data: JSON.stringify( { 'vars': vars, 'savings_data' :savingsData } ), data: JSON.stringify({ 'vars': vars, 'savings_data': savingsData }),
success: function() { $('#save_modal').modal('hide'); } } )" success: function(resp) {
$('#save_modal').modal('hide');
$('#compare_to').append($('<option>', { value: resp.cset_id, text: resp.name }));
}
});"
>Save</button> >Save</button>
</div> </div>
</div> </div>

21
wrapper.sh Executable file
View File

@@ -0,0 +1,21 @@
#!/bin/bash
if [ "$ENV" == "production" ]; then
export WORKERS=2
export THREADS=2
export RELOAD=""
else
cd /pybook_mapped_volume
export WORKERS=1
export THREADS=1
export RELOAD="--reload"
fi
# start cron as root to do historical snapshots
/usr/sbin/cron -f &
# start finplan with right amount of threads/workers, etc.
sudo -u finplan gunicorn --bind=0.0.0.0:80 --timeout 300 --workers=$WORKERS --threads=$THREADS main:app --env ENV="$ENV" --error-logfile gunicorn.error.log --access-logfile gunicorn.log --capture-output $RELOAD --enable-stdio-inheritance
# just in case it fails this keeps the container up so you can check gunicorn logs
sleep 99999