Commit Graph

13 Commits

Author SHA1 Message Date
8734089223 fix(reconcile): fill earliest month deficit first in multi-month allocations
All checks were successful
Deploy to K8s / deploy (push) Successful in 9s
Replace proportional split with a fill-first loop that allocates
min(remaining, deficit) to each matched month in user-supplied order,
where deficit = expected - already_paid. Prior transactions' contributions
are now properly accounted for, so a second payment on overlapping months
fills only what's still owed instead of splitting proportionally by total
expected. Surplus after all deficits are covered goes to the credit bucket.

Fixes: Matyáš Thér 200+550 showing 566/183 instead of 500/250.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-11 23:59:36 +02:00
65694ad378 feat(py): M5.4 fix #2 — add vs and sync_id to payments tx projection
All checks were successful
Deploy to K8s / deploy (push) Successful in 7s
Python's fetch_sheet_data read 9 sheet columns but skipped VS and
Sync ID, causing make parity to report extra fields on every raw
payment row emitted by the Go backend. Both columns are already on
the sheet; add idx_vs / idx_sync_id lookups and the matching keys
to the tx dict so the Python /api/* wire shape matches Go's
RawTransaction.

Update /api/* test fixtures to include vs/sync_id keys for realism.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 23:50:33 +02:00
40e4a9e45e feat(py): M5.3 — add Python /api/* shadow endpoints
Four new JSON routes mirror the Go /api/* handlers so the M5.4 parity
tool can diff them: /api/version, /api/adults, /api/juniors,
/api/payments. A small _unwrap_view_model_for_api() helper in app.py
expands the three pre-serialised JSON strings in the view-model dicts
and renames month_labels_json → month_labels and
raw_payments_json → raw_payments to match the Go wire contract.

Tests in test_app.py assert top-level key sets match the Go API schema
and that member_data, month_labels, raw_payments are objects not strings.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 22:37:14 +02:00
c5a8a4e7b1 fix: include juniors in payment-inference roster
Some checks failed
Deploy to K8s / deploy (push) Successful in 10s
Build and Push / build (push) Successful in 6s
Build and Push / build-go (push) Failing after 12m23s
infer_payments was building member_names from get_members_with_fees()
(adults sheet only). Junior-only members were invisible to the matcher,
so a payment message containing an exact junior name would produce a
fuzzy review match against a different adult sharing the same first name.

Fix: union the adult and junior rosters (deduped via canonical_member_key)
so all members are candidates. The existing exact-name short-circuit in
match_members then handles precedence correctly.

Two regression tests added for the Jáchym Kubík / Jáchym Hrušák case.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 16:38:21 +02:00
394da2e6b8 fix: Tolerate diacritic/case/whitespace mismatches in Person column matching
Some checks failed
Deploy to K8s / deploy (push) Successful in 11s
Build and Push / build (push) Successful in 6s
Build and Push / build-go (push) Failing after 6s
- Add canonical_member_key() in match_payments.py to normalize names via
  NFKD + lowercase + whitespace-collapse before ledger lookup; resolves
  payments attributed to e.g. "Maria Maco" to canonical "Mária Maco".
  Emits logger.info when a non-canonical cell is rescued so sheet typos
  are visible in logs without losing the payment allocation.
- Extend group_payments_by_person() in app.py to accept member_names and
  re-key raw-payment groups under the canonical attendance-sheet name so
  the modal's Raw Payments debug section also finds the row correctly.
- Add raw payments collapsible section to member detail modal in adults.html
  and juniors.html for debugging payment attribution issues.
- Remove 4 obsolete tests targeting routes /fees, /fees-juniors, /reconcile,
  /reconcile-juniors that no longer exist; add test_match_payments.py
  covering canonical key equivalence and reconcile() tolerance end-to-end.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-05 17:22:54 +02:00
81b36878b3 fix: Payment inference returns only exact-name matches when present
Some checks failed
Deploy to K8s / deploy (push) Successful in 11s
Build and Push / build (push) Successful in 7s
Build and Push / build-go (push) Failing after 5s
match_members() now short-circuits on whole-word full-name hits and
uses word-boundary regex everywhere else, so a nickname that is a
substring of another member's surname (e.g. "tov" inside "ottova")
no longer produces false positives. Adds tests/test_match_members.py.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 23:08:59 +02:00
dfdf2aacb8 fix: Distribute multi-month payments by per-month expected fee
All checks were successful
Build and Push / build (push) Successful in 33s
Deploy to K8s / deploy (push) Successful in 12s
reconcile() previously split a multi-month payment evenly across months,
which falsely flagged months as underpaid when their expected fees
differed (e.g. 1250 CZK for 02+03+04 2026 with rates 750/350/150 was
shown as 416/month with two months red).

The allocation now runs per matched member: greedy when the share covers
the total expected (each month gets its expected fee, surplus -> credit),
proportional by expected fee otherwise. Out-of-window months keep the
previous even-split-to-credit behavior. 6 new test cases.

Also adds CHANGELOG.md and a changelog convention in CLAUDE.md.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-03 19:38:10 +02:00
61f2126c1b feat: Change default redirect to Adults dashboard
All checks were successful
Build and Push / build (push) Successful in 8s
Deploy to K8s / deploy (push) Successful in 12s
Co-authored-by: Antigravity <antigravity@google.com>
2026-03-11 13:13:05 +01:00
3377092a3f feat: Add Adults and Juniors dashboards with concise layout, totals, tooltips and unified navigation
All checks were successful
Build and Push / build (push) Successful in 8s
Deploy to K8s / deploy (push) Successful in 8s
Co-authored-by: Antigravity <antigravity@google.com>
2026-03-11 13:01:18 +01:00
033349cafa refactor: code quality improvements across the backend
All checks were successful
Deploy to K8s / deploy (push) Successful in 13s
Build and Push / build (push) Successful in 32s
- Remove insecure SSL verification bypass in attendance.py
- Add gunicorn as production WSGI server (Dockerfile + entrypoint)
- Fix silent data loss in reconciliation (log + surface unmatched members)
- Add required column validation in payment sheet parsing
- Add input validation on /qr route (account format, amount bounds, SPD injection)
- Centralize configuration into scripts/config.py
- Extract credentials path to env-configurable constant
- Hide unmatched transactions from reconcile-juniors page
- Fix test mocks to bypass cache layer (all 8 tests now pass reliably)
- Add pytest + pytest-cov dev dependencies
- Fix typo "Inffering" in infer_payments.py
- Update CLAUDE.md to reflect current project state

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 11:40:32 +01:00
Jan Novak
75a36eb49b feat: Implement junior fees dashboard and reconciliation
All checks were successful
Deploy to K8s / deploy (push) Successful in 11s
Build and Push / build (push) Successful in 9s
- Add dual-sheet architecture to pull attendance from both adult and junior spreadsheets.
- Introduce parsing rules to isolate juniors (e.g. above '# Treneri', tier 'J').
- Add new endpoints `/fees-juniors` and `/reconcile-juniors` to track junior attendances and match bank payments.
- Display granular attendance components showing adult vs. junior practices.
- Add fee rule configuration supporting custom pricing exceptions for specific months (e.g. Sep 2025) and merging billing periods.
- Add `make sync-2025` target to the Makefile for convenience.
- Document junior fees implementation logic and rules in prompts/outcomes.

Co-authored-by: Antigravity <antigravity@google.com>
2026-03-09 17:35:26 +01:00
Jan Novak
815b962dd7 feat: add member details popup with attendance and fee exceptions
All checks were successful
Deploy to K8s / deploy (push) Successful in 12s
Build and Push / build (push) Successful in 8s
2026-03-02 21:41:36 +01:00
Jan Novak
535e1bb772 feat: add reconciliation and ledger views to web dashboard with test suite
All checks were successful
Deploy to K8s / deploy (push) Successful in 11s
2026-03-02 14:29:48 +01:00