feat: improve attendance parsing logic and fix payment date formatting
All checks were successful
Build and Push / build (push) Successful in 8s
Deploy to K8s / deploy (push) Successful in 12s

This commit is contained in:
Jan Novak
2026-03-02 15:06:28 +01:00
parent 70d6794a3c
commit 99b23199b1
4 changed files with 45 additions and 7 deletions

View File

@@ -1,6 +1,6 @@
[project] [project]
name = "fuj-management" name = "fuj-management"
version = "0.05" version = "0.06"
description = "Management tools for FUJ (Frisbee Ultimate Jablonec)" description = "Management tools for FUJ (Frisbee Ultimate Jablonec)"
dependencies = [ dependencies = [
"flask>=3.1.3", "flask>=3.1.3",

View File

@@ -58,14 +58,31 @@ def calculate_fee(attendance_count: int) -> int:
def get_members(rows: list[list[str]]) -> list[tuple[str, str, list[str]]]: def get_members(rows: list[list[str]]) -> list[tuple[str, str, list[str]]]:
"""Parse member rows. Returns list of (name, tier, row).""" """Parse member rows. Returns list of (name, tier, row).
Stopped at row where first column contains '# last line'.
Skips rows starting with '#'.
"""
members = [] members = []
for row in rows[1:]: for row in rows[1:]:
name = row[COL_NAME].strip() if len(row) > COL_NAME else "" if not row or len(row) <= COL_NAME:
if not name or name.lower() in ("jméno", "name", "jmeno"):
continue continue
first_col = row[COL_NAME].strip()
# Terminator for rows to process
if "# last line" in first_col.lower():
break
# Ignore comments
if first_col.startswith("#"):
continue
if not first_col or first_col.lower() in ("jméno", "name", "jmeno"):
continue
tier = row[COL_TIER].strip().upper() if len(row) > COL_TIER else "" tier = row[COL_TIER].strip().upper() if len(row) > COL_TIER else ""
members.append((name, tier, row)) members.append((first_col, tier, row))
return members return members

View File

@@ -159,6 +159,27 @@ def infer_transaction_details(tx: dict, member_names: list[str]) -> dict:
} }
def format_date(val) -> str:
"""Normalize date from Google Sheet (handles serial numbers and strings)."""
if val is None or val == "":
return ""
# Handle Google Sheets serial dates (number of days since 1899-12-30)
if isinstance(val, (int, float)):
base_date = datetime(1899, 12, 30)
dt = base_date + timedelta(days=val)
return dt.strftime("%Y-%m-%d")
val_str = str(val).strip()
if not val_str:
return ""
# If already YYYY-MM-DD, return as is
if len(val_str) == 10 and val_str[4] == "-" and val_str[7] == "-":
return val_str
return val_str
def fetch_sheet_data(spreadsheet_id: str, credentials_path: str) -> list[dict]: def fetch_sheet_data(spreadsheet_id: str, credentials_path: str) -> list[dict]:
"""Fetch all rows from the Google Sheet and convert to a list of dicts.""" """Fetch all rows from the Google Sheet and convert to a list of dicts."""
service = get_sheets_service(credentials_path) service = get_sheets_service(credentials_path)
@@ -197,7 +218,7 @@ def fetch_sheet_data(spreadsheet_id: str, credentials_path: str) -> list[dict]:
return row[idx] if idx != -1 and idx < len(row) else "" return row[idx] if idx != -1 and idx < len(row) else ""
tx = { tx = {
"date": get_val(idx_date), "date": format_date(get_val(idx_date)),
"amount": get_val(idx_amount), "amount": get_val(idx_amount),
"manual_fix": get_val(idx_manual), "manual_fix": get_val(idx_manual),
"person": get_val(idx_person), "person": get_val(idx_person),

2
uv.lock generated
View File

@@ -199,7 +199,7 @@ wheels = [
[[package]] [[package]]
name = "fuj-management" name = "fuj-management"
version = "0.2" version = "0.5"
source = { virtual = "." } source = { virtual = "." }
dependencies = [ dependencies = [
{ name = "flask" }, { name = "flask" },