""" Manuell status per deltaker (migrasjon 087, 2026-08-18). Bruker: "Vi må manuelt kunne sette Dsq, Rtd, Dnf, og fns [DNS]." Tournament-bredt (ikke per runde), overstyrer BÅDE det beregnede til-par-tallet og en ev. Cut-status, og blokkerer videre score-registrering i ALLE runder (strengere enn Cut, som kun blokkerer runder ETTER cut-punktet). """ import pytest from fastapi import HTTPException from app.auth import CurrentUser from app.routers.individual_tournaments import ( HoleUpdate as TournamentHoleUpdate, TournamentParticipantUpdate, individual_leaderboard, update_hole as tournament_update_hole, update_tournament_participant, ) from tests.conftest import ( add_membership, create_org, create_org_hole, create_course, create_player, create_tee, create_tournament, create_tournament_participant, create_tournament_round, create_tournament_round_participant, create_user, ) import app.db as app_db async def _score_holes(tournament_id, round_id, rp_id, org_id, user_id, scores: list[int]) -> None: user = CurrentUser(user_id=user_id) for n, gross in enumerate(scores, start=1): await tournament_update_hole( tournament_id, round_id, rp_id, n, TournamentHoleUpdate(gross_strokes=gross, expected_version=None), organization_id=org_id, user=user, ) async def _setup(org_id, owner_id, method="stroke_gross"): tournament_id = await create_tournament(org_id, name="Status-turnering") course_id = await create_course(org_id, name="Status Links") for n in range(1, 19): await create_org_hole(org_id, course_id, hole_number=n, par=4, stroke_index=n) tee_id = await create_tee(org_id, course_id) async with app_db.org_connection(org_id) as conn: await conn.execute( "UPDATE tournament SET format_type = 'individual', scoring_method = $2 WHERE id = $1", tournament_id, method, ) round1_id = await create_tournament_round(org_id, tournament_id, course_id, sequence=1) round2_id = await create_tournament_round(org_id, tournament_id, course_id, sequence=2) return tournament_id, course_id, tee_id, round1_id, round2_id @pytest.mark.parametrize("status", ["dsq", "rtd", "dnf", "dns"]) async def test_status_overrides_computed_total_label(pool, status): org_id = await create_org() owner_id = await create_user() await add_membership(org_id, owner_id, role="owner") tournament_id, course_id, tee_id, round1_id, round2_id = await _setup(org_id, owner_id) player_id = await create_player(org_id, display_name="Spiller") tp_id = await create_tournament_participant(org_id, tournament_id, player_id) rp_id = await create_tournament_round_participant(org_id, round1_id, tp_id, tee_id) await _score_holes(tournament_id, round1_id, rp_id, org_id, owner_id, [4] * 18) await update_tournament_participant( tournament_id, tp_id, TournamentParticipantUpdate(status=status), organization_id=org_id ) entries = await individual_leaderboard(tournament_id, organization_id=org_id) entry = next(e for e in entries if e.tournament_participant_id == tp_id) assert entry.total_label == status.upper() assert entry.is_leader is False assert entry.position is None assert entry.status == status async def test_status_overrides_even_a_cut_survivor(pool): """En DSQ-et spiller skal vises som DSQ, ikke CUT, selv om de tilfeldigvis også overlevde cutten.""" org_id = await create_org() owner_id = await create_user() await add_membership(org_id, owner_id, role="owner") tournament_id, course_id, tee_id, round1_id, round2_id = await _setup(org_id, owner_id) from app.routers.tournaments import TournamentUpdate, update_tournament from app.routers.individual_tournaments import apply_cut await update_tournament( tournament_id, TournamentUpdate(cut_after_round=1, cut_size=5), organization_id=org_id, ) player_id = await create_player(org_id, display_name="Spiller") tp_id = await create_tournament_participant(org_id, tournament_id, player_id) rp_id = await create_tournament_round_participant(org_id, round1_id, tp_id, tee_id) await _score_holes(tournament_id, round1_id, rp_id, org_id, owner_id, [4] * 18) await apply_cut(tournament_id, organization_id=org_id) await update_tournament_participant( tournament_id, tp_id, TournamentParticipantUpdate(status="dsq"), organization_id=org_id ) entries = await individual_leaderboard(tournament_id, organization_id=org_id) entry = next(e for e in entries if e.tournament_participant_id == tp_id) assert entry.total_label == "DSQ" assert entry.cut is False # var faktisk innenfor cut-grensen async def test_status_blocks_scoring_in_any_round_not_just_after_a_point(pool): """Strengere enn Cut: en DSQ-et/RTD-et/DNF-et/DNS-et spiller er blokkert i ALLE runder, ikke bare etter et gitt punkt.""" org_id = await create_org() owner_id = await create_user() await add_membership(org_id, owner_id, role="owner") tournament_id, course_id, tee_id, round1_id, round2_id = await _setup(org_id, owner_id) player_id = await create_player(org_id, display_name="Spiller") tp_id = await create_tournament_participant(org_id, tournament_id, player_id) rp1_id = await create_tournament_round_participant(org_id, round1_id, tp_id, tee_id) rp2_id = await create_tournament_round_participant(org_id, round2_id, tp_id, tee_id) await update_tournament_participant( tournament_id, tp_id, TournamentParticipantUpdate(status="dsq"), organization_id=org_id ) user = CurrentUser(user_id=owner_id) with pytest.raises(HTTPException) as exc_round1: await tournament_update_hole( tournament_id, round1_id, rp1_id, 1, TournamentHoleUpdate(gross_strokes=4, expected_version=None), organization_id=org_id, user=user, ) assert exc_round1.value.status_code == 403 with pytest.raises(HTTPException) as exc_round2: await tournament_update_hole( tournament_id, round2_id, rp2_id, 1, TournamentHoleUpdate(gross_strokes=4, expected_version=None), organization_id=org_id, user=user, ) assert exc_round2.value.status_code == 403 async def test_active_status_is_unaffected_default(pool): """Ingen regresjon -- default 'active' oppfører seg akkurat som før.""" org_id = await create_org() owner_id = await create_user() await add_membership(org_id, owner_id, role="owner") tournament_id, course_id, tee_id, round1_id, round2_id = await _setup(org_id, owner_id) player_id = await create_player(org_id, display_name="Spiller") tp_id = await create_tournament_participant(org_id, tournament_id, player_id) rp_id = await create_tournament_round_participant(org_id, round1_id, tp_id, tee_id) await _score_holes(tournament_id, round1_id, rp_id, org_id, owner_id, [4] * 18) entries = await individual_leaderboard(tournament_id, organization_id=org_id) entry = next(e for e in entries if e.tournament_participant_id == tp_id) assert entry.status == "active" assert entry.total_label == "E" assert entry.position == "1"