REFACTOR ALL APIs
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
# services/suppliers/app/api/deliveries.py
|
||||
"""
|
||||
Delivery API endpoints
|
||||
Delivery CRUD API endpoints (ATOMIC)
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, Path
|
||||
from typing import List, Optional
|
||||
from typing import List, Optional, Dict, Any
|
||||
from uuid import UUID
|
||||
import structlog
|
||||
|
||||
@@ -13,18 +13,23 @@ from app.core.database import get_db
|
||||
from app.services.delivery_service import DeliveryService
|
||||
from app.schemas.suppliers import (
|
||||
DeliveryCreate, DeliveryUpdate, DeliveryResponse, DeliverySummary,
|
||||
DeliverySearchParams, DeliveryStatusUpdate, DeliveryReceiptConfirmation,
|
||||
DeliveryPerformanceStats, DeliverySummaryStats
|
||||
DeliverySearchParams
|
||||
)
|
||||
from app.models.suppliers import DeliveryStatus
|
||||
from shared.auth.decorators import get_current_user_dep
|
||||
from typing import Dict, Any
|
||||
from shared.routing import RouteBuilder
|
||||
from shared.auth.access_control import require_user_role
|
||||
|
||||
router = APIRouter(prefix="/deliveries", tags=["deliveries"])
|
||||
# Create route builder for consistent URL structure
|
||||
route_builder = RouteBuilder('suppliers')
|
||||
|
||||
|
||||
router = APIRouter(tags=["deliveries"])
|
||||
logger = structlog.get_logger()
|
||||
|
||||
|
||||
@router.post("/", response_model=DeliveryResponse)
|
||||
@router.post(route_builder.build_base_route("deliveries"), response_model=DeliveryResponse)
|
||||
@require_user_role(['admin', 'owner', 'member'])
|
||||
async def create_delivery(
|
||||
delivery_data: DeliveryCreate,
|
||||
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
||||
@@ -48,7 +53,7 @@ async def create_delivery(
|
||||
raise HTTPException(status_code=500, detail="Failed to create delivery")
|
||||
|
||||
|
||||
@router.get("/", response_model=List[DeliverySummary])
|
||||
@router.get(route_builder.build_base_route("deliveries"), response_model=List[DeliverySummary])
|
||||
async def list_deliveries(
|
||||
supplier_id: Optional[UUID] = Query(None, description="Filter by supplier ID"),
|
||||
status: Optional[str] = Query(None, description="Filter by status"),
|
||||
@@ -113,123 +118,7 @@ async def list_deliveries(
|
||||
raise HTTPException(status_code=500, detail="Failed to retrieve deliveries")
|
||||
|
||||
|
||||
@router.get("/today", response_model=List[DeliverySummary])
|
||||
async def get_todays_deliveries(
|
||||
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get deliveries scheduled for today"""
|
||||
# require_permissions(current_user, ["deliveries:read"])
|
||||
|
||||
try:
|
||||
service = DeliveryService(db)
|
||||
deliveries = await service.get_todays_deliveries(current_user.tenant_id)
|
||||
return [DeliverySummary.from_orm(delivery) for delivery in deliveries]
|
||||
except Exception as e:
|
||||
logger.error("Error getting today's deliveries", error=str(e))
|
||||
raise HTTPException(status_code=500, detail="Failed to retrieve today's deliveries")
|
||||
|
||||
|
||||
@router.get("/overdue", response_model=List[DeliverySummary])
|
||||
async def get_overdue_deliveries(
|
||||
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get overdue deliveries"""
|
||||
# require_permissions(current_user, ["deliveries:read"])
|
||||
|
||||
try:
|
||||
service = DeliveryService(db)
|
||||
deliveries = await service.get_overdue_deliveries(current_user.tenant_id)
|
||||
return [DeliverySummary.from_orm(delivery) for delivery in deliveries]
|
||||
except Exception as e:
|
||||
logger.error("Error getting overdue deliveries", error=str(e))
|
||||
raise HTTPException(status_code=500, detail="Failed to retrieve overdue deliveries")
|
||||
|
||||
|
||||
@router.get("/scheduled", response_model=List[DeliverySummary])
|
||||
async def get_scheduled_deliveries(
|
||||
date_from: Optional[str] = Query(None, description="From date (YYYY-MM-DD)"),
|
||||
date_to: Optional[str] = Query(None, description="To date (YYYY-MM-DD)"),
|
||||
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get scheduled deliveries for a date range"""
|
||||
# require_permissions(current_user, ["deliveries:read"])
|
||||
|
||||
try:
|
||||
from datetime import datetime
|
||||
|
||||
date_from_parsed = None
|
||||
date_to_parsed = None
|
||||
|
||||
if date_from:
|
||||
try:
|
||||
date_from_parsed = datetime.fromisoformat(date_from)
|
||||
except ValueError:
|
||||
raise HTTPException(status_code=400, detail="Invalid date_from format")
|
||||
|
||||
if date_to:
|
||||
try:
|
||||
date_to_parsed = datetime.fromisoformat(date_to)
|
||||
except ValueError:
|
||||
raise HTTPException(status_code=400, detail="Invalid date_to format")
|
||||
|
||||
service = DeliveryService(db)
|
||||
deliveries = await service.get_scheduled_deliveries(
|
||||
tenant_id=current_user.tenant_id,
|
||||
date_from=date_from_parsed,
|
||||
date_to=date_to_parsed
|
||||
)
|
||||
return [DeliverySummary.from_orm(delivery) for delivery in deliveries]
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error("Error getting scheduled deliveries", error=str(e))
|
||||
raise HTTPException(status_code=500, detail="Failed to retrieve scheduled deliveries")
|
||||
|
||||
|
||||
@router.get("/performance-stats", response_model=DeliveryPerformanceStats)
|
||||
async def get_delivery_performance_stats(
|
||||
days_back: int = Query(30, ge=1, le=365, description="Number of days to analyze"),
|
||||
supplier_id: Optional[UUID] = Query(None, description="Filter by supplier ID"),
|
||||
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get delivery performance statistics"""
|
||||
# require_permissions(current_user, ["deliveries:read"])
|
||||
|
||||
try:
|
||||
service = DeliveryService(db)
|
||||
stats = await service.get_delivery_performance_stats(
|
||||
tenant_id=current_user.tenant_id,
|
||||
days_back=days_back,
|
||||
supplier_id=supplier_id
|
||||
)
|
||||
return DeliveryPerformanceStats(**stats)
|
||||
except Exception as e:
|
||||
logger.error("Error getting delivery performance stats", error=str(e))
|
||||
raise HTTPException(status_code=500, detail="Failed to retrieve delivery performance statistics")
|
||||
|
||||
|
||||
@router.get("/summary-stats", response_model=DeliverySummaryStats)
|
||||
async def get_delivery_summary_stats(
|
||||
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get delivery summary statistics for dashboard"""
|
||||
# require_permissions(current_user, ["deliveries:read"])
|
||||
|
||||
try:
|
||||
service = DeliveryService(db)
|
||||
stats = await service.get_upcoming_deliveries_summary(current_user.tenant_id)
|
||||
return DeliverySummaryStats(**stats)
|
||||
except Exception as e:
|
||||
logger.error("Error getting delivery summary stats", error=str(e))
|
||||
raise HTTPException(status_code=500, detail="Failed to retrieve delivery summary statistics")
|
||||
|
||||
|
||||
@router.get("/{delivery_id}", response_model=DeliveryResponse)
|
||||
@router.get(route_builder.build_resource_detail_route("deliveries", "delivery_id"), response_model=DeliveryResponse)
|
||||
async def get_delivery(
|
||||
delivery_id: UUID = Path(..., description="Delivery ID"),
|
||||
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
||||
@@ -257,7 +146,8 @@ async def get_delivery(
|
||||
raise HTTPException(status_code=500, detail="Failed to retrieve delivery")
|
||||
|
||||
|
||||
@router.put("/{delivery_id}", response_model=DeliveryResponse)
|
||||
@router.put(route_builder.build_resource_detail_route("deliveries", "delivery_id"), response_model=DeliveryResponse)
|
||||
@require_user_role(['admin', 'owner', 'member'])
|
||||
async def update_delivery(
|
||||
delivery_data: DeliveryUpdate,
|
||||
delivery_id: UUID = Path(..., description="Delivery ID"),
|
||||
@@ -296,109 +186,3 @@ async def update_delivery(
|
||||
raise HTTPException(status_code=500, detail="Failed to update delivery")
|
||||
|
||||
|
||||
@router.patch("/{delivery_id}/status", response_model=DeliveryResponse)
|
||||
async def update_delivery_status(
|
||||
status_data: DeliveryStatusUpdate,
|
||||
delivery_id: UUID = Path(..., description="Delivery ID"),
|
||||
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Update delivery status"""
|
||||
# require_permissions(current_user, ["deliveries:update"])
|
||||
|
||||
try:
|
||||
service = DeliveryService(db)
|
||||
|
||||
# Check delivery exists and belongs to tenant
|
||||
existing_delivery = await service.get_delivery(delivery_id)
|
||||
if not existing_delivery:
|
||||
raise HTTPException(status_code=404, detail="Delivery not found")
|
||||
if existing_delivery.tenant_id != current_user.tenant_id:
|
||||
raise HTTPException(status_code=403, detail="Access denied")
|
||||
|
||||
delivery = await service.update_delivery_status(
|
||||
delivery_id=delivery_id,
|
||||
status=status_data.status,
|
||||
updated_by=current_user.user_id,
|
||||
notes=status_data.notes,
|
||||
update_timestamps=status_data.update_timestamps
|
||||
)
|
||||
|
||||
if not delivery:
|
||||
raise HTTPException(status_code=404, detail="Delivery not found")
|
||||
|
||||
return DeliveryResponse.from_orm(delivery)
|
||||
except HTTPException:
|
||||
raise
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.error("Error updating delivery status", delivery_id=str(delivery_id), error=str(e))
|
||||
raise HTTPException(status_code=500, detail="Failed to update delivery status")
|
||||
|
||||
|
||||
@router.post("/{delivery_id}/receive", response_model=DeliveryResponse)
|
||||
async def receive_delivery(
|
||||
receipt_data: DeliveryReceiptConfirmation,
|
||||
delivery_id: UUID = Path(..., description="Delivery ID"),
|
||||
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Mark delivery as received with inspection details"""
|
||||
# require_permissions(current_user, ["deliveries:receive"])
|
||||
|
||||
try:
|
||||
service = DeliveryService(db)
|
||||
|
||||
# Check delivery exists and belongs to tenant
|
||||
existing_delivery = await service.get_delivery(delivery_id)
|
||||
if not existing_delivery:
|
||||
raise HTTPException(status_code=404, detail="Delivery not found")
|
||||
if existing_delivery.tenant_id != current_user.tenant_id:
|
||||
raise HTTPException(status_code=403, detail="Access denied")
|
||||
|
||||
delivery = await service.mark_as_received(
|
||||
delivery_id=delivery_id,
|
||||
received_by=current_user.user_id,
|
||||
inspection_passed=receipt_data.inspection_passed,
|
||||
inspection_notes=receipt_data.inspection_notes,
|
||||
quality_issues=receipt_data.quality_issues,
|
||||
notes=receipt_data.notes
|
||||
)
|
||||
|
||||
if not delivery:
|
||||
raise HTTPException(status_code=404, detail="Delivery not found")
|
||||
|
||||
return DeliveryResponse.from_orm(delivery)
|
||||
except HTTPException:
|
||||
raise
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.error("Error receiving delivery", delivery_id=str(delivery_id), error=str(e))
|
||||
raise HTTPException(status_code=500, detail="Failed to receive delivery")
|
||||
|
||||
|
||||
@router.get("/purchase-order/{po_id}", response_model=List[DeliverySummary])
|
||||
async def get_deliveries_by_purchase_order(
|
||||
po_id: UUID = Path(..., description="Purchase order ID"),
|
||||
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get all deliveries for a purchase order"""
|
||||
# require_permissions(current_user, ["deliveries:read"])
|
||||
|
||||
try:
|
||||
service = DeliveryService(db)
|
||||
deliveries = await service.get_deliveries_by_purchase_order(po_id)
|
||||
|
||||
# Check tenant access for first delivery (all should belong to same tenant)
|
||||
if deliveries and deliveries[0].tenant_id != current_user.tenant_id:
|
||||
raise HTTPException(status_code=403, detail="Access denied")
|
||||
|
||||
return [DeliverySummary.from_orm(delivery) for delivery in deliveries]
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error("Error getting deliveries by purchase order", po_id=str(po_id), error=str(e))
|
||||
raise HTTPException(status_code=500, detail="Failed to retrieve deliveries for purchase order")
|
||||
Reference in New Issue
Block a user