File size: 5,220 Bytes
fcf8749 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | """
Phase 2 Driver-facing API endpoints.
Handles driver operations: assignments, stats, deliveries, feedback, swaps, issues.
"""
from datetime import date as date_type
from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy.ext.asyncio import AsyncSession
from uuid import UUID
from app.database import get_db
from app.schemas.driver_api import (
TodayAssignmentResponse,
DriverStatsWindowResponse,
DeliveryLogRequest,
DeliveryLogResponse,
RouteSwapRequestCreate,
RouteSwapRequestResponse,
StopIssueRequest,
StopIssueResponse,
)
from app.services.driver_service import (
get_today_assignment,
get_driver_stats,
log_delivery,
create_route_swap_request,
create_stop_issue,
)
router = APIRouter(tags=["Driver"])
@router.get(
"/assignments/today",
response_model=TodayAssignmentResponse,
summary="Get today's assignment",
description="Fetch the driver's assignment for the given date with full stop details.",
)
async def get_assignment_today(
driver_id: UUID = Query(..., description="Driver UUID"),
target_date: date_type = Query(default=None, description="Date (defaults to today)"),
db: AsyncSession = Depends(get_db),
) -> TodayAssignmentResponse:
"""Get driver's assignment for today or specified date."""
actual_date = target_date or date_type.today()
result = await get_today_assignment(db, driver_id, actual_date)
if not result:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="No assignment found for driver on given date",
)
return result
@router.get(
"/drivers/{driver_id}/stats",
response_model=DriverStatsWindowResponse,
summary="Get driver stats",
description="Get driver statistics over a time window.",
)
async def get_driver_stats_endpoint(
driver_id: UUID,
window_days: int = Query(default=7, ge=1, le=90, description="Days to look back"),
db: AsyncSession = Depends(get_db),
) -> DriverStatsWindowResponse:
"""Get driver stats over time window."""
result = await get_driver_stats(db, driver_id, window_days)
if not result:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Driver not found",
)
return result
@router.post(
"/deliveries/log",
response_model=DeliveryLogResponse,
status_code=status.HTTP_201_CREATED,
summary="Log delivery",
description="Log a delivery attempt at a stop.",
)
async def log_delivery_endpoint(
request: DeliveryLogRequest,
db: AsyncSession = Depends(get_db),
) -> DeliveryLogResponse:
"""Log a delivery at a stop."""
try:
result = await log_delivery(
db=db,
assignment_id=request.assignment_id,
route_id=request.route_id,
driver_id=request.driver_id,
stop_order=request.stop_order,
status=request.status,
issue_type=request.issue_type,
package_id=request.package_id,
photo_url=request.photo_url,
signature_data=request.signature_data,
notes=request.notes,
)
await db.commit()
return result
except ValueError as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e),
)
@router.post(
"/route_swap_requests",
response_model=RouteSwapRequestResponse,
status_code=status.HTTP_201_CREATED,
summary="Request route swap",
description="Submit a route swap request.",
)
async def create_route_swap_endpoint(
request: RouteSwapRequestCreate,
db: AsyncSession = Depends(get_db),
) -> RouteSwapRequestResponse:
"""Create a route swap request."""
try:
result = await create_route_swap_request(
db=db,
from_driver_id=request.from_driver_id,
assignment_id=request.assignment_id,
reason=request.reason,
to_driver_id=request.to_driver_id,
preferred_date=request.preferred_date,
)
await db.commit()
return result
except ValueError as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e),
)
@router.post(
"/stop_issues",
response_model=StopIssueResponse,
status_code=status.HTTP_201_CREATED,
summary="Report stop issue",
description="Report an issue at a specific stop.",
)
async def create_stop_issue_endpoint(
request: StopIssueRequest,
db: AsyncSession = Depends(get_db),
) -> StopIssueResponse:
"""Create a stop issue report."""
try:
result = await create_stop_issue(
db=db,
assignment_id=request.assignment_id,
route_id=request.route_id,
driver_id=request.driver_id,
stop_order=request.stop_order,
issue_type=request.issue_type,
notes=request.notes,
)
await db.commit()
return result
except ValueError as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e),
)
|