from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.orm import Session from typing import List from app.db.session import get_db from app.models import Inventory, Book from app.schemas import InventoryCreate, InventoryUpdate, InventoryResponse router = APIRouter(prefix="/inventory", tags=["inventory"]) @router.post("/", response_model=InventoryResponse) def create_inventory(inventory: InventoryCreate, db: Session = Depends(get_db)): book = db.query(Book).filter(Book.id == inventory.book_id).first() if not book: raise HTTPException(status_code=404, detail="Book not found") existing_inventory = db.query(Inventory).filter(Inventory.book_id == inventory.book_id).first() if existing_inventory: raise HTTPException(status_code=400, detail="Inventory for this book already exists") db_inventory = Inventory(**inventory.model_dump()) db.add(db_inventory) db.commit() db.refresh(db_inventory) setattr(db_inventory, 'available_quantity', db_inventory.quantity - db_inventory.reserved_quantity) return db_inventory @router.get("/", response_model=List[InventoryResponse]) def get_inventory( skip: int = Query(0, ge=0), limit: int = Query(100, ge=1, le=1000), low_stock: bool = Query(False, description="Filter items with low stock"), db: Session = Depends(get_db) ): query = db.query(Inventory) if low_stock: query = query.filter(Inventory.quantity <= Inventory.reorder_level) inventories = query.offset(skip).limit(limit).all() for inventory in inventories: setattr(inventory, 'available_quantity', inventory.quantity - inventory.reserved_quantity) return inventories @router.get("/{inventory_id}", response_model=InventoryResponse) def get_inventory_item(inventory_id: int, db: Session = Depends(get_db)): inventory = db.query(Inventory).filter(Inventory.id == inventory_id).first() if not inventory: raise HTTPException(status_code=404, detail="Inventory item not found") setattr(inventory, 'available_quantity', inventory.quantity - inventory.reserved_quantity) return inventory @router.get("/book/{book_id}", response_model=InventoryResponse) def get_inventory_by_book(book_id: int, db: Session = Depends(get_db)): inventory = db.query(Inventory).filter(Inventory.book_id == book_id).first() if not inventory: raise HTTPException(status_code=404, detail="Inventory for this book not found") setattr(inventory, 'available_quantity', inventory.quantity - inventory.reserved_quantity) return inventory @router.put("/{inventory_id}", response_model=InventoryResponse) def update_inventory(inventory_id: int, inventory_update: InventoryUpdate, db: Session = Depends(get_db)): inventory = db.query(Inventory).filter(Inventory.id == inventory_id).first() if not inventory: raise HTTPException(status_code=404, detail="Inventory item not found") update_data = inventory_update.model_dump(exclude_unset=True) for field, value in update_data.items(): setattr(inventory, field, value) db.commit() db.refresh(inventory) setattr(inventory, 'available_quantity', inventory.quantity - inventory.reserved_quantity) return inventory @router.post("/{inventory_id}/restock") def restock_inventory(inventory_id: int, quantity: int = Query(..., gt=0), db: Session = Depends(get_db)): inventory = db.query(Inventory).filter(Inventory.id == inventory_id).first() if not inventory: raise HTTPException(status_code=404, detail="Inventory item not found") inventory.quantity += quantity db.commit() return {"message": f"Restocked {quantity} units. New quantity: {inventory.quantity}"} @router.post("/{inventory_id}/reserve") def reserve_inventory(inventory_id: int, quantity: int = Query(..., gt=0), db: Session = Depends(get_db)): inventory = db.query(Inventory).filter(Inventory.id == inventory_id).first() if not inventory: raise HTTPException(status_code=404, detail="Inventory item not found") available = inventory.quantity - inventory.reserved_quantity if quantity > available: raise HTTPException(status_code=400, detail=f"Not enough stock available. Available: {available}") inventory.reserved_quantity += quantity db.commit() return {"message": f"Reserved {quantity} units"} @router.post("/{inventory_id}/release") def release_inventory(inventory_id: int, quantity: int = Query(..., gt=0), db: Session = Depends(get_db)): inventory = db.query(Inventory).filter(Inventory.id == inventory_id).first() if not inventory: raise HTTPException(status_code=404, detail="Inventory item not found") if quantity > inventory.reserved_quantity: raise HTTPException(status_code=400, detail="Cannot release more than reserved quantity") inventory.reserved_quantity -= quantity db.commit() return {"message": f"Released {quantity} units from reservation"}