Create the frontend receipes page to use real API
This commit is contained in:
@@ -1,117 +0,0 @@
|
||||
# services/recipes/app/api/ingredients.py
|
||||
"""
|
||||
API endpoints for ingredient-related operations (bridge to inventory service)
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Header, Query
|
||||
from typing import List, Optional
|
||||
from uuid import UUID
|
||||
import logging
|
||||
|
||||
from ..services.inventory_client import InventoryClient
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
def get_tenant_id(x_tenant_id: str = Header(...)) -> UUID:
|
||||
"""Extract tenant ID from header"""
|
||||
try:
|
||||
return UUID(x_tenant_id)
|
||||
except ValueError:
|
||||
raise HTTPException(status_code=400, detail="Invalid tenant ID format")
|
||||
|
||||
|
||||
@router.get("/search")
|
||||
async def search_ingredients(
|
||||
tenant_id: UUID = Depends(get_tenant_id),
|
||||
search_term: Optional[str] = Query(None),
|
||||
product_type: Optional[str] = Query(None),
|
||||
category: Optional[str] = Query(None),
|
||||
limit: int = Query(100, ge=1, le=1000),
|
||||
offset: int = Query(0, ge=0)
|
||||
):
|
||||
"""Search ingredients from inventory service"""
|
||||
try:
|
||||
inventory_client = InventoryClient()
|
||||
|
||||
# This would call the inventory service search endpoint
|
||||
# For now, return a placeholder response
|
||||
return {
|
||||
"ingredients": [],
|
||||
"total": 0,
|
||||
"message": "Integration with inventory service needed"
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error searching ingredients: {e}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.get("/{ingredient_id}")
|
||||
async def get_ingredient(
|
||||
ingredient_id: UUID,
|
||||
tenant_id: UUID = Depends(get_tenant_id)
|
||||
):
|
||||
"""Get ingredient details from inventory service"""
|
||||
try:
|
||||
inventory_client = InventoryClient()
|
||||
ingredient = await inventory_client.get_ingredient_by_id(tenant_id, ingredient_id)
|
||||
|
||||
if not ingredient:
|
||||
raise HTTPException(status_code=404, detail="Ingredient not found")
|
||||
|
||||
return ingredient
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting ingredient {ingredient_id}: {e}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.get("/{ingredient_id}/stock")
|
||||
async def get_ingredient_stock(
|
||||
ingredient_id: UUID,
|
||||
tenant_id: UUID = Depends(get_tenant_id)
|
||||
):
|
||||
"""Get ingredient stock level from inventory service"""
|
||||
try:
|
||||
inventory_client = InventoryClient()
|
||||
stock = await inventory_client.get_ingredient_stock_level(tenant_id, ingredient_id)
|
||||
|
||||
if not stock:
|
||||
raise HTTPException(status_code=404, detail="Stock information not found")
|
||||
|
||||
return stock
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting stock for ingredient {ingredient_id}: {e}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.post("/check-availability")
|
||||
async def check_ingredients_availability(
|
||||
required_ingredients: List[dict],
|
||||
tenant_id: UUID = Depends(get_tenant_id)
|
||||
):
|
||||
"""Check if required ingredients are available for production"""
|
||||
try:
|
||||
inventory_client = InventoryClient()
|
||||
result = await inventory_client.check_ingredient_availability(
|
||||
tenant_id,
|
||||
required_ingredients
|
||||
)
|
||||
|
||||
if not result["success"]:
|
||||
raise HTTPException(status_code=400, detail=result["error"])
|
||||
|
||||
return result["data"]
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error checking ingredient availability: {e}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
@@ -1,427 +0,0 @@
|
||||
# services/recipes/app/api/production.py
|
||||
"""
|
||||
API endpoints for production management
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Header, Query
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import List, Optional
|
||||
from uuid import UUID
|
||||
from datetime import date, datetime
|
||||
import logging
|
||||
|
||||
from ..core.database import get_db
|
||||
from ..services.production_service import ProductionService
|
||||
from ..schemas.production import (
|
||||
ProductionBatchCreate,
|
||||
ProductionBatchUpdate,
|
||||
ProductionBatchResponse,
|
||||
ProductionBatchSearchRequest,
|
||||
ProductionScheduleCreate,
|
||||
ProductionScheduleUpdate,
|
||||
ProductionScheduleResponse,
|
||||
ProductionStatisticsResponse,
|
||||
StartProductionRequest,
|
||||
CompleteProductionRequest
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
def get_tenant_id(x_tenant_id: str = Header(...)) -> UUID:
|
||||
"""Extract tenant ID from header"""
|
||||
try:
|
||||
return UUID(x_tenant_id)
|
||||
except ValueError:
|
||||
raise HTTPException(status_code=400, detail="Invalid tenant ID format")
|
||||
|
||||
|
||||
def get_user_id(x_user_id: str = Header(...)) -> UUID:
|
||||
"""Extract user ID from header"""
|
||||
try:
|
||||
return UUID(x_user_id)
|
||||
except ValueError:
|
||||
raise HTTPException(status_code=400, detail="Invalid user ID format")
|
||||
|
||||
|
||||
# Production Batch Endpoints
|
||||
|
||||
@router.post("/batches", response_model=ProductionBatchResponse)
|
||||
async def create_production_batch(
|
||||
batch_data: ProductionBatchCreate,
|
||||
tenant_id: UUID = Depends(get_tenant_id),
|
||||
user_id: UUID = Depends(get_user_id),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Create a new production batch"""
|
||||
try:
|
||||
production_service = ProductionService(db)
|
||||
|
||||
batch_dict = batch_data.dict()
|
||||
batch_dict["tenant_id"] = tenant_id
|
||||
|
||||
result = await production_service.create_production_batch(batch_dict, user_id)
|
||||
|
||||
if not result["success"]:
|
||||
raise HTTPException(status_code=400, detail=result["error"])
|
||||
|
||||
return ProductionBatchResponse(**result["data"])
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error creating production batch: {e}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.get("/batches/{batch_id}", response_model=ProductionBatchResponse)
|
||||
async def get_production_batch(
|
||||
batch_id: UUID,
|
||||
tenant_id: UUID = Depends(get_tenant_id),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get production batch by ID with consumptions"""
|
||||
try:
|
||||
production_service = ProductionService(db)
|
||||
batch = production_service.get_production_batch_with_consumptions(batch_id)
|
||||
|
||||
if not batch:
|
||||
raise HTTPException(status_code=404, detail="Production batch not found")
|
||||
|
||||
# Verify tenant ownership
|
||||
if batch["tenant_id"] != str(tenant_id):
|
||||
raise HTTPException(status_code=403, detail="Access denied")
|
||||
|
||||
return ProductionBatchResponse(**batch)
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting production batch {batch_id}: {e}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.put("/batches/{batch_id}", response_model=ProductionBatchResponse)
|
||||
async def update_production_batch(
|
||||
batch_id: UUID,
|
||||
batch_data: ProductionBatchUpdate,
|
||||
tenant_id: UUID = Depends(get_tenant_id),
|
||||
user_id: UUID = Depends(get_user_id),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Update an existing production batch"""
|
||||
try:
|
||||
production_service = ProductionService(db)
|
||||
|
||||
# Check if batch exists and belongs to tenant
|
||||
existing_batch = production_service.get_production_batch_with_consumptions(batch_id)
|
||||
if not existing_batch:
|
||||
raise HTTPException(status_code=404, detail="Production batch not found")
|
||||
|
||||
if existing_batch["tenant_id"] != str(tenant_id):
|
||||
raise HTTPException(status_code=403, detail="Access denied")
|
||||
|
||||
batch_dict = batch_data.dict(exclude_unset=True)
|
||||
|
||||
result = await production_service.update_production_batch(batch_id, batch_dict, user_id)
|
||||
|
||||
if not result["success"]:
|
||||
raise HTTPException(status_code=400, detail=result["error"])
|
||||
|
||||
return ProductionBatchResponse(**result["data"])
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error updating production batch {batch_id}: {e}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.delete("/batches/{batch_id}")
|
||||
async def delete_production_batch(
|
||||
batch_id: UUID,
|
||||
tenant_id: UUID = Depends(get_tenant_id),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Delete a production batch"""
|
||||
try:
|
||||
production_service = ProductionService(db)
|
||||
|
||||
# Check if batch exists and belongs to tenant
|
||||
existing_batch = production_service.get_production_batch_with_consumptions(batch_id)
|
||||
if not existing_batch:
|
||||
raise HTTPException(status_code=404, detail="Production batch not found")
|
||||
|
||||
if existing_batch["tenant_id"] != str(tenant_id):
|
||||
raise HTTPException(status_code=403, detail="Access denied")
|
||||
|
||||
success = production_service.production_repo.delete(batch_id)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail="Production batch not found")
|
||||
|
||||
return {"message": "Production batch deleted successfully"}
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error deleting production batch {batch_id}: {e}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.get("/batches", response_model=List[ProductionBatchResponse])
|
||||
async def search_production_batches(
|
||||
tenant_id: UUID = Depends(get_tenant_id),
|
||||
search_term: Optional[str] = Query(None),
|
||||
status: Optional[str] = Query(None),
|
||||
priority: Optional[str] = Query(None),
|
||||
start_date: Optional[date] = Query(None),
|
||||
end_date: Optional[date] = Query(None),
|
||||
recipe_id: Optional[UUID] = Query(None),
|
||||
limit: int = Query(100, ge=1, le=1000),
|
||||
offset: int = Query(0, ge=0),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Search production batches with filters"""
|
||||
try:
|
||||
production_service = ProductionService(db)
|
||||
|
||||
batches = production_service.search_production_batches(
|
||||
tenant_id=tenant_id,
|
||||
search_term=search_term,
|
||||
status=status,
|
||||
priority=priority,
|
||||
start_date=start_date,
|
||||
end_date=end_date,
|
||||
recipe_id=recipe_id,
|
||||
limit=limit,
|
||||
offset=offset
|
||||
)
|
||||
|
||||
return [ProductionBatchResponse(**batch) for batch in batches]
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error searching production batches: {e}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.post("/batches/{batch_id}/start", response_model=ProductionBatchResponse)
|
||||
async def start_production_batch(
|
||||
batch_id: UUID,
|
||||
start_data: StartProductionRequest,
|
||||
tenant_id: UUID = Depends(get_tenant_id),
|
||||
user_id: UUID = Depends(get_user_id),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Start production batch and record ingredient consumptions"""
|
||||
try:
|
||||
production_service = ProductionService(db)
|
||||
|
||||
# Check if batch exists and belongs to tenant
|
||||
existing_batch = production_service.get_production_batch_with_consumptions(batch_id)
|
||||
if not existing_batch:
|
||||
raise HTTPException(status_code=404, detail="Production batch not found")
|
||||
|
||||
if existing_batch["tenant_id"] != str(tenant_id):
|
||||
raise HTTPException(status_code=403, detail="Access denied")
|
||||
|
||||
consumptions_list = [cons.dict() for cons in start_data.ingredient_consumptions]
|
||||
|
||||
result = await production_service.start_production_batch(
|
||||
batch_id,
|
||||
consumptions_list,
|
||||
start_data.staff_member or user_id,
|
||||
start_data.production_notes
|
||||
)
|
||||
|
||||
if not result["success"]:
|
||||
raise HTTPException(status_code=400, detail=result["error"])
|
||||
|
||||
return ProductionBatchResponse(**result["data"])
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error starting production batch {batch_id}: {e}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.post("/batches/{batch_id}/complete", response_model=ProductionBatchResponse)
|
||||
async def complete_production_batch(
|
||||
batch_id: UUID,
|
||||
complete_data: CompleteProductionRequest,
|
||||
tenant_id: UUID = Depends(get_tenant_id),
|
||||
user_id: UUID = Depends(get_user_id),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Complete production batch and add finished products to inventory"""
|
||||
try:
|
||||
production_service = ProductionService(db)
|
||||
|
||||
# Check if batch exists and belongs to tenant
|
||||
existing_batch = production_service.get_production_batch_with_consumptions(batch_id)
|
||||
if not existing_batch:
|
||||
raise HTTPException(status_code=404, detail="Production batch not found")
|
||||
|
||||
if existing_batch["tenant_id"] != str(tenant_id):
|
||||
raise HTTPException(status_code=403, detail="Access denied")
|
||||
|
||||
completion_data = complete_data.dict()
|
||||
|
||||
result = await production_service.complete_production_batch(
|
||||
batch_id,
|
||||
completion_data,
|
||||
complete_data.staff_member or user_id
|
||||
)
|
||||
|
||||
if not result["success"]:
|
||||
raise HTTPException(status_code=400, detail=result["error"])
|
||||
|
||||
return ProductionBatchResponse(**result["data"])
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error completing production batch {batch_id}: {e}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.get("/batches/active/list", response_model=List[ProductionBatchResponse])
|
||||
async def get_active_production_batches(
|
||||
tenant_id: UUID = Depends(get_tenant_id),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get all active production batches"""
|
||||
try:
|
||||
production_service = ProductionService(db)
|
||||
batches = production_service.get_active_production_batches(tenant_id)
|
||||
|
||||
return [ProductionBatchResponse(**batch) for batch in batches]
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting active production batches: {e}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.get("/statistics/dashboard", response_model=ProductionStatisticsResponse)
|
||||
async def get_production_statistics(
|
||||
tenant_id: UUID = Depends(get_tenant_id),
|
||||
start_date: Optional[date] = Query(None),
|
||||
end_date: Optional[date] = Query(None),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get production statistics for dashboard"""
|
||||
try:
|
||||
production_service = ProductionService(db)
|
||||
stats = production_service.get_production_statistics(tenant_id, start_date, end_date)
|
||||
|
||||
return ProductionStatisticsResponse(**stats)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting production statistics: {e}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
# Production Schedule Endpoints
|
||||
|
||||
@router.post("/schedules", response_model=ProductionScheduleResponse)
|
||||
async def create_production_schedule(
|
||||
schedule_data: ProductionScheduleCreate,
|
||||
tenant_id: UUID = Depends(get_tenant_id),
|
||||
user_id: UUID = Depends(get_user_id),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Create a new production schedule"""
|
||||
try:
|
||||
production_service = ProductionService(db)
|
||||
|
||||
schedule_dict = schedule_data.dict()
|
||||
schedule_dict["tenant_id"] = tenant_id
|
||||
schedule_dict["created_by"] = user_id
|
||||
|
||||
result = production_service.create_production_schedule(schedule_dict)
|
||||
|
||||
if not result["success"]:
|
||||
raise HTTPException(status_code=400, detail=result["error"])
|
||||
|
||||
return ProductionScheduleResponse(**result["data"])
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error creating production schedule: {e}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.get("/schedules/{schedule_id}", response_model=ProductionScheduleResponse)
|
||||
async def get_production_schedule(
|
||||
schedule_id: UUID,
|
||||
tenant_id: UUID = Depends(get_tenant_id),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get production schedule by ID"""
|
||||
try:
|
||||
production_service = ProductionService(db)
|
||||
schedule = production_service.get_production_schedule(schedule_id)
|
||||
|
||||
if not schedule:
|
||||
raise HTTPException(status_code=404, detail="Production schedule not found")
|
||||
|
||||
# Verify tenant ownership
|
||||
if schedule["tenant_id"] != str(tenant_id):
|
||||
raise HTTPException(status_code=403, detail="Access denied")
|
||||
|
||||
return ProductionScheduleResponse(**schedule)
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting production schedule {schedule_id}: {e}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.get("/schedules/date/{schedule_date}", response_model=ProductionScheduleResponse)
|
||||
async def get_production_schedule_by_date(
|
||||
schedule_date: date,
|
||||
tenant_id: UUID = Depends(get_tenant_id),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get production schedule for specific date"""
|
||||
try:
|
||||
production_service = ProductionService(db)
|
||||
schedule = production_service.get_production_schedule_by_date(tenant_id, schedule_date)
|
||||
|
||||
if not schedule:
|
||||
raise HTTPException(status_code=404, detail="Production schedule not found for this date")
|
||||
|
||||
return ProductionScheduleResponse(**schedule)
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting production schedule for {schedule_date}: {e}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.get("/schedules", response_model=List[ProductionScheduleResponse])
|
||||
async def get_production_schedules(
|
||||
tenant_id: UUID = Depends(get_tenant_id),
|
||||
start_date: Optional[date] = Query(None),
|
||||
end_date: Optional[date] = Query(None),
|
||||
published_only: bool = Query(False),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get production schedules within date range"""
|
||||
try:
|
||||
production_service = ProductionService(db)
|
||||
|
||||
if published_only:
|
||||
schedules = production_service.get_published_schedules(tenant_id, start_date, end_date)
|
||||
else:
|
||||
schedules = production_service.get_production_schedules_range(tenant_id, start_date, end_date)
|
||||
|
||||
return [ProductionScheduleResponse(**schedule) for schedule in schedules]
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting production schedules: {e}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
@@ -4,7 +4,7 @@ API endpoints for recipe management
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Header, Query
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from typing import List, Optional
|
||||
from uuid import UUID
|
||||
import logging
|
||||
@@ -25,12 +25,6 @@ logger = logging.getLogger(__name__)
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
def get_tenant_id(x_tenant_id: str = Header(...)) -> UUID:
|
||||
"""Extract tenant ID from header"""
|
||||
try:
|
||||
return UUID(x_tenant_id)
|
||||
except ValueError:
|
||||
raise HTTPException(status_code=400, detail="Invalid tenant ID format")
|
||||
|
||||
|
||||
def get_user_id(x_user_id: str = Header(...)) -> UUID:
|
||||
@@ -41,12 +35,12 @@ def get_user_id(x_user_id: str = Header(...)) -> UUID:
|
||||
raise HTTPException(status_code=400, detail="Invalid user ID format")
|
||||
|
||||
|
||||
@router.post("/", response_model=RecipeResponse)
|
||||
@router.post("/{tenant_id}/recipes", response_model=RecipeResponse)
|
||||
async def create_recipe(
|
||||
tenant_id: UUID,
|
||||
recipe_data: RecipeCreate,
|
||||
tenant_id: UUID = Depends(get_tenant_id),
|
||||
user_id: UUID = Depends(get_user_id),
|
||||
db: Session = Depends(get_db)
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""Create a new recipe"""
|
||||
try:
|
||||
@@ -76,16 +70,16 @@ async def create_recipe(
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.get("/{recipe_id}", response_model=RecipeResponse)
|
||||
@router.get("/{tenant_id}/recipes/{recipe_id}", response_model=RecipeResponse)
|
||||
async def get_recipe(
|
||||
tenant_id: UUID,
|
||||
recipe_id: UUID,
|
||||
tenant_id: UUID = Depends(get_tenant_id),
|
||||
db: Session = Depends(get_db)
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""Get recipe by ID with ingredients"""
|
||||
try:
|
||||
recipe_service = RecipeService(db)
|
||||
recipe = recipe_service.get_recipe_with_ingredients(recipe_id)
|
||||
recipe = await recipe_service.get_recipe_with_ingredients(recipe_id)
|
||||
|
||||
if not recipe:
|
||||
raise HTTPException(status_code=404, detail="Recipe not found")
|
||||
@@ -103,20 +97,20 @@ async def get_recipe(
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.put("/{recipe_id}", response_model=RecipeResponse)
|
||||
@router.put("/{tenant_id}/recipes/{recipe_id}", response_model=RecipeResponse)
|
||||
async def update_recipe(
|
||||
tenant_id: UUID,
|
||||
recipe_id: UUID,
|
||||
recipe_data: RecipeUpdate,
|
||||
tenant_id: UUID = Depends(get_tenant_id),
|
||||
user_id: UUID = Depends(get_user_id),
|
||||
db: Session = Depends(get_db)
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""Update an existing recipe"""
|
||||
try:
|
||||
recipe_service = RecipeService(db)
|
||||
|
||||
# Check if recipe exists and belongs to tenant
|
||||
existing_recipe = recipe_service.get_recipe_with_ingredients(recipe_id)
|
||||
existing_recipe = await recipe_service.get_recipe_with_ingredients(recipe_id)
|
||||
if not existing_recipe:
|
||||
raise HTTPException(status_code=404, detail="Recipe not found")
|
||||
|
||||
@@ -149,26 +143,26 @@ async def update_recipe(
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.delete("/{recipe_id}")
|
||||
@router.delete("/{tenant_id}/recipes/{recipe_id}")
|
||||
async def delete_recipe(
|
||||
tenant_id: UUID,
|
||||
recipe_id: UUID,
|
||||
tenant_id: UUID = Depends(get_tenant_id),
|
||||
db: Session = Depends(get_db)
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""Delete a recipe"""
|
||||
try:
|
||||
recipe_service = RecipeService(db)
|
||||
|
||||
# Check if recipe exists and belongs to tenant
|
||||
existing_recipe = recipe_service.get_recipe_with_ingredients(recipe_id)
|
||||
existing_recipe = await recipe_service.get_recipe_with_ingredients(recipe_id)
|
||||
if not existing_recipe:
|
||||
raise HTTPException(status_code=404, detail="Recipe not found")
|
||||
|
||||
if existing_recipe["tenant_id"] != str(tenant_id):
|
||||
raise HTTPException(status_code=403, detail="Access denied")
|
||||
|
||||
# Use repository to delete
|
||||
success = recipe_service.recipe_repo.delete(recipe_id)
|
||||
# Use service to delete
|
||||
success = await recipe_service.delete_recipe(recipe_id)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail="Recipe not found")
|
||||
|
||||
@@ -181,9 +175,9 @@ async def delete_recipe(
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.get("/", response_model=List[RecipeResponse])
|
||||
@router.get("/{tenant_id}/recipes", response_model=List[RecipeResponse])
|
||||
async def search_recipes(
|
||||
tenant_id: UUID = Depends(get_tenant_id),
|
||||
tenant_id: UUID,
|
||||
search_term: Optional[str] = Query(None),
|
||||
status: Optional[str] = Query(None),
|
||||
category: Optional[str] = Query(None),
|
||||
@@ -192,13 +186,13 @@ async def search_recipes(
|
||||
difficulty_level: Optional[int] = Query(None, ge=1, le=5),
|
||||
limit: int = Query(100, ge=1, le=1000),
|
||||
offset: int = Query(0, ge=0),
|
||||
db: Session = Depends(get_db)
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""Search recipes with filters"""
|
||||
try:
|
||||
recipe_service = RecipeService(db)
|
||||
|
||||
recipes = recipe_service.search_recipes(
|
||||
|
||||
recipes = await recipe_service.search_recipes(
|
||||
tenant_id=tenant_id,
|
||||
search_term=search_term,
|
||||
status=status,
|
||||
@@ -217,13 +211,13 @@ async def search_recipes(
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.post("/{recipe_id}/duplicate", response_model=RecipeResponse)
|
||||
@router.post("/{tenant_id}/recipes/{recipe_id}/duplicate", response_model=RecipeResponse)
|
||||
async def duplicate_recipe(
|
||||
tenant_id: UUID,
|
||||
recipe_id: UUID,
|
||||
duplicate_data: RecipeDuplicateRequest,
|
||||
tenant_id: UUID = Depends(get_tenant_id),
|
||||
user_id: UUID = Depends(get_user_id),
|
||||
db: Session = Depends(get_db)
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""Create a duplicate of an existing recipe"""
|
||||
try:
|
||||
@@ -255,19 +249,19 @@ async def duplicate_recipe(
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.post("/{recipe_id}/activate", response_model=RecipeResponse)
|
||||
@router.post("/{tenant_id}/recipes/{recipe_id}/activate", response_model=RecipeResponse)
|
||||
async def activate_recipe(
|
||||
tenant_id: UUID,
|
||||
recipe_id: UUID,
|
||||
tenant_id: UUID = Depends(get_tenant_id),
|
||||
user_id: UUID = Depends(get_user_id),
|
||||
db: Session = Depends(get_db)
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""Activate a recipe for production"""
|
||||
try:
|
||||
recipe_service = RecipeService(db)
|
||||
|
||||
# Check if recipe exists and belongs to tenant
|
||||
existing_recipe = recipe_service.get_recipe_with_ingredients(recipe_id)
|
||||
existing_recipe = await recipe_service.get_recipe_with_ingredients(recipe_id)
|
||||
if not existing_recipe:
|
||||
raise HTTPException(status_code=404, detail="Recipe not found")
|
||||
|
||||
@@ -288,19 +282,19 @@ async def activate_recipe(
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.get("/{recipe_id}/feasibility", response_model=RecipeFeasibilityResponse)
|
||||
@router.get("/{tenant_id}/recipes/{recipe_id}/feasibility", response_model=RecipeFeasibilityResponse)
|
||||
async def check_recipe_feasibility(
|
||||
tenant_id: UUID,
|
||||
recipe_id: UUID,
|
||||
batch_multiplier: float = Query(1.0, gt=0),
|
||||
tenant_id: UUID = Depends(get_tenant_id),
|
||||
db: Session = Depends(get_db)
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""Check if recipe can be produced with current inventory"""
|
||||
try:
|
||||
recipe_service = RecipeService(db)
|
||||
|
||||
# Check if recipe exists and belongs to tenant
|
||||
existing_recipe = recipe_service.get_recipe_with_ingredients(recipe_id)
|
||||
existing_recipe = await recipe_service.get_recipe_with_ingredients(recipe_id)
|
||||
if not existing_recipe:
|
||||
raise HTTPException(status_code=404, detail="Recipe not found")
|
||||
|
||||
@@ -321,15 +315,15 @@ async def check_recipe_feasibility(
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.get("/statistics/dashboard", response_model=RecipeStatisticsResponse)
|
||||
@router.get("/{tenant_id}/recipes/statistics/dashboard", response_model=RecipeStatisticsResponse)
|
||||
async def get_recipe_statistics(
|
||||
tenant_id: UUID = Depends(get_tenant_id),
|
||||
db: Session = Depends(get_db)
|
||||
tenant_id: UUID,
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""Get recipe statistics for dashboard"""
|
||||
try:
|
||||
recipe_service = RecipeService(db)
|
||||
stats = recipe_service.get_recipe_statistics(tenant_id)
|
||||
stats = await recipe_service.get_recipe_statistics(tenant_id)
|
||||
|
||||
return RecipeStatisticsResponse(**stats)
|
||||
|
||||
@@ -338,17 +332,17 @@ async def get_recipe_statistics(
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.get("/categories/list")
|
||||
@router.get("/{tenant_id}/recipes/categories/list")
|
||||
async def get_recipe_categories(
|
||||
tenant_id: UUID = Depends(get_tenant_id),
|
||||
db: Session = Depends(get_db)
|
||||
tenant_id: UUID,
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""Get list of recipe categories used by tenant"""
|
||||
try:
|
||||
recipe_service = RecipeService(db)
|
||||
|
||||
# Get categories from existing recipes
|
||||
recipes = recipe_service.search_recipes(tenant_id, limit=1000)
|
||||
recipes = await recipe_service.search_recipes(tenant_id, limit=1000)
|
||||
categories = list(set(recipe["category"] for recipe in recipes if recipe["category"]))
|
||||
categories.sort()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user