Envelope budget: Budget page, per-month assignments stored on a Budget tab, rollover and ready-to-assign
build-container / build (push) Successful in 50s
build-container / build (push) Successful in 50s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
837f89e563
commit
4b93d6229d
8 files changed
+235
-5
No files matched your search
@@ -504,6 +504,39 @@ def autocategorize(workbook=WORKBOOK):
|
||||
_save_workbook(wb, workbook)
|
||||
return dict(updated=n, remaining=left, backup=b.name)
|
||||
|
||||
|
||||
def set_budget(month, budgets, workbook=WORKBOOK):
|
||||
"""Replace the envelope amounts for one month (YYYY-MM) on the Budget tab. budgets: {envelope: amount}."""
|
||||
from openpyxl import load_workbook
|
||||
from openpyxl.styles import Font, PatternFill, Alignment
|
||||
if not re.fullmatch(r"\d{4}-\d\d", month or ""): raise ValueError("bad month")
|
||||
b = _backup(workbook); wb = load_workbook(workbook)
|
||||
if "Budget" not in wb.sheetnames:
|
||||
ws = wb.create_sheet("Budget")
|
||||
ws["A1"], ws["B1"], ws["C1"] = "Month", "Envelope", "Budgeted"
|
||||
for c in ("A1", "B1", "C1"):
|
||||
ws[c].font = Font(name="Arial", bold=True, color="FFFFFF"); ws[c].fill = PatternFill("solid", fgColor="1F3864")
|
||||
ws["E1"] = "Envelope budget amounts, one row per month and envelope. Edit them on the app's Budget page; spending comes from the Bill Log."
|
||||
ws["E1"].font = Font(name="Arial", italic=True)
|
||||
ws.column_dimensions["A"].width = 10; ws.column_dimensions["B"].width = 28; ws.column_dimensions["C"].width = 12
|
||||
ws.freeze_panes = "A2"
|
||||
ws = wb["Budget"]
|
||||
keep = []
|
||||
for r in ws.iter_rows(min_row=2, max_col=3, values_only=True):
|
||||
if r[0] is None or r[1] is None: continue
|
||||
m = r[0] if isinstance(r[0], str) else f"{r[0]:%Y-%m}"
|
||||
if m != month: keep.append((m, r[1], r[2] or 0))
|
||||
for r in range(2, ws.max_row + 1):
|
||||
for c in (1, 2, 3): ws.cell(r, c).value = None
|
||||
new = [(month, k, round(float(v), 2)) for k, v in budgets.items() if v not in (None, "") and round(float(v), 2) != 0]
|
||||
for i, row in enumerate(sorted(keep + new), 2):
|
||||
for c, v in enumerate(row, 1):
|
||||
ws.cell(i, c).value = v
|
||||
ws.cell(i, c).font = Font(name="Arial", size=10)
|
||||
ws.cell(i, 3).number_format = '$#,##0.00;($#,##0.00);-'
|
||||
_save_workbook(wb, workbook)
|
||||
return dict(rows=len(new), backup=b.name)
|
||||
|
||||
def summarize(rows):
|
||||
return dict(log=sum(r.kind == "log" for r in rows), excluded=sum(r.kind == "excluded" for r in rows),
|
||||
new_payees=sorted({r.payee for r in rows if r.is_new_payee}))
|
||||
|
||||
Reference in new issue
Block a user