120 lines
4.3 KiB
Python
120 lines
4.3 KiB
Python
"""HTTP routes for parental-leave data: manual entry + scraper status.
|
|
|
|
POST /api/parental-leave/manual — manual entry (always available)
|
|
GET /api/parental-leave/{personal_data_uuid}/{child_id} — latest snapshot
|
|
GET /api/parental-leave/{personal_data_uuid}/{child_id}/history — all snapshots
|
|
|
|
Scraper endpoints (POST /api/fetch-data/start, GET /api/fetch-data/poll,
|
|
POST /api/fetch-data/cancel) are stubs returning 501 until the legal gate
|
|
clears (ARCHITECTURE.md §2.3).
|
|
"""
|
|
|
|
from uuid import UUID
|
|
|
|
from fastapi import APIRouter, HTTPException, status
|
|
from starlette.requests import Request
|
|
|
|
from app.config import settings
|
|
from app.dependencies import CurrentUserDep, ParentalLeaveRepositoryDep
|
|
from app.main import limiter
|
|
from app.models.parental_leave import (
|
|
ManualFetchRequest,
|
|
ParentalLeaveFetchResponse,
|
|
)
|
|
from app.services.fetch_data_service import ManualFetchService
|
|
from app.utils.errors import ValidationError
|
|
|
|
router = APIRouter(prefix="/api/parental-leave", tags=["parental-leave"])
|
|
scraper_router = APIRouter(prefix="/api/fetch-data", tags=["fetch-data"])
|
|
|
|
_SCRAPER_DISABLED = HTTPException(
|
|
status.HTTP_501_NOT_IMPLEMENTED,
|
|
"FK scraping is disabled pending legal/ToS + BankID review (§2.3). "
|
|
"Use /api/parental-leave/manual for data entry.",
|
|
)
|
|
_SCRAPER_NOT_IMPLEMENTED = HTTPException(
|
|
status.HTTP_501_NOT_IMPLEMENTED,
|
|
"FK scraper is not yet implemented.",
|
|
)
|
|
|
|
|
|
@router.post(
|
|
"/manual", response_model=ParentalLeaveFetchResponse, status_code=status.HTTP_201_CREATED
|
|
)
|
|
async def save_manual_entry(
|
|
payload: ManualFetchRequest,
|
|
repo: ParentalLeaveRepositoryDep,
|
|
_current_user: CurrentUserDep,
|
|
) -> ParentalLeaveFetchResponse:
|
|
service = ManualFetchService(repo)
|
|
try:
|
|
fetch = await service.save_manual_entry(
|
|
personal_data_uuid=payload.personal_data_uuid,
|
|
workspace_id=payload.workspace_id,
|
|
child_id=payload.child_id,
|
|
total_days=payload.total_days,
|
|
days_used=payload.days_used,
|
|
reserved_days_total=payload.reserved_days_total,
|
|
reserved_days_left=payload.reserved_days_left,
|
|
transferable_days_left=payload.transferable_days_left,
|
|
dubbeldagar_left=payload.dubbeldagar_left,
|
|
sjukpenning_total=payload.sjukpenning_total,
|
|
sjukpenning_used=payload.sjukpenning_used,
|
|
lagsta_niva_total=payload.lagsta_niva_total,
|
|
lagsta_niva_used=payload.lagsta_niva_used,
|
|
)
|
|
except ValidationError as exc:
|
|
raise HTTPException(status.HTTP_422_UNPROCESSABLE_ENTITY, str(exc)) from exc
|
|
return ParentalLeaveFetchResponse.from_entity(fetch)
|
|
|
|
|
|
@router.get("/{personal_data_uuid}/{child_id}", response_model=ParentalLeaveFetchResponse | None)
|
|
async def get_latest(
|
|
personal_data_uuid: UUID,
|
|
child_id: UUID,
|
|
repo: ParentalLeaveRepositoryDep,
|
|
_current_user: CurrentUserDep,
|
|
) -> ParentalLeaveFetchResponse | None:
|
|
service = ManualFetchService(repo)
|
|
fetch = await service.get_latest(personal_data_uuid, child_id)
|
|
return ParentalLeaveFetchResponse.from_entity(fetch) if fetch else None
|
|
|
|
|
|
@router.get(
|
|
"/{personal_data_uuid}/{child_id}/history", response_model=list[ParentalLeaveFetchResponse]
|
|
)
|
|
async def get_history(
|
|
personal_data_uuid: UUID,
|
|
child_id: UUID,
|
|
repo: ParentalLeaveRepositoryDep,
|
|
_current_user: CurrentUserDep,
|
|
) -> list[ParentalLeaveFetchResponse]:
|
|
service = ManualFetchService(repo)
|
|
history = await service.list_history(personal_data_uuid, child_id)
|
|
return [ParentalLeaveFetchResponse.from_entity(f) for f in history]
|
|
|
|
|
|
# Scraper stubs — 501 until legal gate clears (settings.scraper_enabled).
|
|
@scraper_router.post("/start")
|
|
@limiter.limit("20/minute")
|
|
async def start_fetch(request: Request, _current_user: CurrentUserDep) -> None:
|
|
if not settings.scraper_enabled:
|
|
raise _SCRAPER_DISABLED
|
|
raise _SCRAPER_NOT_IMPLEMENTED
|
|
|
|
|
|
@scraper_router.get("/poll")
|
|
@limiter.limit("20/minute")
|
|
async def poll_fetch(request: Request, _current_user: CurrentUserDep) -> None:
|
|
if not settings.scraper_enabled:
|
|
raise _SCRAPER_DISABLED
|
|
raise _SCRAPER_NOT_IMPLEMENTED
|
|
|
|
|
|
@scraper_router.post("/cancel")
|
|
@limiter.limit("20/minute")
|
|
async def cancel_fetch(request: Request, _current_user: CurrentUserDep) -> None:
|
|
if not settings.scraper_enabled:
|
|
raise _SCRAPER_DISABLED
|
|
raise _SCRAPER_NOT_IMPLEMENTED
|