Add frontend procurement implementation

This commit is contained in:
Urtzi Alfaro
2025-09-09 12:02:41 +02:00
parent bc3d0ff90c
commit a290663ec5
10 changed files with 1051 additions and 371 deletions

View File

@@ -27,8 +27,8 @@ from shared.clients.forecast_client import ForecastServiceClient
from shared.config.base import BaseServiceSettings
from shared.monitoring.decorators import monitor_performance
# Create router
router = APIRouter(prefix="/procurement-plans", tags=["Procurement Planning"])
# Create router - tenant-scoped
router = APIRouter(prefix="/tenants/{tenant_id}", tags=["Procurement Planning"])
# Create service settings
service_settings = BaseServiceSettings()
@@ -82,9 +82,10 @@ async def get_procurement_service(db: AsyncSession = Depends(get_db)) -> Procure
# PROCUREMENT PLAN ENDPOINTS
# ================================================================
@router.get("/current", response_model=Optional[ProcurementPlanResponse])
@router.get("/procurement/plans/current", response_model=Optional[ProcurementPlanResponse])
@monitor_performance("get_current_procurement_plan")
async def get_current_procurement_plan(
tenant_id: uuid.UUID,
tenant_access: TenantAccess = Depends(get_current_tenant),
procurement_service: ProcurementService = Depends(get_procurement_service)
):
@@ -103,9 +104,10 @@ async def get_current_procurement_plan(
)
@router.get("/{plan_date}", response_model=Optional[ProcurementPlanResponse])
@router.get("/procurement/plans/date/{plan_date}", response_model=Optional[ProcurementPlanResponse])
@monitor_performance("get_procurement_plan_by_date")
async def get_procurement_plan_by_date(
tenant_id: uuid.UUID,
plan_date: date,
tenant_access: TenantAccess = Depends(get_current_tenant),
procurement_service: ProcurementService = Depends(get_procurement_service)
@@ -125,9 +127,10 @@ async def get_procurement_plan_by_date(
)
@router.get("/", response_model=PaginatedProcurementPlans)
@router.get("/procurement/plans", response_model=PaginatedProcurementPlans)
@monitor_performance("list_procurement_plans")
async def list_procurement_plans(
tenant_id: uuid.UUID,
status: Optional[str] = Query(None, description="Filter by plan status"),
start_date: Optional[date] = Query(None, description="Start date filter (YYYY-MM-DD)"),
end_date: Optional[date] = Query(None, description="End date filter (YYYY-MM-DD)"),
@@ -175,9 +178,10 @@ async def list_procurement_plans(
)
@router.post("/generate", response_model=GeneratePlanResponse)
@router.post("/procurement/plans/generate", response_model=GeneratePlanResponse)
@monitor_performance("generate_procurement_plan")
async def generate_procurement_plan(
tenant_id: uuid.UUID,
request: GeneratePlanRequest,
tenant_access: TenantAccess = Depends(get_current_tenant),
procurement_service: ProcurementService = Depends(get_procurement_service)
@@ -216,9 +220,10 @@ async def generate_procurement_plan(
)
@router.put("/{plan_id}/status")
@router.put("/procurement/plans/{plan_id}/status")
@monitor_performance("update_procurement_plan_status")
async def update_procurement_plan_status(
tenant_id: uuid.UUID,
plan_id: uuid.UUID,
status: str = Query(..., description="New status", pattern="^(draft|pending_approval|approved|in_execution|completed|cancelled)$"),
tenant_access: TenantAccess = Depends(get_current_tenant),
@@ -254,9 +259,10 @@ async def update_procurement_plan_status(
)
@router.get("/id/{plan_id}", response_model=Optional[ProcurementPlanResponse])
@router.get("/procurement/plans/id/{plan_id}", response_model=Optional[ProcurementPlanResponse])
@monitor_performance("get_procurement_plan_by_id")
async def get_procurement_plan_by_id(
tenant_id: uuid.UUID,
plan_id: uuid.UUID,
tenant_access: TenantAccess = Depends(get_current_tenant),
procurement_service: ProcurementService = Depends(get_procurement_service)
@@ -290,9 +296,10 @@ async def get_procurement_plan_by_id(
# DASHBOARD ENDPOINTS
# ================================================================
@router.get("/dashboard/data", response_model=Optional[DashboardData])
@router.get("/procurement/dashboard", response_model=Optional[DashboardData])
@monitor_performance("get_procurement_dashboard")
async def get_procurement_dashboard(
tenant_id: uuid.UUID,
tenant_access: TenantAccess = Depends(get_current_tenant),
procurement_service: ProcurementService = Depends(get_procurement_service)
):
@@ -321,9 +328,10 @@ async def get_procurement_dashboard(
# REQUIREMENT MANAGEMENT ENDPOINTS
# ================================================================
@router.get("/{plan_id}/requirements")
@router.get("/procurement/plans/{plan_id}/requirements")
@monitor_performance("get_plan_requirements")
async def get_plan_requirements(
tenant_id: uuid.UUID,
plan_id: uuid.UUID,
status: Optional[str] = Query(None, description="Filter by requirement status"),
priority: Optional[str] = Query(None, description="Filter by priority level"),
@@ -364,9 +372,10 @@ async def get_plan_requirements(
)
@router.get("/requirements/critical")
@router.get("/procurement/requirements/critical")
@monitor_performance("get_critical_requirements")
async def get_critical_requirements(
tenant_id: uuid.UUID,
tenant_access: TenantAccess = Depends(get_current_tenant),
procurement_service: ProcurementService = Depends(get_procurement_service)
):
@@ -391,9 +400,10 @@ async def get_critical_requirements(
# UTILITY ENDPOINTS
# ================================================================
@router.post("/scheduler/trigger")
@router.post("/procurement/scheduler/trigger")
@monitor_performance("trigger_daily_scheduler")
async def trigger_daily_scheduler(
tenant_id: uuid.UUID,
tenant_access: TenantAccess = Depends(get_current_tenant),
procurement_service: ProcurementService = Depends(get_procurement_service)
):
@@ -419,7 +429,7 @@ async def trigger_daily_scheduler(
)
@router.get("/health")
@router.get("/procurement/health")
async def procurement_health_check():
"""
Health check endpoint for procurement service

View File

@@ -21,7 +21,8 @@ class ProcurementPlanRepository(BaseRepository):
"""Repository for procurement plan operations"""
def __init__(self, db: AsyncSession):
super().__init__(db, ProcurementPlan)
super().__init__(ProcurementPlan)
self.db = db
async def create_plan(self, plan_data: Dict[str, Any]) -> ProcurementPlan:
"""Create a new procurement plan"""
@@ -134,7 +135,8 @@ class ProcurementRequirementRepository(BaseRepository):
"""Repository for procurement requirement operations"""
def __init__(self, db: AsyncSession):
super().__init__(db, ProcurementRequirement)
super().__init__(ProcurementRequirement)
self.db = db
async def create_requirement(self, requirement_data: Dict[str, Any]) -> ProcurementRequirement:
"""Create a new procurement requirement"""

View File

@@ -36,7 +36,7 @@ class CacheService:
self.redis_url,
decode_responses=True,
socket_keepalive=True,
socket_keepalive_options={"TCP_KEEPIDLE": 1, "TCP_KEEPINTVL": 3, "TCP_KEEPCNT": 5},
socket_keepalive_options={1: 1, 3: 3, 5: 5}, # Use integer keys
retry_on_timeout=True,
max_connections=50
)