from typing import Any, List, Optional from fastapi import APIRouter, Depends, HTTPException, Query, status from sqlalchemy.orm import Session from app import crud from app.api import deps from app.models.user import User from app.schemas.item import Item, ItemCreate, ItemUpdate router = APIRouter() @router.get("/", response_model=List[Item]) def read_items( db: Session = Depends(deps.get_db), skip: int = 0, limit: int = 100, category_id: Optional[int] = None, supplier_id: Optional[int] = None, low_stock: Optional[bool] = False, current_user: User = Depends(deps.get_current_user), ) -> Any: """ Retrieve inventory items with optional filtering. """ if low_stock: items = crud.item.get_low_stock(db, skip=skip, limit=limit) elif category_id: items = crud.item.get_by_category(db, category_id=category_id, skip=skip, limit=limit) elif supplier_id: items = crud.item.get_by_supplier(db, supplier_id=supplier_id, skip=skip, limit=limit) else: items = crud.item.get_multi(db, skip=skip, limit=limit) return items @router.post("/", response_model=Item, status_code=status.HTTP_201_CREATED) def create_item( *, db: Session = Depends(deps.get_db), item_in: ItemCreate, current_user: User = Depends(deps.get_current_user), ) -> Any: """ Create new inventory item. """ # Check if item with the same SKU or barcode already exists if item_in.sku: item = crud.item.get_by_sku(db, sku=item_in.sku) if item: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Item with this SKU already exists", ) if item_in.barcode: item = crud.item.get_by_barcode(db, barcode=item_in.barcode) if item: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Item with this barcode already exists", ) # Validate category if provided if item_in.category_id and not crud.category.get(db, id=item_in.category_id): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="The category doesn't exist", ) # Validate supplier if provided if item_in.supplier_id and not crud.supplier.get(db, id=item_in.supplier_id): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="The supplier doesn't exist", ) item = crud.item.create(db, obj_in=item_in) return item @router.get("/{item_id}", response_model=Item) def read_item( *, db: Session = Depends(deps.get_db), item_id: int, current_user: User = Depends(deps.get_current_user), ) -> Any: """ Get item by ID. """ item = crud.item.get(db, id=item_id) if not item: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Item not found", ) return item @router.put("/{item_id}", response_model=Item) def update_item( *, db: Session = Depends(deps.get_db), item_id: int, item_in: ItemUpdate, current_user: User = Depends(deps.get_current_user), ) -> Any: """ Update an item. """ item = crud.item.get(db, id=item_id) if not item: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Item not found", ) # Check if SKU is being changed and if it already exists if item_in.sku and item_in.sku != item.sku: existing_item = crud.item.get_by_sku(db, sku=item_in.sku) if existing_item and existing_item.id != item_id: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Item with this SKU already exists", ) # Check if barcode is being changed and if it already exists if item_in.barcode and item_in.barcode != item.barcode: existing_item = crud.item.get_by_barcode(db, barcode=item_in.barcode) if existing_item and existing_item.id != item_id: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Item with this barcode already exists", ) # Validate category if provided if item_in.category_id and not crud.category.get(db, id=item_in.category_id): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="The category doesn't exist", ) # Validate supplier if provided if item_in.supplier_id and not crud.supplier.get(db, id=item_in.supplier_id): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="The supplier doesn't exist", ) item = crud.item.update(db, db_obj=item, obj_in=item_in) return item @router.delete("/{item_id}", status_code=status.HTTP_204_NO_CONTENT, response_model=None) def delete_item( *, db: Session = Depends(deps.get_db), item_id: int, current_user: User = Depends(deps.get_current_user), ) -> Any: """ Delete an item. """ item = crud.item.get(db, id=item_id) if not item: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Item not found", ) # Check if the item has any transactions transactions = crud.transaction.get_by_item(db, item_id=item_id, skip=0, limit=1) if transactions: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Cannot delete item with transaction history", ) crud.item.remove(db, id=item_id) return None @router.get("/search/", response_model=List[Item]) def search_items( *, db: Session = Depends(deps.get_db), name: Optional[str] = Query(None, min_length=1), sku: Optional[str] = Query(None, min_length=1), barcode: Optional[str] = Query(None, min_length=1), current_user: User = Depends(deps.get_current_user), ) -> Any: """ Search for items by name, SKU, or barcode. """ if sku: item = crud.item.get_by_sku(db, sku=sku) return [item] if item else [] if barcode: item = crud.item.get_by_barcode(db, barcode=barcode) return [item] if item else [] if name: items = db.query(crud.item.model).filter( crud.item.model.name.ilike(f"%{name}%") ).all() return items # If no search parameters are provided, return an empty list return []