- Added a Makefile to easily run project scripts (fees, match, web, image) - Modified attendance.py to dynamically handle a variable number of header rows from the Google Sheet - Updated both attendance calculations and calculate_fees terminal output to show actual attendance counts (e.g., '750 CZK (3)') - Created a Flask web dashboard (app.py and templates/fees.html) to view member fees in an attractive, condensed, terminal-like UI - Bound the Flask server to port 5000 and added a routing alias from '/' to '/fees' - Configured Python virtual environment (.venv) creation directly into the Makefile to resolve global pip install errors on macOS Co-authored-by: Antigravity <antigravity@deepmind.com>
3.0 KiB
3.0 KiB
Scripts
All scripts live in scripts/ and use Python 3.10+ with stdlib only (no pip dependencies).
calculate_fees.py
Calculates monthly fees for each Adult member based on Tuesday practice attendance.
cd scripts && python3 calculate_fees.py
Outputs a table of Adult members with their monthly fee (0 / 200 / 750 CZK) and totals per month. Data is fetched live from the Google Sheet.
match_payments.py
Matches incoming bank payments against expected fees to produce a reconciliation report.
cd scripts && python3 match_payments.py [--from YYYY-MM-DD] [--to YYYY-MM-DD]
| Option | Default | Description |
|---|---|---|
--from |
2025-12-01 |
Start of date range for bank transactions |
--to |
today | End of date range |
Bank data access is controlled by the FIO_API_TOKEN environment variable:
- Set — uses the Fio REST API (JSON, structured data, all fields)
- Not set — scrapes the public transparent account HTML page
# With API token:
FIO_API_TOKEN=xxx python3 match_payments.py --from 2026-01-01 --to 2026-02-11
# Without (public page):
python3 match_payments.py --from 2026-01-01 --to 2026-02-11
Report sections:
- Summary table — per member, per month:
OK/UNPAID {amount}/{paid}/{expected}+ balance - Credits — advance payments for months without attendance data yet
- Unmatched transactions — payments the script couldn't assign to any member
- Matched transaction details — full breakdown of which payment was assigned where, with
[REVIEW]tags on low-confidence matches
Known limitations:
- Lump-sum payments covering multiple months are split evenly rather than by actual per-month fee
- Messages with no member name and a sender not in the member list cannot be matched
- Common surnames (Novák) are excluded from last-name-only matching to avoid false positives
Shared modules
attendance.py
Shared attendance and fee logic, imported by both scripts above.
Key functions:
| Function | Description |
|---|---|
fetch_csv() |
Fetches the Google Sheet as parsed CSV rows |
parse_dates(header_row) |
Extracts (column_index, date) pairs from the header |
group_by_month(dates) |
Groups column indices by YYYY-MM |
calculate_fee(count) |
Applies fee rules: 0→0, 1→200, 2+→750 CZK |
get_members(rows) |
Parses member rows into (name, tier, row) tuples |
get_members_with_fees() |
Full pipeline: fetch → parse → compute fees. Returns (members, sorted_months) |
czech_utils.py
Czech language text utilities.
| Function | Description |
|---|---|
normalize(text) |
Strip diacritics and lowercase (Štrúdl → strudl) |
parse_month_references(text) |
Extract YYYY-MM strings from Czech free text. Handles month names in all declensions (leden, ledna, lednu), numeric formats (01/26, 11+12/2025), dot notation (12.2025), and ranges (listopad-leden) |
CZECH_MONTHS |
Dict mapping normalized Czech month names (all declensions) to month numbers |