Erstumsetzung: OAMC Turnierauswertung (AP 0–7, 9)
* Datenmodell + Alembic-Initialmigration (Plan §4), Seed Saison 2026 * Wertungs-Engine (Plan §3.3), regelbasiert je Kategorie/Saison - Abnahmetest gegen die Ergebnisliste 2026-05-31 * Meisterschaftsberechnung mit Streichresultaten + Tie-Break (PLATZHALTER-Punktetabelle, O-1 offen) * Ingest-API (idempotent, dry_run) inkl. Excel-Leser und Fahrer-Matching/Merge * Zeitmessungs-Endpoint (Batch, idempotent, unzugeordnet/unplausibel) + SSE-Anzeige - Mess-Pi-Client bewusst NICHT enthalten (docs/zeitmessung-endpoint.md) * Frontend: öffentliche Seiten + internes Backend (Jinja2/HTMX, kein Build) * Auslieferung: Docker (multi-arch) + docker-compose sowie Debian-Paket/APT-Repo * 57 Tests grün gegen echte PostgreSQL-Testdatenbank Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
"""Seed fuer Saison 2026 — abgeleitet aus plan.md §3.2 und §3.4."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from oamc.meisterschaft.berechnung import PLATZHALTER_PUNKTETABELLE
|
||||
from oamc.models import Klasse, Meisterschaft, Saison, Verein
|
||||
from oamc.models.enums import Kategorie
|
||||
|
||||
# "Turniere in der Saison" -> "davon gewertet" (Plan §3.4)
|
||||
STREICHRESULTATE_2026 = {
|
||||
"12": 8, "11": 8, "10": 8, "9": 7, "8": 6, "7": 5, "6": 4, "5": 3, "4": 2,
|
||||
}
|
||||
|
||||
# Jugendklassen: Einteilung strikt nach Jahrgang (Plan §3.2)
|
||||
JUGENDKLASSEN = [
|
||||
("J 1", [2019, 2018, 2017], 110, 5.5, "Kindermotorrad", 7),
|
||||
("J 2", [2016, 2015], 110, 5.5, "Kindermotorrad", None),
|
||||
("J 3", [2014, 2013], 125, 11.0, "Mofa / Motorrad / Roller", None),
|
||||
("J 4", [2012, 2011], 125, 11.0, "Mofa / Motorrad / Roller", None),
|
||||
("J 5", [2010, 2009, 2008], 125, 11.0, "Mofa / Motorrad / Roller (bis 18. Geburtstag)", None),
|
||||
]
|
||||
|
||||
# Erwachsenenklassen: konkrete Fahrzeugzuordnung ist offene Frage O-2.
|
||||
STAMMKLASSEN = [f"S {i}" for i in range(1, 10)]
|
||||
ANFAENGERKLASSEN = [f"A {i}" for i in range(1, 5)]
|
||||
|
||||
VEREINE = [
|
||||
("OAMC Reinheim e.V. im ADAC", "OAMC Reinheim", "ADAC Hessen-Thueringen"),
|
||||
("MSC Hainstadt", "Hainstadt", "ADAC Hessen-Thueringen"),
|
||||
("MSC Schotten", "Schotten", "ADAC Hessen-Thueringen"),
|
||||
("PMS Kassel", "Kassel", "ADAC Hessen-Thueringen"),
|
||||
]
|
||||
|
||||
|
||||
def _get_or_create(db: Session, model, defaults=None, **kwargs):
|
||||
obj = db.scalars(select(model).filter_by(**kwargs)).first()
|
||||
if obj is not None:
|
||||
return obj, False
|
||||
obj = model(**kwargs, **(defaults or {}))
|
||||
db.add(obj)
|
||||
db.flush()
|
||||
return obj, True
|
||||
|
||||
|
||||
def seed_saison_2026(db: Session) -> dict[str, int]:
|
||||
"""Idempotenter Seed. Rueckgabe: Zaehler der neu angelegten Objekte."""
|
||||
|
||||
zaehler = {"saison": 0, "verein": 0, "klasse": 0, "meisterschaft": 0}
|
||||
|
||||
saison, neu = _get_or_create(
|
||||
db,
|
||||
Saison,
|
||||
jahr=2026,
|
||||
defaults={
|
||||
"turnierordnung_version": "MT-D2025 (zu verifizieren, Plan §10)",
|
||||
"streichresultate_tabelle": STREICHRESULTATE_2026,
|
||||
"nenngeld_cent": 1000,
|
||||
"aktiv": True,
|
||||
},
|
||||
)
|
||||
zaehler["saison"] += int(neu)
|
||||
|
||||
for name, kurz, gau in VEREINE:
|
||||
_, neu = _get_or_create(
|
||||
db, Verein, name=name, defaults={"kurzname": kurz, "adac_gau": gau, "aktiv": True}
|
||||
)
|
||||
zaehler["verein"] += int(neu)
|
||||
|
||||
sortierung = 0
|
||||
for code, jahrgaenge, ccm, kw, typ, mindestalter in JUGENDKLASSEN:
|
||||
sortierung += 1
|
||||
_, neu = _get_or_create(
|
||||
db,
|
||||
Klasse,
|
||||
saison_jahr=2026,
|
||||
code=code,
|
||||
defaults={
|
||||
"kategorie": Kategorie.JUGEND,
|
||||
"bezeichnung": f"Jugend {code} (Jahrgang {'/'.join(map(str, jahrgaenge))})",
|
||||
"jahrgaenge": jahrgaenge,
|
||||
"ccm_max": ccm,
|
||||
"kw_max": kw,
|
||||
"fahrzeugtyp": typ,
|
||||
"mindestalter_am_veranstaltungstag": mindestalter,
|
||||
"sortierung": sortierung,
|
||||
},
|
||||
)
|
||||
zaehler["klasse"] += int(neu)
|
||||
|
||||
for code in STAMMKLASSEN:
|
||||
sortierung += 1
|
||||
_, neu = _get_or_create(
|
||||
db, Klasse, saison_jahr=2026, code=code,
|
||||
defaults={
|
||||
"kategorie": Kategorie.STAMM,
|
||||
"bezeichnung": f"Stammfahrer {code}",
|
||||
"fahrzeugtyp": None,
|
||||
"sortierung": sortierung,
|
||||
"notiz": "O-2 offen: Fahrzeugtyp/Hubraum/kW noch zuzuordnen",
|
||||
},
|
||||
)
|
||||
zaehler["klasse"] += int(neu)
|
||||
|
||||
for code in ANFAENGERKLASSEN:
|
||||
sortierung += 1
|
||||
_, neu = _get_or_create(
|
||||
db, Klasse, saison_jahr=2026, code=code,
|
||||
defaults={
|
||||
"kategorie": Kategorie.ANFAENGER,
|
||||
"bezeichnung": f"Anfaenger {code}",
|
||||
"fahrzeugtyp": None,
|
||||
"sortierung": sortierung,
|
||||
"notiz": "O-2 offen: Fahrzeugtyp/Hubraum/kW noch zuzuordnen",
|
||||
},
|
||||
)
|
||||
zaehler["klasse"] += int(neu)
|
||||
|
||||
platzhalter_regelwerk = {
|
||||
"punkte": {str(k): v for k, v in PLATZHALTER_PUNKTETABELLE.items()},
|
||||
"_hinweis": "O-1 offen: PLATZHALTER-Punktetabelle, nicht offiziell!",
|
||||
}
|
||||
|
||||
_, neu = _get_or_create(
|
||||
db, Meisterschaft, saison_jahr=2026, bezeichnung="HTH Erwachsene 2026",
|
||||
defaults={"kategorie": Kategorie.STAMM, "regelwerk": platzhalter_regelwerk},
|
||||
)
|
||||
zaehler["meisterschaft"] += int(neu)
|
||||
|
||||
jugendklassen = db.scalars(
|
||||
select(Klasse).where(Klasse.saison_jahr == 2026, Klasse.kategorie == Kategorie.JUGEND)
|
||||
).all()
|
||||
for k in jugendklassen:
|
||||
_, neu = _get_or_create(
|
||||
db, Meisterschaft, saison_jahr=2026, bezeichnung=f"HTH Jugend {k.code} 2026",
|
||||
defaults={
|
||||
"kategorie": Kategorie.JUGEND,
|
||||
"klasse_id": k.id,
|
||||
"regelwerk": platzhalter_regelwerk,
|
||||
},
|
||||
)
|
||||
zaehler["meisterschaft"] += int(neu)
|
||||
|
||||
return zaehler
|
||||
Reference in New Issue
Block a user