Improve the frontend 3

This commit is contained in:
Urtzi Alfaro
2025-10-30 21:08:07 +01:00
parent 36217a2729
commit 63f5c6d512
184 changed files with 21512 additions and 7442 deletions

View File

@@ -455,3 +455,174 @@ async def resolve_or_create_products_batch(
logger.error("Batch product resolution failed",
error=str(e), tenant_id=tenant_id)
raise HTTPException(status_code=500, detail=f"Batch resolution failed: {str(e)}")
# ================================================================
# NEW: BATCH API ENDPOINTS FOR ORCHESTRATOR
# ================================================================
class BatchIngredientsRequest(BaseModel):
"""Request for batch ingredient fetching"""
ingredient_ids: List[UUID] = Field(..., description="List of ingredient IDs to fetch")
class BatchIngredientsResponse(BaseModel):
"""Response with ingredient data"""
ingredients: List[Dict[str, Any]] = Field(..., description="List of ingredient data")
found_count: int = Field(..., description="Number of ingredients found")
missing_ids: List[str] = Field(default_factory=list, description="IDs not found")
@router.post(
route_builder.build_operations_route("ingredients/batch"),
response_model=BatchIngredientsResponse
)
async def get_ingredients_batch(
request: BatchIngredientsRequest,
tenant_id: UUID = Path(..., description="Tenant ID"),
current_user: Dict[str, Any] = Depends(get_current_user_dep),
db: AsyncSession = Depends(get_db)
):
"""
Fetch multiple ingredients in a single request (for Orchestrator).
This endpoint reduces N API calls to 1, improving performance when
the orchestrator needs ingredient data for production/procurement planning.
"""
try:
if not request.ingredient_ids:
return BatchIngredientsResponse(
ingredients=[],
found_count=0,
missing_ids=[]
)
service = InventoryService()
ingredients = []
found_ids = set()
for ingredient_id in request.ingredient_ids:
try:
ingredient = await service.get_ingredient_by_id(ingredient_id, tenant_id, db)
if ingredient:
ingredients.append({
'id': str(ingredient.id),
'name': ingredient.name,
'type': ingredient.type,
'unit': ingredient.unit,
'current_stock': float(ingredient.current_stock) if ingredient.current_stock else 0,
'reorder_point': float(ingredient.reorder_point) if ingredient.reorder_point else 0,
'cost_per_unit': float(ingredient.cost_per_unit) if ingredient.cost_per_unit else 0,
'category': ingredient.category,
'is_active': ingredient.is_active,
'shelf_life_days': ingredient.shelf_life_days
})
found_ids.add(str(ingredient_id))
except Exception as e:
logger.warning(
"Failed to fetch ingredient in batch",
ingredient_id=str(ingredient_id),
error=str(e)
)
continue
missing_ids = [str(id) for id in request.ingredient_ids if str(id) not in found_ids]
logger.info(
"Batch ingredient fetch complete",
requested=len(request.ingredient_ids),
found=len(ingredients),
missing=len(missing_ids),
tenant_id=str(tenant_id)
)
return BatchIngredientsResponse(
ingredients=ingredients,
found_count=len(ingredients),
missing_ids=missing_ids
)
except Exception as e:
logger.error(
"Batch ingredient fetch failed",
error=str(e),
tenant_id=str(tenant_id)
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Batch ingredient fetch failed: {str(e)}"
)
class BatchStockLevelsRequest(BaseModel):
"""Request for batch stock level fetching"""
ingredient_ids: List[UUID] = Field(..., description="List of ingredient IDs")
class BatchStockLevelsResponse(BaseModel):
"""Response with stock level data"""
stock_levels: Dict[str, float] = Field(..., description="Ingredient ID to stock level mapping")
found_count: int = Field(..., description="Number of stock levels found")
@router.post(
route_builder.build_operations_route("stock-levels/batch"),
response_model=BatchStockLevelsResponse
)
async def get_stock_levels_batch(
request: BatchStockLevelsRequest,
tenant_id: UUID = Path(..., description="Tenant ID"),
current_user: Dict[str, Any] = Depends(get_current_user_dep),
db: AsyncSession = Depends(get_db)
):
"""
Fetch stock levels for multiple ingredients in a single request.
Optimized endpoint for Orchestrator to quickly check inventory levels
without making individual API calls per ingredient.
"""
try:
if not request.ingredient_ids:
return BatchStockLevelsResponse(
stock_levels={},
found_count=0
)
service = InventoryService()
stock_levels = {}
for ingredient_id in request.ingredient_ids:
try:
ingredient = await service.get_ingredient_by_id(ingredient_id, tenant_id, db)
if ingredient:
stock_levels[str(ingredient_id)] = float(ingredient.current_stock) if ingredient.current_stock else 0.0
except Exception as e:
logger.warning(
"Failed to fetch stock level in batch",
ingredient_id=str(ingredient_id),
error=str(e)
)
continue
logger.info(
"Batch stock level fetch complete",
requested=len(request.ingredient_ids),
found=len(stock_levels),
tenant_id=str(tenant_id)
)
return BatchStockLevelsResponse(
stock_levels=stock_levels,
found_count=len(stock_levels)
)
except Exception as e:
logger.error(
"Batch stock level fetch failed",
error=str(e),
tenant_id=str(tenant_id)
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Batch stock level fetch failed: {str(e)}"
)