Budget history by month, shared tab navigation, file imported statements into Statements/year/month and stop re-reading them
build-container / build (push) Successful in 40s

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 5.5 committed 2026-10-21 15:52:05 -04:00
1 parent d7808a3925
commit 20317b14c9
7 files changed
+147 -12

No files matched your search

+19 -4
View File
@@ -68,10 +68,10 @@ def state():
rows = [dict(date=f"{r.txn.date:%Y-%m-%d}", account=r.txn.account, desc=r.txn.desc[:60], amount=r.txn.amount, kind=r.kind,
payee=r.payee, what=r.what, reason=r.reason, new_payee=r.is_new_payee) for r in new]
sm = L.summarize(new)
return dict(coverage=coverage(res["statements"]), skipped=[dict(file=f, why=w) for f, w in res["skipped"]],
return dict(coverage=coverage(res["statements"] + L.archived_statements()), skipped=[dict(file=f, why=w) for f, w in res["skipped"]],
duplicates=[dict(file=a, same_as=b) for a, b in res["dups"]],
bad=[dict(file=f, parsed=p, stated=s) for f, p, s, ok in res["checks"] if not ok],
already=res["already"], new=rows, summary=sm, statements=len(res["statements"]),
already=res["already"], new=rows, archivable=(0 if new else len([x for x in res["statements"] if x.file not in res["bad"]])), summary=sm, statements=len(res["statements"]),
excel_open=(DATA / "~$Bills_Tracker.xlsx").exists() or (DATA / ".~lock.Bills_Tracker.xlsx#").exists(),
backups=sorted(p.name for p in L.BACKUPS.glob("*.xlsx"))[-5:] if L.BACKUPS.exists() else [])
@@ -151,6 +151,12 @@ class H(BaseHTTPRequestHandler):
if not L.WORKBOOK.exists(): return self._send(200, {"setup": True})
return self._send(200, B.compute(workbook_data(), month))
except Exception as e: return self._send(500, {"error": str(e)})
if u.path == "/api/budget_history":
with LOCK:
try:
if not L.WORKBOOK.exists(): return self._send(200, dict(months=[], envelopes=[]))
return self._send(200, B.history(workbook_data()))
except Exception as e: return self._send(500, {"error": str(e)})
if u.path == "/api/payees":
with LOCK:
try: return self._send(200, L.uncategorized())
@@ -193,15 +199,24 @@ class H(BaseHTTPRequestHandler):
res = L.run_preview(DATA)
if not res["new"]: return self._send(200, {"message": "Nothing new to import."})
out = L.apply(res["new"])
return self._send(200, {"message": f"Added {out['log_rows']} rows to the Bill Log and {out['excluded_rows']} to Excluded Transfers.",
try: filed = L.archive_statements()["moved"]
except Exception: filed = 0
tail = f" Filed {filed} statement(s) into Statements/year/month." if filed else ""
return self._send(200, {"message": f"Added {out['log_rows']} rows to the Bill Log and {out['excluded_rows']} to Excluded Transfers.{tail}",
"backup": Path(out["backup"]).name, "new_payees": out["new_payees"]})
if u.path == "/api/archive":
try:
with LOCK: out = L.archive_statements()
except ValueError as e: return self._send(400, {"error": str(e)})
return self._send(200, {"message": f"Filed {out['moved']} statement(s) into Statements/year/month. They won't be read again."})
if u.path == "/api/undo":
with LOCK:
b = sorted(L.BACKUPS.glob("*.xlsx")) if L.BACKUPS.exists() else []
if not b: return self._send(200, {"message": "No backups to restore."})
keep = L.BACKUPS / f"before_undo_{dt.datetime.now():%Y%m%d_%H%M%S}.xlsx"
shutil.copy2(L.WORKBOOK, keep); shutil.copy2(b[-1], L.WORKBOOK)
return self._send(200, {"message": f"Restored the workbook from {b[-1].name}."})
back = L.unarchive_last()
return self._send(200, {"message": f"Restored the workbook from {b[-1].name}." + (f" Moved {back} statement(s) back to the data folder." if back else "")})
if u.path == "/api/create_blank":
tpl = HERE / "template" / "Bills_Tracker.template.xlsx"
with LOCK: