
- Set up project structure and FastAPI application - Create database models for users, products, and inventory - Configure SQLAlchemy and Alembic for database management - Implement JWT authentication - Create API endpoints for user, product, and inventory management - Add admin-only routes and authorization middleware - Add health check endpoint - Update README with documentation - Lint and fix code issues
226 lines
7.2 KiB
Python
226 lines
7.2 KiB
Python
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
|
|
from app.models.inventory import InventoryStatus
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
# Inventory Item endpoints
|
|
@router.get("/items/", response_model=List[schemas.InventoryItemWithProduct])
|
|
def read_inventory_items(
|
|
db: Session = Depends(deps.get_db),
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
status: Optional[InventoryStatus] = None,
|
|
current_user: models.User = Depends(deps.get_current_active_user),
|
|
) -> Any:
|
|
"""
|
|
Retrieve inventory items with optional filtering.
|
|
"""
|
|
items = crud.inventory.get_all_inventory_items(
|
|
db,
|
|
skip=skip,
|
|
limit=limit,
|
|
status=status
|
|
)
|
|
return items
|
|
|
|
|
|
@router.post("/items/", response_model=schemas.InventoryItem)
|
|
def create_inventory_item(
|
|
*,
|
|
db: Session = Depends(deps.get_db),
|
|
item_in: schemas.InventoryItemCreate,
|
|
current_user: models.User = Depends(deps.get_current_admin_user),
|
|
) -> Any:
|
|
"""
|
|
Create new inventory item. Admin only.
|
|
"""
|
|
# Check if product exists
|
|
product = crud.product.get_product_by_id(db, product_id=item_in.product_id)
|
|
if not product:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Product not found",
|
|
)
|
|
|
|
# Check if inventory item for this product already exists
|
|
existing_item = crud.inventory.get_inventory_item_by_product_id(db, product_id=item_in.product_id)
|
|
if existing_item:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="Inventory item for this product already exists",
|
|
)
|
|
|
|
# Create inventory item
|
|
item = crud.inventory.create_inventory_item(db, obj_in=item_in)
|
|
|
|
# Create initial inventory transaction
|
|
if item_in.quantity > 0:
|
|
transaction_in = schemas.InventoryTransactionCreate(
|
|
product_id=item_in.product_id,
|
|
quantity_change=item_in.quantity,
|
|
notes="Initial inventory",
|
|
transaction_by=current_user.id
|
|
)
|
|
crud.inventory.create_transaction(db, obj_in=transaction_in)
|
|
|
|
return item
|
|
|
|
|
|
@router.get("/items/{item_id}", response_model=schemas.InventoryItemWithProduct)
|
|
def read_inventory_item(
|
|
*,
|
|
db: Session = Depends(deps.get_db),
|
|
item_id: str,
|
|
current_user: models.User = Depends(deps.get_current_active_user),
|
|
) -> Any:
|
|
"""
|
|
Get inventory item by ID.
|
|
"""
|
|
item = crud.inventory.get_inventory_item_by_id(db, item_id=item_id)
|
|
if not item:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Inventory item not found",
|
|
)
|
|
return item
|
|
|
|
|
|
@router.put("/items/{item_id}", response_model=schemas.InventoryItem)
|
|
def update_inventory_item(
|
|
*,
|
|
db: Session = Depends(deps.get_db),
|
|
item_id: str,
|
|
item_in: schemas.InventoryItemUpdate,
|
|
current_user: models.User = Depends(deps.get_current_admin_user),
|
|
) -> Any:
|
|
"""
|
|
Update an inventory item. Admin only.
|
|
"""
|
|
item = crud.inventory.get_inventory_item_by_id(db, item_id=item_id)
|
|
if not item:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Inventory item not found",
|
|
)
|
|
|
|
# Create transaction if quantity is being updated
|
|
if item_in.quantity is not None and item_in.quantity != item.quantity:
|
|
quantity_change = item_in.quantity - item.quantity
|
|
transaction_in = schemas.InventoryTransactionCreate(
|
|
product_id=item.product_id,
|
|
quantity_change=quantity_change,
|
|
notes=f"Manual inventory adjustment from {item.quantity} to {item_in.quantity}",
|
|
transaction_by=current_user.id
|
|
)
|
|
crud.inventory.create_transaction(db, obj_in=transaction_in)
|
|
|
|
item = crud.inventory.update_inventory_item(db, db_obj=item, obj_in=item_in)
|
|
return item
|
|
|
|
|
|
@router.delete("/items/{item_id}", response_model=schemas.InventoryItem, status_code=status.HTTP_200_OK)
|
|
def delete_inventory_item(
|
|
*,
|
|
db: Session = Depends(deps.get_db),
|
|
item_id: str,
|
|
current_user: models.User = Depends(deps.get_current_admin_user),
|
|
) -> Any:
|
|
"""
|
|
Delete an inventory item. Admin only.
|
|
"""
|
|
item = crud.inventory.get_inventory_item_by_id(db, item_id=item_id)
|
|
if not item:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Inventory item not found",
|
|
)
|
|
|
|
item = crud.inventory.delete_inventory_item(db, item_id=item_id)
|
|
return item
|
|
|
|
|
|
# Inventory Transaction endpoints
|
|
@router.get("/transactions/", response_model=List[schemas.InventoryTransaction])
|
|
def read_transactions(
|
|
db: Session = Depends(deps.get_db),
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
product_id: Optional[str] = None,
|
|
current_user: models.User = Depends(deps.get_current_admin_user),
|
|
) -> Any:
|
|
"""
|
|
Retrieve inventory transactions. Admin only.
|
|
"""
|
|
if product_id:
|
|
transactions = crud.inventory.get_transactions_by_product_id(
|
|
db,
|
|
product_id=product_id,
|
|
skip=skip,
|
|
limit=limit
|
|
)
|
|
else:
|
|
# Get all transactions - would need to add a method for this
|
|
# For now, we'll just return an empty list
|
|
transactions = []
|
|
|
|
return transactions
|
|
|
|
|
|
@router.post("/transactions/", response_model=schemas.InventoryTransaction)
|
|
def create_transaction(
|
|
*,
|
|
db: Session = Depends(deps.get_db),
|
|
transaction_in: schemas.InventoryTransactionCreate,
|
|
current_user: models.User = Depends(deps.get_current_admin_user),
|
|
) -> Any:
|
|
"""
|
|
Create new inventory transaction. Admin only.
|
|
"""
|
|
# Check if product exists
|
|
product = crud.product.get_product_by_id(db, product_id=transaction_in.product_id)
|
|
if not product:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Product not found",
|
|
)
|
|
|
|
# Check if inventory item exists for this product
|
|
inventory_item = crud.inventory.get_inventory_item_by_product_id(db, product_id=transaction_in.product_id)
|
|
if not inventory_item:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="No inventory item found for this product",
|
|
)
|
|
|
|
# Set the current user as the transaction creator if not specified
|
|
if transaction_in.transaction_by is None:
|
|
transaction_in.transaction_by = current_user.id
|
|
|
|
transaction = crud.inventory.create_transaction(db, obj_in=transaction_in)
|
|
return transaction
|
|
|
|
|
|
@router.get("/transactions/{transaction_id}", response_model=schemas.InventoryTransaction)
|
|
def read_transaction(
|
|
*,
|
|
db: Session = Depends(deps.get_db),
|
|
transaction_id: str,
|
|
current_user: models.User = Depends(deps.get_current_admin_user),
|
|
) -> Any:
|
|
"""
|
|
Get transaction by ID. Admin only.
|
|
"""
|
|
transaction = crud.inventory.get_transaction_by_id(db, transaction_id=transaction_id)
|
|
if not transaction:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Transaction not found",
|
|
)
|
|
return transaction |