import sys from pathlib import Path from datetime import datetime import re from flask import Flask, render_template # Add scripts directory to path to allow importing from it scripts_dir = Path(__file__).parent / "scripts" sys.path.append(str(scripts_dir)) from attendance import get_members_with_fees, SHEET_ID as ATTENDANCE_SHEET_ID from match_payments import reconcile, fetch_sheet_data, DEFAULT_SPREADSHEET_ID as PAYMENTS_SHEET_ID app = Flask(__name__) @app.route("/") def index(): # Redirect root to /fees for convenience while there are no other apps return '' @app.route("/fees") def fees(): attendance_url = f"https://docs.google.com/spreadsheets/d/{ATTENDANCE_SHEET_ID}/edit" payments_url = f"https://docs.google.com/spreadsheets/d/{PAYMENTS_SHEET_ID}/edit" members, sorted_months = get_members_with_fees() if not members: return "No data." # Filter to adults only for display results = [(name, fees) for name, tier, fees in members if tier == "A"] # Format month labels month_labels = { m: datetime.strptime(m, "%Y-%m").strftime("%b %Y") for m in sorted_months } monthly_totals = {m: 0 for m in sorted_months} formatted_results = [] for name, month_fees in results: row = {"name": name, "months": []} for m in sorted_months: fee, count = month_fees.get(m, (0, 0)) monthly_totals[m] += fee cell = f"{fee} CZK ({count})" if count > 0 else "-" row["months"].append(cell) formatted_results.append(row) return render_template( "fees.html", months=[month_labels[m] for m in sorted_months], results=formatted_results, totals=[f"{monthly_totals[m]} CZK" for m in sorted_months], attendance_url=attendance_url, payments_url=payments_url ) @app.route("/reconcile") def reconcile_view(): attendance_url = f"https://docs.google.com/spreadsheets/d/{ATTENDANCE_SHEET_ID}/edit" payments_url = f"https://docs.google.com/spreadsheets/d/{PAYMENTS_SHEET_ID}/edit" # Use hardcoded credentials path for now, consistent with other scripts credentials_path = ".secret/fuj-management-bot-credentials.json" members, sorted_months = get_members_with_fees() if not members: return "No data." transactions = fetch_sheet_data(PAYMENTS_SHEET_ID, credentials_path) result = reconcile(members, sorted_months, transactions) # Format month labels month_labels = { m: datetime.strptime(m, "%Y-%m").strftime("%b %Y") for m in sorted_months } # Filter to adults for the main table adult_names = sorted([name for name, tier, _ in members if tier == "A"]) formatted_results = [] for name in adult_names: data = result["members"][name] row = {"name": name, "months": [], "balance": data["total_balance"]} for m in sorted_months: mdata = data["months"].get(m, {"expected": 0, "paid": 0}) expected = mdata["expected"] paid = int(mdata["paid"]) cell_status = "" if expected == 0 and paid == 0: cell = "-" elif paid >= expected and expected > 0: cell = "OK" elif paid > 0: cell = f"{paid}/{expected}" else: cell = f"UNPAID {expected}" row["months"].append(cell) row["balance"] = data["total_balance"] # Updated to use total_balance formatted_results.append(row) # Format credits and debts credits = sorted([{"name": n, "amount": a["total_balance"]} for n, a in result["members"].items() if a["total_balance"] > 0], key=lambda x: x["name"]) debts = sorted([{"name": n, "amount": abs(a["total_balance"])} for n, a in result["members"].items() if a["total_balance"] < 0], key=lambda x: x["name"]) # Format unmatched unmatched = result["unmatched"] return render_template( "reconcile.html", months=[month_labels[m] for m in sorted_months], results=formatted_results, credits=credits, debts=debts, unmatched=unmatched, attendance_url=attendance_url, payments_url=payments_url ) @app.route("/payments") def payments(): attendance_url = f"https://docs.google.com/spreadsheets/d/{ATTENDANCE_SHEET_ID}/edit" payments_url = f"https://docs.google.com/spreadsheets/d/{PAYMENTS_SHEET_ID}/edit" credentials_path = ".secret/fuj-management-bot-credentials.json" transactions = fetch_sheet_data(PAYMENTS_SHEET_ID, credentials_path) # Group transactions by person grouped = {} for tx in transactions: person = str(tx.get("person", "")).strip() if not person: person = "Unmatched / Unknown" # Handle multiple people (comma separated) people = [p.strip() for p in person.split(",") if p.strip()] for p in people: # Strip markers clean_p = re.sub(r"\[\?\]\s*", "", p) if clean_p not in grouped: grouped[clean_p] = [] grouped[clean_p].append(tx) # Sort people and their transactions sorted_people = sorted(grouped.keys()) for p in sorted_people: # Sort by date descending grouped[p].sort(key=lambda x: str(x.get("date", "")), reverse=True) return render_template( "payments.html", grouped_payments=grouped, sorted_people=sorted_people, attendance_url=attendance_url, payments_url=payments_url ) if __name__ == "__main__": app.run(debug=True, host='0.0.0.0', port=5001)