"""Tests für Auszahlungs-Anträge mit Genehmigung (router/hours_payouts.py).""" import pytest import pytest_asyncio from httpx import AsyncClient @pytest_asyncio.fixture(scope="session", loop_scope="session") async def payout_headers(client: AsyncClient): resp = await client.post("/api/v1/auth/register", json={ "company_name": "Payout GmbH", "first_name": "Paul", "last_name": "Out", "email": "admin@payoutgmbh.de", "password": "Secret123", }) assert resp.status_code == 201, resp.text return {"Authorization": f"Bearer {resp.json()['access_token']}"} @pytest.mark.asyncio(loop_scope="session") async def test_request_disabled_by_default(client: AsyncClient, payout_headers): r = await client.post("/api/v1/hr/payouts/request", json={"hours": 4}, headers=payout_headers) assert r.status_code == 403 @pytest.mark.asyncio(loop_scope="session") async def test_enable_and_request_approve(client: AsyncClient, payout_headers): # Firma schaltet Selbstbedienung frei up = await client.patch("/api/v1/companies/me", json={"payout_request_enabled": True}, headers=payout_headers) assert up.status_code == 200, up.text assert up.json()["payout_request_enabled"] is True # Antrag stellen – Status requested, kein Saldo-Abzug r = await client.post("/api/v1/hr/payouts/request", json={"hours": 5, "note": "Bitte auszahlen"}, headers=payout_headers) assert r.status_code == 201, r.text pid = r.json()["id"] assert r.json()["status"] == "requested" bal = await client.get("/api/v1/absences/overtime-balance", headers=payout_headers) assert float(bal.json()["taken_hours"]) == 0.0 # HR genehmigt – jetzt Saldo-Abzug ap = await client.post(f"/api/v1/hr/payouts/{pid}/approve", json={}, headers=payout_headers) assert ap.status_code == 200, ap.text assert ap.json()["status"] == "approved" bal2 = await client.get("/api/v1/absences/overtime-balance", headers=payout_headers) assert float(bal2.json()["taken_hours"]) == 5.0 # Erneutes Genehmigen scheitert ap2 = await client.post(f"/api/v1/hr/payouts/{pid}/approve", json={}, headers=payout_headers) assert ap2.status_code == 409 @pytest.mark.asyncio(loop_scope="session") async def test_reject_no_deduction(client: AsyncClient, payout_headers): r = await client.post("/api/v1/hr/payouts/request", json={"hours": 3}, headers=payout_headers) pid = r.json()["id"] before = float((await client.get("/api/v1/absences/overtime-balance", headers=payout_headers)).json()["taken_hours"]) rej = await client.post(f"/api/v1/hr/payouts/{pid}/reject", json={"rejection_reason": "kein Budget"}, headers=payout_headers) assert rej.status_code == 200 assert rej.json()["status"] == "rejected" assert rej.json()["rejection_reason"] == "kein Budget" after = float((await client.get("/api/v1/absences/overtime-balance", headers=payout_headers)).json()["taken_hours"]) assert after == before # kein Abzug bei Ablehnung @pytest.mark.asyncio(loop_scope="session") async def test_cancel_own_request(client: AsyncClient, payout_headers): r = await client.post("/api/v1/hr/payouts/request", json={"hours": 2}, headers=payout_headers) pid = r.json()["id"] c = await client.post(f"/api/v1/hr/payouts/{pid}/cancel", json={}, headers=payout_headers) assert c.status_code == 200 assert c.json()["status"] == "cancelled" # Genehmigen eines zurückgezogenen Antrags scheitert ap = await client.post(f"/api/v1/hr/payouts/{pid}/approve", json={}, headers=payout_headers) assert ap.status_code == 409