feat: initial dashboard implementation and robust attendance parsing
- 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>
This commit is contained in:
69
docs/fee-calculation-spec.md
Normal file
69
docs/fee-calculation-spec.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# Fee Calculation Spec — Tuesday Practices
|
||||
|
||||
## Data Source
|
||||
|
||||
- Google Sheet: `1E2e_gT_K5AwSRCDLDTa2UetZTkHmBOcz0kFbBUNUNBA`
|
||||
- Sheet: first sheet only (Tuesday practices, 20:30–22:00)
|
||||
- Public export URL (CSV): `https://docs.google.com/spreadsheets/d/1E2e_gT_K5AwSRCDLDTa2UetZTkHmBOcz0kFbBUNUNBA/export?format=csv`
|
||||
|
||||
## Sheet Structure
|
||||
|
||||
| Row | Content |
|
||||
| --- | --- |
|
||||
| 1 | Header: title in col A, dates in cols D+ (format `M/D/YYYY`) |
|
||||
| 2 | Venue per date (irrelevant for pricing) |
|
||||
| 3 | Total attendees per date |
|
||||
| 4+ | Member rows: Name (col A), Tier (col B), Total (col C), attendance TRUE/FALSE (cols D+) |
|
||||
|
||||
Member rows end when the Name column is empty.
|
||||
|
||||
## Tiers
|
||||
|
||||
| Code | Meaning | Pays from this sheet? |
|
||||
| --- | --- | --- |
|
||||
| A | Adult | Yes |
|
||||
| J | Junior | No (paid via separate attendance sheet) |
|
||||
| X | Exempt | No |
|
||||
|
||||
## Fee Rules (Adults only)
|
||||
|
||||
Fees are calculated per calendar month based on the number of attended practices in that month.
|
||||
|
||||
| Practices in month | Fee |
|
||||
| --- | --- |
|
||||
| 0 | 0 CZK |
|
||||
| 1 | 200 CZK |
|
||||
| 2 or more | 750 CZK |
|
||||
|
||||
## Payment Matching
|
||||
|
||||
### Bank Account
|
||||
|
||||
- Fio banka transparent account: `2800359168/2010`
|
||||
- Owner: Nathan Heilmann
|
||||
- Public view: `https://ib.fio.cz/ib/transparent?a=2800359168`
|
||||
|
||||
### Data Access
|
||||
|
||||
- **Without API token**: scrape the public transparent account HTML page
|
||||
- **With API token**: Fio REST API at `https://fioapi.fio.cz/v1/rest/periods/{token}/{from}/{to}/transactions.json`
|
||||
- Token is generated in Fio internetbanking (Settings → API)
|
||||
- Rate limit: 1 request per 30 seconds per token
|
||||
- Available fields: date, amount, currency, sender account, sender name, VS, SS, KS, user identification, message, type, and more
|
||||
|
||||
### Matching Approach
|
||||
|
||||
Payments are matched to members using best-effort heuristics, with uncertain matches flagged for manual review.
|
||||
|
||||
1. **Name matching**: Normalize (strip diacritics, lowercase) sender name and message text, compare against member names and nicknames
|
||||
2. **Month parsing**: Extract Czech month names (leden, únor, ...) and numeric patterns (01/26, 1/2026) from the message
|
||||
3. **Amount validation**: Check if amount aligns with expected fees (200, 750, or multiples)
|
||||
4. **Multi-person splitting**: When a message references multiple members, split the payment across them
|
||||
|
||||
### Advance Payments
|
||||
|
||||
If a payment references a month with no attendance data yet, it is tracked as **credit** on the member's account. The credit is applied once that month's attendance is recorded.
|
||||
|
||||
## PII Constraint
|
||||
|
||||
No member names or personal data are committed to git. All data is fetched at runtime from the Google Sheet and bank account.
|
||||
Reference in New Issue
Block a user