
- Added comprehensive book management with CRUD operations - Implemented inventory tracking with stock management and reservations - Created order management system with status tracking - Integrated Stripe payment processing with payment intents - Added SQLite database with SQLAlchemy ORM and Alembic migrations - Implemented health check and API documentation endpoints - Added comprehensive error handling and validation - Configured CORS middleware for frontend integration
119 lines
5.0 KiB
Python
119 lines
5.0 KiB
Python
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"} |