import argparse import json from pathlib import Path from typing import List, Dict from openpyxl import Workbook from openpyxl.styles import Font from openpyxl.utils import get_column_letter MATCH_FIELDS: List[Dict[str, str]] = [ { "name": "competition_code", "label": "Kód soutěže", "help": "Např. A1A. Použije se, pokud není vyplněno competition_external_id.", }, { "name": "competition_external_id", "label": "External ID soutěže (UUID)", "help": "UUID soutěže z odkazu na fotbal.cz. Má přednost před competition_code.", }, {"name": "round", "label": "Kolo", "help": "Např. 2. kolo, 10. kolo atd."}, { "name": "is_home", "label": "Domácí / venku", "help": "Hodnota home/away (nebo 1/0, true/false, yes/no).", }, {"name": "opponent_name", "label": "Soupeř", "help": "Název soupeře."}, { "name": "opponent_club_link", "label": "Odkaz na klub soupeře", "help": "URL na klub soupeře z fotbal.cz – z URL se přečte UUID pro loga.", }, { "name": "external_match_id", "label": "External ID zápasu (UUID)", "help": "UUID zápasu; pokud není, vezme se UUID z match_link.", }, { "name": "kickoff_date", "label": "Datum výkopu (YYYY-MM-DD)", "help": "Datum zápasu, např. 2025-03-15.", }, { "name": "kickoff_time", "label": "Čas výkopu (HH:MM)", "help": "Čas zápasu, např. 17:00.", }, { "name": "score_fulltime", "label": "Konečný stav", "help": "Např. 2:1. Může být prázdné pro budoucí zápasy.", }, { "name": "score_halftime", "label": "Poločasu", "help": "Např. 1:0. Volitelné.", }, { "name": "match_link", "label": "Odkaz na zápas", "help": "URL na detail zápasu na is.fotbal.cz.", }, {"name": "venue", "label": "Hřiště", "help": "Název hřiště / stadionu."}, {"name": "note", "label": "Poznámka", "help": "Libovolná poznámka k zápasu."}, ] TABLE_FIELDS: List[Dict[str, str]] = [ { "name": "competition_code", "label": "Kód soutěže", "help": "Např. A1A. Použije se, pokud není vyplněno competition_external_id.", }, { "name": "competition_external_id", "label": "External ID soutěže (UUID)", "help": "UUID soutěže z odkazu na fotbal.cz. Má přednost před competition_code.", }, {"name": "rank", "label": "Pořadí", "help": "Pozice v tabulce, např. 1."}, {"name": "team_name", "label": "Tým", "help": "Název týmu."}, { "name": "team_club_link", "label": "Odkaz na klub týmu", "help": "URL na klub z fotbal.cz – z URL se přečte UUID pro loga.", }, {"name": "played", "label": "Zápasy", "help": "Počet odehraných zápasů."}, {"name": "wins", "label": "Výhry", "help": "Počet výher."}, {"name": "draws", "label": "Remízy", "help": "Počet remíz."}, {"name": "losses", "label": "Prohry", "help": "Počet proher."}, { "name": "score", "label": "Skóre", "help": "Souhrnné skóre ve formátu góly:inkasované, např. 45:17.", }, {"name": "points", "label": "Body", "help": "Počet bodů v tabulce."}, ] def _auto_width(sheet): for column_cells in sheet.columns: max_length = 0 column = column_cells[0].column for cell in column_cells: value = str(cell.value) if cell.value is not None else "" if len(value) > max_length: max_length = len(value) adjusted = max(max_length + 2, 12) sheet.column_dimensions[get_column_letter(column)].width = adjusted def generate_workbook(output_dir: Path) -> None: wb = Workbook() ws_matches = wb.active ws_matches.title = "matches" ws_matches.append([f["name"] for f in MATCH_FIELDS]) for cell in ws_matches[1]: cell.font = Font(bold=True) _auto_width(ws_matches) ws_tables = wb.create_sheet(title="tables") ws_tables.append([f["name"] for f in TABLE_FIELDS]) for cell in ws_tables[1]: cell.font = Font(bold=True) _auto_width(ws_tables) path = output_dir / "manual_facr_templates.xlsx" wb.save(path) def generate_forms_spec(output_dir: Path) -> None: spec = { "matches_form": { "title": "Manuální zápasy (FAČR)", "description": "Formulář pro ruční zadání zápasů ve struktuře odpovídající CSV/XLSX/JSON importu.", "fields": [ { "name": f["name"], "label": f["label"], "help_text": f["help"], "type": "text", "required": f["name"] in {"competition_code", "competition_external_id", "is_home", "opponent_name"}, } for f in MATCH_FIELDS ], }, "tables_form": { "title": "Manuální tabulky (FAČR)", "description": "Formulář pro ruční zadání tabulek soutěží ve struktuře odpovídající CSV/XLSX/JSON importu.", "fields": [ { "name": f["name"], "label": f["label"], "help_text": f["help"], "type": "text", "required": f["name"] in {"competition_code", "competition_external_id", "rank", "team_name"}, } for f in TABLE_FIELDS ], }, } path = output_dir / "manual_facr_google_forms.json" path.write_text(json.dumps(spec, ensure_ascii=False, indent=2), encoding="utf-8") def main() -> None: parser = argparse.ArgumentParser( description=( "Generate manual FACR Excel templates (matches/tables) and a Google Forms " "field specification from a single schema." ) ) parser.add_argument( "--output-dir", type=str, default=None, help=( "Output directory for generated files. " "Defaults to /static/manual-facr." ), ) args = parser.parse_args() if args.output_dir: output_dir = Path(args.output_dir) else: output_dir = Path(__file__).resolve().parents[1] / "static" / "manual-facr" output_dir.mkdir(parents=True, exist_ok=True) generate_workbook(output_dir) generate_forms_spec(output_dir) if __name__ == "__main__": main()