feat: expense tracker Python parity (Wave 10)
Some checks failed
Python CI / pytest (ubuntu-latest) (push) Has been cancelled
Python CI / pytest (windows-latest) (push) Has been cancelled
Python CI / ruff (push) Has been cancelled

New `expenses_handlers.py`:
- parse_expense(phrase) -> (amount, category) | None  — pure fn, fully
  unit-tested. Handles "потратил 500 на еду", comma decimals "12,50",
  EN "spent 12.5 on coffee", default category "разное".
- do_expenses_log: append entry to expenses.json (atomic write-then-rename).
- do_expenses_today: sum today's entries (local-day boundary).
- do_expenses_week: rolling 7-day total + count.
- do_expenses_breakdown: per-category, top-5 + tail collapse.

extensions.py / main.py / commands.yaml: 4 new dispatch entries.
.gitignore: + expenses.json.

tests/test_expenses_handlers.py: 8 unit tests covering parse, log,
today/week math, breakdown ordering + tail collapse.

Tests: 96 → 104 (+8). Total Python coverage now mirrors Rust pack
behaviour for personal finance.
This commit is contained in:
Bossiara13 2026-05-16 15:02:07 +03:00
parent b3cfaa5171
commit f102b8dc95
6 changed files with 343 additions and 0 deletions

View file

@ -32,6 +32,7 @@ import personality_handlers
import time_tracker_handlers
import outlook_handlers
import wave68_handlers
import expenses_handlers
_speak_fn = print
_set_clipboard_fn = None
@ -49,6 +50,7 @@ def set_speak(fn):
time_tracker_handlers.set_speak(fn)
outlook_handlers.set_speak(fn)
wave68_handlers.set_speak(fn)
expenses_handlers.set_speak(fn)
def set_clipboard_fn(fn):
@ -1166,3 +1168,11 @@ def do_trivia(a, v): wave68_handlers.do_trivia(a, v)
def do_good_night(a, v): wave68_handlers.do_good_night(a, v)
def do_good_morning(a, v): wave68_handlers.do_good_morning(a, v)
def do_coffee_break(a, v): wave68_handlers.do_coffee_break(a, v)
# ── Expenses proxies (to expenses_handlers) ────────────────────────────────
def do_expenses_log(a, v): expenses_handlers.do_expenses_log(a, v)
def do_expenses_today(a, v): expenses_handlers.do_expenses_today(a, v)
def do_expenses_week(a, v): expenses_handlers.do_expenses_week(a, v)
def do_expenses_breakdown(a, v): expenses_handlers.do_expenses_breakdown(a, v)