Add POI feature and imporve the overall backend implementation

This commit is contained in:
Urtzi Alfaro
2025-11-12 15:34:10 +01:00
parent e8096cd979
commit 5783c7ed05
173 changed files with 16862 additions and 9078 deletions

View File

@@ -13,6 +13,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
from app.core.database import get_db
from app.core.config import settings
from app.services.purchase_order_service import PurchaseOrderService
from app.services.overdue_po_detector import OverduePODetector
from app.schemas.purchase_order_schemas import (
PurchaseOrderCreate,
PurchaseOrderUpdate,
@@ -25,6 +26,7 @@ from app.schemas.purchase_order_schemas import (
SupplierInvoiceResponse,
)
from shared.routing import RouteBuilder
from shared.auth.decorators import get_current_user_dep
import structlog
logger = structlog.get_logger()
@@ -368,6 +370,7 @@ async def create_delivery(
po_id: str,
delivery_data: DeliveryCreate,
tenant_id: str = Path(..., description="Tenant ID"),
current_user: dict = Depends(get_current_user_dep),
service: PurchaseOrderService = Depends(get_po_service)
):
"""
@@ -391,7 +394,7 @@ async def create_delivery(
delivery = await service.create_delivery(
tenant_id=uuid.UUID(tenant_id),
delivery_data=delivery_data,
created_by=uuid.uuid4() # TODO: Get from auth context
created_by=uuid.UUID(current_user.get("user_id"))
)
return DeliveryResponse.model_validate(delivery)
@@ -411,6 +414,7 @@ async def update_delivery_status(
delivery_id: str,
status: str = Query(..., description="New delivery status"),
tenant_id: str = Path(..., description="Tenant ID"),
current_user: dict = Depends(get_current_user_dep),
service: PurchaseOrderService = Depends(get_po_service)
):
"""
@@ -431,7 +435,7 @@ async def update_delivery_status(
tenant_id=uuid.UUID(tenant_id),
delivery_id=uuid.UUID(delivery_id),
status=status,
updated_by=uuid.uuid4() # TODO: Get from auth context
updated_by=uuid.UUID(current_user.get("user_id"))
)
if not delivery:
@@ -461,6 +465,7 @@ async def create_invoice(
po_id: str,
invoice_data: SupplierInvoiceCreate,
tenant_id: str = Path(..., description="Tenant ID"),
current_user: dict = Depends(get_current_user_dep),
service: PurchaseOrderService = Depends(get_po_service)
):
"""
@@ -482,7 +487,7 @@ async def create_invoice(
invoice = await service.create_invoice(
tenant_id=uuid.UUID(tenant_id),
invoice_data=invoice_data,
created_by=uuid.uuid4() # TODO: Get from auth context
created_by=uuid.UUID(current_user.get("user_id"))
)
return SupplierInvoiceResponse.model_validate(invoice)
@@ -492,3 +497,77 @@ async def create_invoice(
except Exception as e:
logger.error("Error creating invoice", error=str(e), po_id=po_id)
raise HTTPException(status_code=500, detail=str(e))
# ================================================================
# OVERDUE PO DETECTION
# ================================================================
@router.get(
route_builder.build_base_route("purchase-orders/overdue"),
response_model=List[dict]
)
async def get_overdue_purchase_orders(
tenant_id: str = Path(..., description="Tenant ID"),
limit: int = Query(10, ge=1, le=100, description="Max results")
):
"""
Get overdue purchase orders for dashboard display.
Returns POs that are past their estimated delivery date
but not yet marked as delivered.
Args:
tenant_id: Tenant UUID
limit: Maximum number of results (default: 10)
Returns:
List of overdue PO summaries with severity and days overdue
"""
try:
detector = OverduePODetector()
overdue_pos = await detector.get_overdue_pos_for_dashboard(
tenant_id=uuid.UUID(tenant_id),
limit=limit
)
return overdue_pos
except Exception as e:
logger.error("Error getting overdue POs", error=str(e), tenant_id=tenant_id)
raise HTTPException(status_code=500, detail=str(e))
@router.get(
route_builder.build_resource_action_route("purchase-orders", "po_id", "overdue-status"),
response_model=dict
)
async def check_po_overdue_status(
po_id: str,
tenant_id: str = Path(..., description="Tenant ID")
):
"""
Check if a specific PO is overdue.
Args:
tenant_id: Tenant UUID
po_id: Purchase order UUID
Returns:
Overdue status info or null if not overdue
"""
try:
detector = OverduePODetector()
overdue_info = await detector.check_single_po_overdue(
po_id=uuid.UUID(po_id),
tenant_id=uuid.UUID(tenant_id)
)
if overdue_info:
return overdue_info
else:
return {"overdue": False}
except Exception as e:
logger.error("Error checking PO overdue status", error=str(e), po_id=po_id)
raise HTTPException(status_code=500, detail=str(e))