feat(repairs): add repair management foundation

This commit is contained in:
Schubert Ferenc 2026-07-04 11:46:58 +02:00
parent 22e54f212c
commit e9ec207617
37 changed files with 2149 additions and 7 deletions

View file

@ -0,0 +1,142 @@
from fastapi import APIRouter, Depends, Header, HTTPException, Query, status
from sqlalchemy.orm import Session
from starlette.requests import Request
from typing import cast
from app.core.config import settings
from app.core.rbac import require_permission
from app.db.database import get_db
from app.models.repair import Repair
from app.models.user import User
from app.repositories.repair_repository import RepairRepository
from app.schemas.repair import (
RepairCreate,
RepairIntakePayload,
RepairIntakeResponse,
RepairListResponse,
RepairResponse,
RepairStatus,
RepairStatusHistoryResponse,
RepairStatusUpdate,
RepairUpdate,
)
from app.services.repair_service import RepairService
router = APIRouter(tags=["Repairs"])
def get_repair_or_404(db: Session, repair_id: int) -> Repair:
repair = RepairRepository.get_by_id(db, repair_id)
if repair is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Reparatur nicht gefunden")
return repair
@router.get("/repairs", response_model=RepairListResponse)
@router.get("/repairs/", response_model=RepairListResponse, include_in_schema=False)
def get_repairs(
status_filter: str | None = Query(default=None, alias="status"),
q: str | None = None,
customer_id: int | None = None,
source: str | None = None,
priority: str | None = None,
limit: int = Query(default=50, ge=1, le=100),
offset: int = Query(default=0, ge=0),
db: Session = Depends(get_db),
current_user: User = Depends(require_permission("repairs.read")),
):
items, total = RepairRepository.list(
db,
status=status_filter,
q=q,
customer_id=customer_id,
source=source,
priority=priority,
limit=limit,
offset=offset,
)
return RepairListResponse(items=items, total=total, limit=limit, offset=offset)
@router.get("/repairs/{repair_id}", response_model=RepairResponse)
def get_repair(
repair_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(require_permission("repairs.read")),
):
return get_repair_or_404(db, repair_id)
@router.post("/repairs", response_model=RepairResponse, status_code=status.HTTP_201_CREATED)
@router.post("/repairs/", response_model=RepairResponse, status_code=status.HTTP_201_CREATED, include_in_schema=False)
def create_repair(
repair: RepairCreate,
request: Request,
db: Session = Depends(get_db),
current_user: User = Depends(require_permission("repairs.create")),
):
return RepairService.create(db, repair, actor=current_user, request=request)
@router.put("/repairs/{repair_id}", response_model=RepairResponse)
def update_repair(
repair_id: int,
repair: RepairUpdate,
request: Request,
db: Session = Depends(get_db),
current_user: User = Depends(require_permission("repairs.update")),
):
db_repair = get_repair_or_404(db, repair_id)
return RepairService.update(db, db_repair, repair, actor=current_user, request=request)
@router.delete("/repairs/{repair_id}", response_model=RepairResponse)
def delete_repair(
repair_id: int,
request: Request,
db: Session = Depends(get_db),
current_user: User = Depends(require_permission("repairs.delete")),
):
db_repair = get_repair_or_404(db, repair_id)
return RepairService.cancel(db, db_repair, actor=current_user, request=request)
@router.put("/repairs/{repair_id}/status", response_model=RepairResponse)
def update_repair_status(
repair_id: int,
payload: RepairStatusUpdate,
request: Request,
db: Session = Depends(get_db),
current_user: User = Depends(require_permission("repairs.status.update")),
):
db_repair = get_repair_or_404(db, repair_id)
return RepairService.update_status(db, db_repair, payload, actor=current_user, request=request)
@router.get("/repairs/{repair_id}/history", response_model=list[RepairStatusHistoryResponse])
def get_repair_history(
repair_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(require_permission("repairs.read")),
):
get_repair_or_404(db, repair_id)
return RepairRepository.get_history(db, repair_id)
@router.post("/public/repair-intake", response_model=RepairIntakeResponse, status_code=status.HTTP_201_CREATED)
def create_repair_intake(
payload: RepairIntakePayload,
request: Request,
x_olympus_intake_token: str | None = Header(default=None, alias="X-Olympus-Intake-Token"),
db: Session = Depends(get_db),
):
expected_token = settings.olympus_repair_intake_token
if not expected_token or not x_olympus_intake_token or x_olympus_intake_token != expected_token:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Nicht autorisiert")
repair = RepairService.create_from_intake(db, payload, request=request)
return RepairIntakeResponse(
repair_number=repair.repair_number,
status=cast(RepairStatus, repair.status),
message="Reparaturanfrage übernommen",
)