REFACTOR ALL APIs

This commit is contained in:
Urtzi Alfaro
2025-10-06 15:27:01 +02:00
parent dc8221bd2f
commit 38fb98bc27
166 changed files with 18454 additions and 13605 deletions

View File

@@ -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")