REFACTOR ALL APIs
This commit is contained in:
253
services/production/app/api/production_batches.py
Normal file
253
services/production/app/api/production_batches.py
Normal file
@@ -0,0 +1,253 @@
|
||||
# services/production/app/api/production_batches.py
|
||||
"""
|
||||
Production Batches API - ATOMIC CRUD operations on ProductionBatch model
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Path, Query
|
||||
from typing import Optional
|
||||
from datetime import date
|
||||
from uuid import UUID
|
||||
import structlog
|
||||
|
||||
from shared.auth.decorators import get_current_user_dep
|
||||
from shared.routing import RouteBuilder
|
||||
from app.core.database import get_db
|
||||
from app.services.production_service import ProductionService
|
||||
from app.schemas.production import (
|
||||
ProductionBatchCreate,
|
||||
ProductionBatchUpdate,
|
||||
ProductionBatchStatusUpdate,
|
||||
ProductionBatchResponse,
|
||||
ProductionBatchListResponse,
|
||||
ProductionStatusEnum
|
||||
)
|
||||
from app.core.config import settings
|
||||
|
||||
logger = structlog.get_logger()
|
||||
route_builder = RouteBuilder('production')
|
||||
router = APIRouter(tags=["production-batches"])
|
||||
|
||||
|
||||
def get_production_service() -> ProductionService:
|
||||
"""Dependency injection for production service"""
|
||||
from app.core.database import database_manager
|
||||
return ProductionService(database_manager, settings)
|
||||
|
||||
|
||||
@router.get(
|
||||
route_builder.build_base_route("batches"),
|
||||
response_model=ProductionBatchListResponse
|
||||
)
|
||||
async def list_production_batches(
|
||||
tenant_id: UUID = Path(...),
|
||||
status: Optional[ProductionStatusEnum] = Query(None, description="Filter by status"),
|
||||
product_id: Optional[UUID] = Query(None, description="Filter by product"),
|
||||
order_id: Optional[UUID] = Query(None, description="Filter by order"),
|
||||
start_date: Optional[date] = Query(None, description="Filter from date"),
|
||||
end_date: Optional[date] = Query(None, description="Filter to date"),
|
||||
page: int = Query(1, ge=1, description="Page number"),
|
||||
page_size: int = Query(50, ge=1, le=100, description="Page size"),
|
||||
current_user: dict = Depends(get_current_user_dep),
|
||||
production_service: ProductionService = Depends(get_production_service)
|
||||
):
|
||||
"""List batches with filters: date, status, product, order_id"""
|
||||
try:
|
||||
filters = {
|
||||
"status": status,
|
||||
"product_id": str(product_id) if product_id else None,
|
||||
"order_id": str(order_id) if order_id else None,
|
||||
"start_date": start_date,
|
||||
"end_date": end_date
|
||||
}
|
||||
|
||||
batch_list = await production_service.get_production_batches_list(tenant_id, filters, page, page_size)
|
||||
|
||||
logger.info("Retrieved production batches list",
|
||||
tenant_id=str(tenant_id), filters=filters)
|
||||
|
||||
return batch_list
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Error listing production batches",
|
||||
error=str(e), tenant_id=str(tenant_id))
|
||||
raise HTTPException(status_code=500, detail="Failed to list production batches")
|
||||
|
||||
|
||||
@router.post(
|
||||
route_builder.build_base_route("batches"),
|
||||
response_model=ProductionBatchResponse
|
||||
)
|
||||
async def create_production_batch(
|
||||
batch_data: ProductionBatchCreate,
|
||||
tenant_id: UUID = Path(...),
|
||||
current_user: dict = Depends(get_current_user_dep),
|
||||
production_service: ProductionService = Depends(get_production_service)
|
||||
):
|
||||
"""Create a new production batch"""
|
||||
try:
|
||||
batch = await production_service.create_production_batch(tenant_id, batch_data)
|
||||
|
||||
logger.info("Created production batch",
|
||||
batch_id=str(batch.id), tenant_id=str(tenant_id))
|
||||
|
||||
return ProductionBatchResponse.model_validate(batch)
|
||||
|
||||
except ValueError as e:
|
||||
logger.warning("Invalid batch data", error=str(e), tenant_id=str(tenant_id))
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.error("Error creating production batch",
|
||||
error=str(e), tenant_id=str(tenant_id))
|
||||
raise HTTPException(status_code=500, detail="Failed to create production batch")
|
||||
|
||||
|
||||
@router.get(
|
||||
route_builder.build_base_route("batches/active"),
|
||||
response_model=ProductionBatchListResponse
|
||||
)
|
||||
async def get_active_batches(
|
||||
tenant_id: UUID = Path(...),
|
||||
current_user: dict = Depends(get_current_user_dep),
|
||||
db=Depends(get_db)
|
||||
):
|
||||
"""Get currently active production batches"""
|
||||
try:
|
||||
from app.repositories.production_batch_repository import ProductionBatchRepository
|
||||
batch_repo = ProductionBatchRepository(db)
|
||||
|
||||
batches = await batch_repo.get_active_batches(str(tenant_id))
|
||||
batch_responses = [ProductionBatchResponse.model_validate(batch) for batch in batches]
|
||||
|
||||
logger.info("Retrieved active production batches",
|
||||
count=len(batches), tenant_id=str(tenant_id))
|
||||
|
||||
return ProductionBatchListResponse(
|
||||
batches=batch_responses,
|
||||
total_count=len(batches),
|
||||
page=1,
|
||||
page_size=len(batches)
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Error getting active batches",
|
||||
error=str(e), tenant_id=str(tenant_id))
|
||||
raise HTTPException(status_code=500, detail="Failed to get active batches")
|
||||
|
||||
|
||||
@router.get(
|
||||
route_builder.build_resource_detail_route("batches", "batch_id"),
|
||||
response_model=ProductionBatchResponse
|
||||
)
|
||||
async def get_batch_details(
|
||||
tenant_id: UUID = Path(...),
|
||||
batch_id: UUID = Path(...),
|
||||
current_user: dict = Depends(get_current_user_dep),
|
||||
db=Depends(get_db)
|
||||
):
|
||||
"""Get detailed information about a production batch"""
|
||||
try:
|
||||
from app.repositories.production_batch_repository import ProductionBatchRepository
|
||||
batch_repo = ProductionBatchRepository(db)
|
||||
|
||||
batch = await batch_repo.get(batch_id)
|
||||
if not batch or str(batch.tenant_id) != str(tenant_id):
|
||||
raise HTTPException(status_code=404, detail="Production batch not found")
|
||||
|
||||
logger.info("Retrieved production batch details",
|
||||
batch_id=str(batch_id), tenant_id=str(tenant_id))
|
||||
|
||||
return ProductionBatchResponse.model_validate(batch)
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error("Error getting batch details",
|
||||
error=str(e), batch_id=str(batch_id), tenant_id=str(tenant_id))
|
||||
raise HTTPException(status_code=500, detail="Failed to get batch details")
|
||||
|
||||
|
||||
@router.put(
|
||||
route_builder.build_nested_resource_route("batches", "batch_id", "status"),
|
||||
response_model=ProductionBatchResponse
|
||||
)
|
||||
async def update_batch_status(
|
||||
status_update: ProductionBatchStatusUpdate,
|
||||
tenant_id: UUID = Path(...),
|
||||
batch_id: UUID = Path(...),
|
||||
current_user: dict = Depends(get_current_user_dep),
|
||||
production_service: ProductionService = Depends(get_production_service)
|
||||
):
|
||||
"""Update production batch status"""
|
||||
try:
|
||||
batch = await production_service.update_batch_status(tenant_id, batch_id, status_update)
|
||||
|
||||
logger.info("Updated production batch status",
|
||||
batch_id=str(batch_id),
|
||||
new_status=status_update.status.value,
|
||||
tenant_id=str(tenant_id))
|
||||
|
||||
return ProductionBatchResponse.model_validate(batch)
|
||||
|
||||
except ValueError as e:
|
||||
logger.warning("Invalid status update", error=str(e), batch_id=str(batch_id))
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.error("Error updating batch status",
|
||||
error=str(e), batch_id=str(batch_id), tenant_id=str(tenant_id))
|
||||
raise HTTPException(status_code=500, detail="Failed to update batch status")
|
||||
|
||||
|
||||
@router.put(
|
||||
route_builder.build_resource_detail_route("batches", "batch_id"),
|
||||
response_model=ProductionBatchResponse
|
||||
)
|
||||
async def update_production_batch(
|
||||
batch_update: ProductionBatchUpdate,
|
||||
tenant_id: UUID = Path(...),
|
||||
batch_id: UUID = Path(...),
|
||||
current_user: dict = Depends(get_current_user_dep),
|
||||
production_service: ProductionService = Depends(get_production_service)
|
||||
):
|
||||
"""Update batch (e.g., start time, notes, status)"""
|
||||
try:
|
||||
batch = await production_service.update_production_batch(tenant_id, batch_id, batch_update)
|
||||
|
||||
logger.info("Updated production batch",
|
||||
batch_id=str(batch_id), tenant_id=str(tenant_id))
|
||||
|
||||
return ProductionBatchResponse.model_validate(batch)
|
||||
|
||||
except ValueError as e:
|
||||
logger.warning("Invalid batch update", error=str(e), batch_id=str(batch_id))
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.error("Error updating production batch",
|
||||
error=str(e), batch_id=str(batch_id), tenant_id=str(tenant_id))
|
||||
raise HTTPException(status_code=500, detail="Failed to update production batch")
|
||||
|
||||
|
||||
@router.delete(
|
||||
route_builder.build_resource_detail_route("batches", "batch_id")
|
||||
)
|
||||
async def delete_production_batch(
|
||||
tenant_id: UUID = Path(...),
|
||||
batch_id: UUID = Path(...),
|
||||
current_user: dict = Depends(get_current_user_dep),
|
||||
production_service: ProductionService = Depends(get_production_service)
|
||||
):
|
||||
"""Cancel/delete draft batch (soft delete preferred)"""
|
||||
try:
|
||||
await production_service.delete_production_batch(tenant_id, batch_id)
|
||||
|
||||
logger.info("Deleted production batch",
|
||||
batch_id=str(batch_id), tenant_id=str(tenant_id))
|
||||
|
||||
return {"message": "Production batch deleted successfully"}
|
||||
|
||||
except ValueError as e:
|
||||
logger.warning("Cannot delete batch", error=str(e), batch_id=str(batch_id))
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.error("Error deleting production batch",
|
||||
error=str(e), batch_id=str(batch_id), tenant_id=str(tenant_id))
|
||||
raise HTTPException(status_code=500, detail="Failed to delete production batch")
|
||||
Reference in New Issue
Block a user