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>
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>
- 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>
- 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>
- 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>