Budget: expected income per month so Ready to assign works with mid-month and month-end paychecks
build-container / build (push) Successful in 41s
build-container / build (push) Successful in 41s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3d956f3fd2
commit
d7808a3925
2 files changed
+25
-11
No files matched your search
@@ -14,6 +14,8 @@ def ym_add(ym, n):
|
||||
|
||||
def this_month(): return f"{dt.date.today():%Y-%m}"
|
||||
|
||||
EXPECTED = "Expected income" # stored on the Budget tab like an envelope row, but it is income you plan on, not an envelope
|
||||
|
||||
def compute(D, month):
|
||||
cats = list(D.get("categories") or [])
|
||||
spent = defaultdict(float) # (cat, ym)
|
||||
@@ -23,10 +25,12 @@ def compute(D, month):
|
||||
income = defaultdict(float)
|
||||
for i in D.get("income", []): income[i[0][:7]] += i[3]
|
||||
bud = defaultdict(float) # (cat, ym)
|
||||
expected = {} # ym -> income you expect this month (paychecks still to come)
|
||||
for m, env, amt in D.get("budget", []):
|
||||
if env == EXPECTED: expected[m] = amt; continue
|
||||
bud[(env, m)] += amt
|
||||
if env not in cats: cats.append(env)
|
||||
budget_months = sorted({m for (_, m) in bud})
|
||||
budget_months = sorted({m for (_, m) in bud} | set(expected))
|
||||
start = min(budget_months[0], month) if budget_months else month
|
||||
first_tx = min((t[0][:7] for t in D["tx"]), default=month)
|
||||
|
||||
@@ -41,11 +45,19 @@ def compute(D, month):
|
||||
rows.append(dict(envelope=c, budgeted=round(b, 2), spent=round(s, 2), prior=round(avail - b + s, 2),
|
||||
available=round(avail, 2), suggest=suggest))
|
||||
inc_month = income.get(month, 0.0)
|
||||
inc_cum = sum(v for m, v in income.items() if start <= m <= month)
|
||||
bud_cum = sum(v for (_, m), v in bud.items() if m <= month)
|
||||
# income that counts for a month = whichever is bigger: what actually arrived, or what you said to expect
|
||||
counted = lambda m: max(income.get(m, 0.0), expected.get(m, 0.0))
|
||||
prev = ym_add(month, -1)
|
||||
inc_prev = sum(counted(m) for m in {*income, *expected} if start <= m <= prev)
|
||||
bud_prev = sum(v for (_, m), v in bud.items() if m <= prev)
|
||||
prev_income = round(income.get(prev, 0.0), -1)
|
||||
# a month from today on starts out expecting last month's income, until you set a figure
|
||||
exp_default = expected.get(month, prev_income if month >= this_month() else 0.0)
|
||||
inc_cum = inc_prev + counted(month); bud_cum = bud_prev + sum(v for (_, m), v in bud.items() if m == month)
|
||||
months, m = [], min(first_tx, start)
|
||||
while m <= ym_add(this_month(), 1):
|
||||
months.append(m); m = ym_add(m, 1)
|
||||
return dict(month=month, start=start, envelopes=rows, income_month=round(inc_month, 2),
|
||||
ready=round(inc_cum - bud_cum, 2), budgeted_month=round(sum(r["budgeted"] for r in rows), 2),
|
||||
ready=round(inc_cum - bud_cum, 2), ready_before=round(inc_prev - bud_prev, 2),
|
||||
expected=exp_default, expected_saved=month in expected, budgeted_month=round(sum(r["budgeted"] for r in rows), 2),
|
||||
has_budget=bool(budget_months), months=months, prev_has=any(v for (c, m), v in bud.items() if m == ym_add(month, -1)))
|
||||
Reference in new issue
Block a user