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,67 @@
|
||||
"""Excel-Import (AP 4/8). Spaltenzuordnung gegen die realen Vorlagen noch offen (O-12)."""
|
||||
|
||||
import io
|
||||
|
||||
from openpyxl import Workbook
|
||||
|
||||
from oamc.importer.xlsx import lese_ergebnisliste, lese_nennliste
|
||||
from oamc.seeds import seed_saison_2026
|
||||
from tests import factories as f
|
||||
|
||||
HEAD = {"X-API-Key": "test-key"}
|
||||
|
||||
|
||||
def _xlsx(rows: list[list]) -> bytes:
|
||||
wb = Workbook()
|
||||
ws = wb.active
|
||||
for r in rows:
|
||||
ws.append(r)
|
||||
buf = io.BytesIO()
|
||||
wb.save(buf)
|
||||
return buf.getvalue()
|
||||
|
||||
|
||||
def test_lese_nennliste_mappt_spalten():
|
||||
daten = _xlsx([
|
||||
["Start-Nr.", "Voller Name", "Regionalclub", "Klasse", "Geburtsjahr"],
|
||||
[32, "Gál-Szász Péter", "OAMC Reinheim", "J 2", 2015],
|
||||
[33, "Bernius Meik", "Hainstadt", "S 6", 1985],
|
||||
])
|
||||
bulk = lese_nennliste(daten, quelle="test", idempotenz_schluessel="k1")
|
||||
assert [s.startnummer for s in bulk.starts] == [32, 33]
|
||||
assert bulk.starts[0].fahrer.nachname == "Gál-Szász"
|
||||
assert bulk.starts[0].fahrer.vorname == "Péter"
|
||||
assert bulk.starts[0].klasse == "J 2"
|
||||
|
||||
|
||||
def test_lese_ergebnisliste_liest_zeit_und_fehler():
|
||||
daten = _xlsx([
|
||||
["Start-Nr.", "Voller Name", "Klasse", "Summe Zeit", "Summe Fehler", "Gesamt", "Platzierung"],
|
||||
[1, "Bernius Meik", "S 6", "105,43", 0, "105,43", 1],
|
||||
])
|
||||
bulk = lese_ergebnisliste(daten, quelle="test", idempotenz_schluessel="k2")
|
||||
e = bulk.ergebnisse[0]
|
||||
assert str(e.summe_zeit) == "105.43"
|
||||
assert e.summe_fehler == 0
|
||||
assert str(e.gesamt_erwartet) == "105.43"
|
||||
|
||||
|
||||
def test_import_xlsx_endpoint_dry_run(client):
|
||||
db = client.db
|
||||
seed_saison_2026(db)
|
||||
t = f.turnier(db)
|
||||
db.flush()
|
||||
daten = _xlsx([
|
||||
["Start-Nr.", "Voller Name", "Klasse", "Geburtsjahr"],
|
||||
[5, "Freund Philipp", "J 3", 2014],
|
||||
])
|
||||
r = client.post(
|
||||
f"/api/v1/turniere/{t.id}/import/xlsx?dry_run=true",
|
||||
headers=HEAD,
|
||||
data={"art": "nennliste", "idempotenz_schluessel": "xlsx-1"},
|
||||
files={"datei": ("nenn.xlsx", daten,
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")},
|
||||
)
|
||||
assert r.status_code == 200, r.text
|
||||
assert r.json()["dry_run"] is True
|
||||
assert r.json()["angelegt"] == 1
|
||||
Reference in New Issue
Block a user