Automated Action 700da98f88 Implement small business inventory management system with FastAPI and SQLite
- Created complete RESTful API for inventory management
- Set up database models for items, categories, suppliers, and transactions
- Implemented user authentication with JWT tokens
- Added transaction tracking for inventory movements
- Created comprehensive API endpoints for all CRUD operations
- Set up Alembic for database migrations
- Added input validation and error handling
- Created detailed documentation in README
2025-06-08 10:00:50 +00:00

182 lines
5.7 KiB
Python

from typing import Any, List
from datetime import datetime, date
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from app import crud, models, schemas
from app.api import deps
from app.models.transaction import TransactionType
router = APIRouter()
@router.get("/", response_model=List[schemas.Transaction])
def read_transactions(
db: Session = Depends(deps.get_db),
skip: int = 0,
limit: int = 100,
current_user: models.User = Depends(deps.get_current_active_user),
) -> Any:
"""
Retrieve transactions.
"""
transactions = crud.transaction.get_multi(db, skip=skip, limit=limit)
return transactions
@router.post("/", response_model=schemas.Transaction)
def create_transaction(
*,
db: Session = Depends(deps.get_db),
transaction_in: schemas.TransactionCreate,
current_user: models.User = Depends(deps.get_current_active_user),
) -> Any:
"""
Create new transaction and update item quantity.
"""
# Validate item exists
item = crud.item.get(db, id=transaction_in.item_id)
if not item:
raise HTTPException(
status_code=404,
detail=f"Item with ID {transaction_in.item_id} not found"
)
# Create the transaction
transaction = crud.transaction.create(db, obj_in=transaction_in)
# Update item quantity based on transaction type
if transaction.transaction_type == TransactionType.PURCHASE:
# Increase stock
new_quantity = item.quantity + transaction.quantity
elif transaction.transaction_type == TransactionType.SALE:
# Decrease stock, but check if enough available
if item.quantity < transaction.quantity:
raise HTTPException(
status_code=400,
detail=f"Insufficient quantity available. Only {item.quantity} items in stock."
)
new_quantity = item.quantity - transaction.quantity
elif transaction.transaction_type == TransactionType.ADJUSTMENT:
# Direct update to specified quantity
new_quantity = item.quantity + transaction.quantity # Quantity can be positive or negative
elif transaction.transaction_type == TransactionType.RETURN:
# Increase stock for returns
new_quantity = item.quantity + transaction.quantity
else:
raise HTTPException(
status_code=400,
detail=f"Invalid transaction type: {transaction.transaction_type}"
)
# Update the item quantity
crud.item.update(db, db_obj=item, obj_in={"quantity": new_quantity})
return transaction
@router.get("/{id}", response_model=schemas.Transaction)
def read_transaction(
*,
db: Session = Depends(deps.get_db),
id: str,
current_user: models.User = Depends(deps.get_current_active_user),
) -> Any:
"""
Get transaction by ID.
"""
transaction = crud.transaction.get(db, id=id)
if not transaction:
raise HTTPException(status_code=404, detail="Transaction not found")
return transaction
@router.get("/by-item/{item_id}", response_model=List[schemas.Transaction])
def read_transactions_by_item(
*,
db: Session = Depends(deps.get_db),
item_id: str,
skip: int = 0,
limit: int = 100,
current_user: models.User = Depends(deps.get_current_active_user),
) -> Any:
"""
Get transactions by item ID.
"""
# Validate item exists
item = crud.item.get(db, id=item_id)
if not item:
raise HTTPException(status_code=404, detail="Item not found")
transactions = crud.transaction.get_by_item(db, item_id=item_id, skip=skip, limit=limit)
return transactions
@router.get("/by-user/{user_id}", response_model=List[schemas.Transaction])
def read_transactions_by_user(
*,
db: Session = Depends(deps.get_db),
user_id: str,
skip: int = 0,
limit: int = 100,
current_user: models.User = Depends(deps.get_current_active_superuser),
) -> Any:
"""
Get transactions by user ID. Only accessible by superusers.
"""
# Validate user exists
user = crud.user.get(db, id=user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")
transactions = crud.transaction.get_by_user(db, user_id=user_id, skip=skip, limit=limit)
return transactions
@router.get("/by-type/{transaction_type}", response_model=List[schemas.Transaction])
def read_transactions_by_type(
*,
db: Session = Depends(deps.get_db),
transaction_type: TransactionType,
skip: int = 0,
limit: int = 100,
current_user: models.User = Depends(deps.get_current_active_user),
) -> Any:
"""
Get transactions by transaction type.
"""
transactions = crud.transaction.get_by_type(
db,
transaction_type=transaction_type,
skip=skip,
limit=limit
)
return transactions
@router.get("/by-date-range/", response_model=List[schemas.Transaction])
def read_transactions_by_date_range(
*,
db: Session = Depends(deps.get_db),
start_date: date = Query(..., description="Start date in format YYYY-MM-DD"),
end_date: date = Query(..., description="End date in format YYYY-MM-DD"),
skip: int = 0,
limit: int = 100,
current_user: models.User = Depends(deps.get_current_active_user),
) -> Any:
"""
Get transactions within a date range.
"""
# Convert dates to datetime objects
start_datetime = datetime.combine(start_date, datetime.min.time())
end_datetime = datetime.combine(end_date, datetime.max.time())
transactions = crud.transaction.get_by_date_range(
db,
start_date=start_datetime,
end_date=end_datetime,
skip=skip,
limit=limit
)
return transactions