Files
timemaster/backend/app/routers/import_kimai.py
T
sysops 1fedd683e0 Initial commit – TimeMaster Zeiterfassung & HR-Tool
Stand: agent-06 (Audit-Log), agent-05 (Krankmeldung), agent-07 Phase 1 (Personalnummer),
Busylight-Pull-Integration, TOTP/2FA, Abwesenheiten, Zeiterfassung, Kiosk-Grundgerüst.
Migrations 0001–0023 deployed auf 192.168.1.137 + .164.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 20:03:27 +02:00

88 lines
2.6 KiB
Python

"""Router: Kimai CSV Import (nur HR / Admin)."""
import uuid
from typing import Annotated
from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile, status
from pydantic import BaseModel
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.dependencies import get_db, require_role
from app.models.user import User, UserRole
from app.services.kimai_import_service import (
ImportPreviewEntry,
ImportResult,
preview_kimai_import,
run_kimai_import,
)
router = APIRouter(prefix="/import", tags=["import"])
_allowed_roles = [UserRole.HR, UserRole.COMPANY_ADMIN, UserRole.SUPER_ADMIN]
class ImportPreviewResponse(BaseModel):
preview: list[ImportPreviewEntry]
time_count: int
absence_count: int
skip_count: int
errors: list[str]
class ImportRunResponse(BaseModel):
time_imported: int
absence_imported: int
skipped: int
errors: list[str]
@router.post("/kimai/preview", response_model=ImportPreviewResponse)
async def kimai_preview(
user_id: Annotated[str, Form()],
file: Annotated[UploadFile, File()],
current_user: User = require_role(*_allowed_roles),
db: AsyncSession = Depends(get_db),
):
"""Vorschau des Kimai-Imports (keine DB-Änderungen)."""
try:
target_id = uuid.UUID(user_id)
except ValueError:
raise HTTPException(status_code=400, detail="Ungültige user_id")
content = await file.read()
result: ImportResult = await preview_kimai_import(content, target_id, db)
time_count = sum(1 for p in result.preview if p.kind == "time" and not p.skipped)
abs_count = sum(1 for p in result.preview if p.kind == "absence" and not p.skipped)
return ImportPreviewResponse(
preview=result.preview,
time_count=time_count,
absence_count=abs_count,
skip_count=result.skipped,
errors=result.errors,
)
@router.post("/kimai/run", response_model=ImportRunResponse)
async def kimai_run(
user_id: Annotated[str, Form()],
file: Annotated[UploadFile, File()],
current_user: User = require_role(*_allowed_roles),
db: AsyncSession = Depends(get_db),
):
"""Führt den Kimai-Import durch (schreibt in DB)."""
try:
target_id = uuid.UUID(user_id)
except ValueError:
raise HTTPException(status_code=400, detail="Ungültige user_id")
content = await file.read()
result: ImportResult = await run_kimai_import(content, target_id, current_user.id, db)
return ImportRunResponse(
time_imported=result.time_imported,
absence_imported=result.absence_imported,
skipped=result.skipped,
errors=result.errors,
)