from typing import Any, List, Optional from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.orm import Session from app import crud, models, schemas from app.api import deps router = APIRouter() # Category endpoints @router.get("/categories/", response_model=List[schemas.Category]) def read_categories( db: Session = Depends(deps.get_db), skip: int = 0, limit: int = 100, current_user: models.User = Depends(deps.get_current_active_user), ) -> Any: """ Retrieve categories. """ categories = crud.product.get_all_categories(db, skip=skip, limit=limit) return categories @router.post("/categories/", response_model=schemas.Category) def create_category( *, db: Session = Depends(deps.get_db), category_in: schemas.CategoryCreate, current_user: models.User = Depends(deps.get_current_admin_user), ) -> Any: """ Create new category. Admin only. """ category = crud.product.get_category_by_name(db, name=category_in.name) if category: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Category with this name already exists", ) category = crud.product.create_category(db, obj_in=category_in) return category @router.get("/categories/{category_id}", response_model=schemas.Category) def read_category( *, db: Session = Depends(deps.get_db), category_id: str, current_user: models.User = Depends(deps.get_current_active_user), ) -> Any: """ Get category by ID. """ category = crud.product.get_category_by_id(db, category_id=category_id) if not category: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Category not found", ) return category @router.put("/categories/{category_id}", response_model=schemas.Category) def update_category( *, db: Session = Depends(deps.get_db), category_id: str, category_in: schemas.CategoryUpdate, current_user: models.User = Depends(deps.get_current_admin_user), ) -> Any: """ Update a category. Admin only. """ category = crud.product.get_category_by_id(db, category_id=category_id) if not category: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Category not found", ) # Check if updated name already exists if category_in.name and category_in.name != category.name: existing_category = crud.product.get_category_by_name(db, name=category_in.name) if existing_category: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Category with this name already exists", ) category = crud.product.update_category(db, db_obj=category, obj_in=category_in) return category @router.delete("/categories/{category_id}", response_model=schemas.Category) def delete_category( *, db: Session = Depends(deps.get_db), category_id: str, current_user: models.User = Depends(deps.get_current_admin_user), ) -> Any: """ Delete a category. Admin only. """ category = crud.product.get_category_by_id(db, category_id=category_id) if not category: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Category not found", ) # Check if category has products products = crud.product.get_all_products(db, category_id=category_id) if products: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Cannot delete category with associated products", ) category = crud.product.delete_category(db, category_id=category_id) return category # Product endpoints @router.get("/", response_model=List[schemas.Product]) def read_products( db: Session = Depends(deps.get_db), skip: int = 0, limit: int = 100, category_id: Optional[str] = None, active_only: bool = False, current_user: models.User = Depends(deps.get_current_active_user), ) -> Any: """ Retrieve products with optional filtering. """ products = crud.product.get_all_products( db, skip=skip, limit=limit, category_id=category_id, active_only=active_only ) return products @router.post("/", response_model=schemas.Product) def create_product( *, db: Session = Depends(deps.get_db), product_in: schemas.ProductCreate, current_user: models.User = Depends(deps.get_current_admin_user), ) -> Any: """ Create new product. Admin only. """ # Check if SKU exists product = crud.product.get_product_by_sku(db, sku=product_in.sku) if product: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Product with this SKU already exists", ) # Check if category exists if provided if product_in.category_id: category = crud.product.get_category_by_id(db, category_id=product_in.category_id) if not category: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Category not found", ) product = crud.product.create_product(db, obj_in=product_in) return product @router.get("/{product_id}", response_model=schemas.ProductWithCategory) def read_product( *, db: Session = Depends(deps.get_db), product_id: str, current_user: models.User = Depends(deps.get_current_active_user), ) -> Any: """ Get product by ID. """ product = crud.product.get_product_by_id(db, product_id=product_id) if not product: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Product not found", ) return product @router.put("/{product_id}", response_model=schemas.Product) def update_product( *, db: Session = Depends(deps.get_db), product_id: str, product_in: schemas.ProductUpdate, current_user: models.User = Depends(deps.get_current_admin_user), ) -> Any: """ Update a product. Admin only. """ product = crud.product.get_product_by_id(db, product_id=product_id) if not product: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Product not found", ) # Check if updated SKU already exists if product_in.sku and product_in.sku != product.sku: existing_product = crud.product.get_product_by_sku(db, sku=product_in.sku) if existing_product: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Product with this SKU already exists", ) # Check if category exists if provided if product_in.category_id: category = crud.product.get_category_by_id(db, category_id=product_in.category_id) if not category: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Category not found", ) product = crud.product.update_product(db, db_obj=product, obj_in=product_in) return product @router.delete("/{product_id}", response_model=schemas.Product) def delete_product( *, db: Session = Depends(deps.get_db), product_id: str, current_user: models.User = Depends(deps.get_current_admin_user), ) -> Any: """ Delete a product. Admin only. """ product = crud.product.get_product_by_id(db, product_id=product_id) if not product: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Product not found", ) # Check if product has inventory items inventory_item = crud.inventory.get_inventory_item_by_product_id(db, product_id=product_id) if inventory_item: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Cannot delete product with associated inventory items", ) product = crud.product.delete_product(db, product_id=product_id) return product