Automated Action a17fe518a9 Implement Small Business Inventory Management System
This commit includes:
- Project structure setup with FastAPI and SQLite
- Database models and schemas for inventory management
- CRUD operations for all entities
- API endpoints for product, category, supplier, and inventory management
- User authentication with JWT tokens
- Initial database migration
- Comprehensive README with setup instructions
2025-06-17 19:02:35 +00:00

200 lines
6.7 KiB
Python

from typing import Any, List, Optional
from datetime import datetime
from fastapi import APIRouter, Depends, HTTPException, Body
from sqlalchemy.orm import Session
from app import crud, models, schemas
from app.api import deps
router = APIRouter()
@router.get("/", response_model=List[schemas.Inventory])
def read_inventories(
db: Session = Depends(deps.get_db),
skip: int = 0,
limit: int = 100,
location: Optional[str] = None,
current_user: models.User = Depends(deps.get_current_active_user),
) -> Any:
"""
Retrieve inventory items with optional filtering by location.
"""
if location:
inventories = crud.inventory.get_by_location(db, location=location, skip=skip, limit=limit)
else:
inventories = crud.inventory.get_multi(db, skip=skip, limit=limit)
return inventories
@router.get("/product/{product_id}", response_model=schemas.Inventory)
def read_inventory_by_product(
*,
db: Session = Depends(deps.get_db),
product_id: int,
current_user: models.User = Depends(deps.get_current_active_user),
) -> Any:
"""
Get inventory by product ID.
"""
inventory = crud.inventory.get_by_product_id(db, product_id=product_id)
if not inventory:
raise HTTPException(status_code=404, detail="Inventory not found for this product")
return inventory
@router.get("/low-stock", response_model=schemas.InventorySummaryList)
def read_low_stock(
db: Session = Depends(deps.get_db),
skip: int = 0,
limit: int = 100,
current_user: models.User = Depends(deps.get_current_active_user),
) -> Any:
"""
Get products with inventory below minimum stock level.
"""
low_stock_items = crud.inventory.get_low_stock(db, skip=skip, limit=limit)
return {"inventories": low_stock_items}
@router.get("/summary", response_model=schemas.InventorySummaryList)
def read_inventory_summary(
db: Session = Depends(deps.get_db),
skip: int = 0,
limit: int = 100,
current_user: models.User = Depends(deps.get_current_active_user),
) -> Any:
"""
Get inventory summary for all products.
"""
summary = crud.inventory.get_inventory_summary(db, skip=skip, limit=limit)
return {"inventories": summary}
@router.put("/adjust/{product_id}", response_model=schemas.Inventory)
def adjust_inventory(
*,
db: Session = Depends(deps.get_db),
product_id: int,
quantity_change: int = Body(..., description="Amount to add or subtract from inventory"),
location: Optional[str] = Body(None, description="Location of the inventory"),
notes: Optional[str] = Body(None, description="Notes about the adjustment"),
current_user: models.User = Depends(deps.get_current_active_user),
) -> Any:
"""
Adjust inventory quantity for a product.
Positive values increase stock, negative values decrease stock.
"""
# Verify the product exists
product = crud.product.get(db, id=product_id)
if not product:
raise HTTPException(status_code=404, detail="Product not found")
# Update inventory and create transaction record
result = crud.inventory.update_stock(
db=db,
product_id=product_id,
quantity_change=quantity_change,
user_id=current_user.id,
transaction_type="adjustment",
notes=notes
)
# Update location if provided
if location and location != result["inventory"].location:
inventory_update = schemas.InventoryUpdate(
product_id=product_id,
quantity=result["inventory"].quantity,
location=location
)
inventory = crud.inventory.update(db, db_obj=result["inventory"], obj_in=inventory_update)
return inventory
return result["inventory"]
@router.post("/transactions/", response_model=schemas.InventoryTransaction)
def create_inventory_transaction(
*,
db: Session = Depends(deps.get_db),
transaction_in: schemas.InventoryTransactionCreate,
current_user: models.User = Depends(deps.get_current_active_user),
) -> Any:
"""
Create a new inventory transaction and update inventory accordingly.
"""
# Verify the product exists
product = crud.product.get(db, id=transaction_in.product_id)
if not product:
raise HTTPException(status_code=404, detail="Product not found")
# Validate transaction type
valid_types = ["purchase", "sale", "adjustment", "return", "transfer"]
if transaction_in.transaction_type not in valid_types:
raise HTTPException(
status_code=400,
detail=f"Invalid transaction type. Must be one of: {', '.join(valid_types)}"
)
# Update inventory and create transaction record
result = crud.inventory.update_stock(
db=db,
product_id=transaction_in.product_id,
quantity_change=transaction_in.quantity,
user_id=current_user.id,
transaction_type=transaction_in.transaction_type,
reference=transaction_in.reference,
unit_price=transaction_in.unit_price,
notes=transaction_in.notes
)
return result["transaction"]
@router.get("/transactions/", response_model=List[schemas.InventoryTransaction])
def read_inventory_transactions(
db: Session = Depends(deps.get_db),
skip: int = 0,
limit: int = 100,
product_id: Optional[int] = None,
transaction_type: Optional[str] = None,
start_date: Optional[datetime] = None,
end_date: Optional[datetime] = None,
current_user: models.User = Depends(deps.get_current_active_user),
) -> Any:
"""
Retrieve inventory transactions with optional filtering.
"""
if product_id:
transactions = crud.inventory_transaction.get_by_product_id(
db, product_id=product_id, skip=skip, limit=limit
)
elif transaction_type:
transactions = crud.inventory_transaction.get_by_type(
db, transaction_type=transaction_type, skip=skip, limit=limit
)
elif start_date and end_date:
transactions = crud.inventory_transaction.get_by_date_range(
db, start_date=start_date, end_date=end_date, skip=skip, limit=limit
)
else:
transactions = crud.inventory_transaction.get_multi(db, skip=skip, limit=limit)
return transactions
@router.get("/transactions/{transaction_id}", response_model=schemas.InventoryTransaction)
def read_inventory_transaction(
*,
db: Session = Depends(deps.get_db),
transaction_id: int,
current_user: models.User = Depends(deps.get_current_active_user),
) -> Any:
"""
Get inventory transaction by ID.
"""
transaction = crud.inventory_transaction.get(db, id=transaction_id)
if not transaction:
raise HTTPException(status_code=404, detail="Transaction not found")
return transaction