Start integrating the onboarding flow with backend 3

This commit is contained in:
Urtzi Alfaro
2025-09-04 23:19:53 +02:00
parent 9eedc2e5f2
commit 0faaa25e58
26 changed files with 314 additions and 767 deletions

View File

@@ -3,7 +3,7 @@
Supplier API endpoints
"""
from fastapi import APIRouter, Depends, HTTPException, Query, Path
from fastapi import APIRouter, Depends, HTTPException, Query, Path, Request
from typing import List, Optional
from uuid import UUID
import structlog
@@ -18,23 +18,22 @@ from app.schemas.suppliers import (
from shared.auth.decorators import get_current_user_dep
from typing import Dict, Any
router = APIRouter(prefix="/suppliers", tags=["suppliers"])
router = APIRouter(prefix="/tenants/{tenant_id}/suppliers", tags=["suppliers"])
logger = structlog.get_logger()
@router.post("", response_model=SupplierResponse)
@router.post("/", response_model=SupplierResponse)
async def create_supplier(
supplier_data: SupplierCreate,
tenant_id: str = Path(..., description="Tenant ID"),
current_user: Dict[str, Any] = Depends(get_current_user_dep),
db: Session = Depends(get_db)
):
"""Create a new supplier"""
# require_permissions(current_user, ["suppliers:create"])
try:
service = SupplierService(db)
supplier = await service.create_supplier(
tenant_id=current_user.tenant_id,
tenant_id=UUID(tenant_id),
supplier_data=supplier_data,
created_by=current_user.user_id
)
@@ -46,14 +45,15 @@ async def create_supplier(
raise HTTPException(status_code=500, detail="Failed to create supplier")
@router.get("", response_model=List[SupplierSummary])
@router.get("/", response_model=List[SupplierSummary])
async def list_suppliers(
tenant_id: str = Path(..., description="Tenant ID"),
search_term: Optional[str] = Query(None, description="Search term"),
supplier_type: Optional[str] = Query(None, description="Supplier type filter"),
status: Optional[str] = Query(None, description="Status filter"),
limit: int = Query(50, ge=1, le=1000, description="Number of results to return"),
offset: int = Query(0, ge=0, description="Number of results to skip"),
current_user: Dict[str, Any] = Depends(get_current_user_dep),
db: Session = Depends(get_db)
):
"""List suppliers with optional filters"""
@@ -69,7 +69,7 @@ async def list_suppliers(
offset=offset
)
suppliers = await service.search_suppliers(
tenant_id=current_user.tenant_id,
tenant_id=UUID(tenant_id),
search_params=search_params
)
return [SupplierSummary.from_orm(supplier) for supplier in suppliers]
@@ -80,7 +80,7 @@ async def list_suppliers(
@router.get("/statistics", response_model=SupplierStatistics)
async def get_supplier_statistics(
current_user: Dict[str, Any] = Depends(get_current_user_dep),
tenant_id: str = Path(..., description="Tenant ID"),
db: Session = Depends(get_db)
):
"""Get supplier statistics for dashboard"""
@@ -88,7 +88,7 @@ async def get_supplier_statistics(
try:
service = SupplierService(db)
stats = await service.get_supplier_statistics(current_user.tenant_id)
stats = await service.get_supplier_statistics(UUID(tenant_id))
return SupplierStatistics(**stats)
except Exception as e:
logger.error("Error getting supplier statistics", error=str(e))
@@ -97,7 +97,7 @@ async def get_supplier_statistics(
@router.get("/active", response_model=List[SupplierSummary])
async def get_active_suppliers(
current_user: Dict[str, Any] = Depends(get_current_user_dep),
tenant_id: str = Path(..., description="Tenant ID"),
db: Session = Depends(get_db)
):
"""Get all active suppliers"""
@@ -105,7 +105,7 @@ async def get_active_suppliers(
try:
service = SupplierService(db)
suppliers = await service.get_active_suppliers(current_user.tenant_id)
suppliers = await service.get_active_suppliers(UUID(tenant_id))
return [SupplierSummary.from_orm(supplier) for supplier in suppliers]
except Exception as e:
logger.error("Error getting active suppliers", error=str(e))
@@ -114,8 +114,8 @@ async def get_active_suppliers(
@router.get("/top", response_model=List[SupplierSummary])
async def get_top_suppliers(
tenant_id: str = Path(..., description="Tenant ID"),
limit: int = Query(10, ge=1, le=50, description="Number of top suppliers to return"),
current_user: Dict[str, Any] = Depends(get_current_user_dep),
db: Session = Depends(get_db)
):
"""Get top performing suppliers"""
@@ -123,7 +123,7 @@ async def get_top_suppliers(
try:
service = SupplierService(db)
suppliers = await service.get_top_suppliers(current_user.tenant_id, limit)
suppliers = await service.get_top_suppliers(UUID(tenant_id), limit)
return [SupplierSummary.from_orm(supplier) for supplier in suppliers]
except Exception as e:
logger.error("Error getting top suppliers", error=str(e))
@@ -132,8 +132,8 @@ async def get_top_suppliers(
@router.get("/pending-review", response_model=List[SupplierSummary])
async def get_suppliers_needing_review(
tenant_id: str = Path(..., description="Tenant ID"),
days_since_last_order: int = Query(30, ge=1, le=365, description="Days since last order"),
current_user: Dict[str, Any] = Depends(get_current_user_dep),
db: Session = Depends(get_db)
):
"""Get suppliers that may need performance review"""
@@ -142,7 +142,7 @@ async def get_suppliers_needing_review(
try:
service = SupplierService(db)
suppliers = await service.get_suppliers_needing_review(
current_user.tenant_id, days_since_last_order
UUID(tenant_id), days_since_last_order
)
return [SupplierSummary.from_orm(supplier) for supplier in suppliers]
except Exception as e:
@@ -153,7 +153,7 @@ async def get_suppliers_needing_review(
@router.get("/{supplier_id}", response_model=SupplierResponse)
async def get_supplier(
supplier_id: UUID = Path(..., description="Supplier ID"),
current_user: Dict[str, Any] = Depends(get_current_user_dep),
tenant_id: str = Path(..., description="Tenant ID"),
db: Session = Depends(get_db)
):
"""Get supplier by ID"""
@@ -166,10 +166,6 @@ async def get_supplier(
if not supplier:
raise HTTPException(status_code=404, detail="Supplier not found")
# Check tenant access
if supplier.tenant_id != current_user.tenant_id:
raise HTTPException(status_code=403, detail="Access denied")
return SupplierResponse.from_orm(supplier)
except HTTPException:
raise
@@ -191,12 +187,10 @@ async def update_supplier(
try:
service = SupplierService(db)
# Check supplier exists and belongs to tenant
# Check supplier exists
existing_supplier = await service.get_supplier(supplier_id)
if not existing_supplier:
raise HTTPException(status_code=404, detail="Supplier not found")
if existing_supplier.tenant_id != current_user.tenant_id:
raise HTTPException(status_code=403, detail="Access denied")
supplier = await service.update_supplier(
supplier_id=supplier_id,
@@ -220,7 +214,6 @@ async def update_supplier(
@router.delete("/{supplier_id}")
async def delete_supplier(
supplier_id: UUID = Path(..., description="Supplier ID"),
current_user: Dict[str, Any] = Depends(get_current_user_dep),
db: Session = Depends(get_db)
):
"""Delete supplier (soft delete)"""
@@ -229,12 +222,10 @@ async def delete_supplier(
try:
service = SupplierService(db)
# Check supplier exists and belongs to tenant
# Check supplier exists
existing_supplier = await service.get_supplier(supplier_id)
if not existing_supplier:
raise HTTPException(status_code=404, detail="Supplier not found")
if existing_supplier.tenant_id != current_user.tenant_id:
raise HTTPException(status_code=403, detail="Access denied")
success = await service.delete_supplier(supplier_id)
if not success:
@@ -261,12 +252,10 @@ async def approve_supplier(
try:
service = SupplierService(db)
# Check supplier exists and belongs to tenant
# Check supplier exists
existing_supplier = await service.get_supplier(supplier_id)
if not existing_supplier:
raise HTTPException(status_code=404, detail="Supplier not found")
if existing_supplier.tenant_id != current_user.tenant_id:
raise HTTPException(status_code=403, detail="Access denied")
if approval_data.action == "approve":
supplier = await service.approve_supplier(
@@ -299,7 +288,7 @@ async def approve_supplier(
@router.get("/types/{supplier_type}", response_model=List[SupplierSummary])
async def get_suppliers_by_type(
supplier_type: str = Path(..., description="Supplier type"),
current_user: Dict[str, Any] = Depends(get_current_user_dep),
tenant_id: str = Path(..., description="Tenant ID"),
db: Session = Depends(get_db)
):
"""Get suppliers by type"""
@@ -315,7 +304,7 @@ async def get_suppliers_by_type(
raise HTTPException(status_code=400, detail="Invalid supplier type")
service = SupplierService(db)
suppliers = await service.get_suppliers_by_type(current_user.tenant_id, type_enum)
suppliers = await service.get_suppliers_by_type(UUID(tenant_id), type_enum)
return [SupplierSummary.from_orm(supplier) for supplier in suppliers]
except HTTPException:
raise