Add new categories/envelopes from the Budget page and the loader's categorize card
build-container / build (push) Successful in 35s

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 5.5 committed 2026-10-21 14:37:23 -04:00
1 parent 690316e541
commit 5068021b09
4 files changed
+33 -1

No files matched your search

+19
View File
@@ -487,6 +487,25 @@ def set_categories(changes, workbook=WORKBOOK):
_save_workbook(wb, workbook)
return dict(updated=n, backup=b.name)
def add_category(name, workbook=WORKBOOK):
"""Add a category (envelope) to the Lists tab: first free slot in E4:E23, else E25:E40 (the web pages show them all;
the Excel summary tabs only have 20 slots)."""
from openpyxl import load_workbook
from copy import copy
name = re.sub(r"\s+", " ", (name or "")).strip()
if not name or len(name) > 40: raise ValueError("Give the category a name (40 characters or fewer).")
b = _backup(workbook); wb = load_workbook(workbook); ls = wb["Lists"]
if name.lower() in {str(c).lower() for c in _categories(wb)}: raise ValueError(f"'{name}' already exists.")
row = next((r for r in list(range(4, 24)) + list(range(25, 41)) if ls.cell(r, 5).value is None), None)
if row is None: raise ValueError("The Lists tab has no free category slots left.")
cell = ls.cell(row, 5); cell.value = name
src = ls.cell(4, 5); cell.font, cell.border, cell.alignment, cell.fill = copy(src.font), copy(src.border), copy(src.alignment), copy(src.fill)
if row > 23:
for dv in ls.data_validations.dataValidation:
if dv.formula1 == "$E$4:$E$23": dv.formula1 = "$E$4:$E$40"
_save_workbook(wb, workbook)
return dict(name=name, backup=b.name, beyond_excel=row > 23)
def autocategorize(workbook=WORKBOOK):
"""Apply the built-in merchant rules to payees still set to Other / Unsorted."""
from openpyxl import load_workbook