
- Set up project structure with FastAPI and SQLite - Create database models for inventory management - Set up SQLAlchemy and Alembic for database migrations - Create initial database migrations - Implement CRUD operations for products, categories, suppliers - Implement stock movement tracking and inventory management - Add authentication and user management - Add API endpoints for all entities - Add health check endpoint - Update README with project information and usage instructions
106 lines
3.3 KiB
Python
106 lines
3.3 KiB
Python
from typing import Any, List
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app import crud, models, schemas
|
|
from app.api import deps
|
|
from app.models.stock_movement import MovementType
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("/", response_model=List[schemas.StockMovement])
|
|
def read_stock_movements(
|
|
db: Session = Depends(deps.get_db),
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
current_user: models.User = Depends(deps.get_current_active_user),
|
|
) -> Any:
|
|
"""
|
|
Retrieve stock movements.
|
|
"""
|
|
stock_movements = crud.stock_movement.get_multi(db, skip=skip, limit=limit)
|
|
return stock_movements
|
|
|
|
|
|
@router.post("/", response_model=schemas.StockMovement)
|
|
def create_stock_movement(
|
|
*,
|
|
db: Session = Depends(deps.get_db),
|
|
stock_movement_in: schemas.StockMovementCreate,
|
|
current_user: models.User = Depends(deps.get_current_active_user),
|
|
) -> Any:
|
|
"""
|
|
Create new stock movement and update product stock levels.
|
|
"""
|
|
# Check if product exists
|
|
product = crud.product.get(db, id=stock_movement_in.product_id)
|
|
if not product:
|
|
raise HTTPException(status_code=404, detail="Product not found")
|
|
|
|
# For outgoing stock, make sure we have enough
|
|
if stock_movement_in.movement_type in [MovementType.SALE, MovementType.ADJUSTMENT] and stock_movement_in.quantity > 0:
|
|
if product.current_stock < stock_movement_in.quantity:
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail=f"Not enough stock available. Current stock: {product.current_stock}",
|
|
)
|
|
|
|
# Create stock movement and update product stock level
|
|
stock_movement = crud.stock_movement.create_with_product_update(
|
|
db, obj_in=stock_movement_in, created_by=current_user.id
|
|
)
|
|
return stock_movement
|
|
|
|
|
|
@router.get("/{stock_movement_id}", response_model=schemas.StockMovement)
|
|
def read_stock_movement(
|
|
*,
|
|
db: Session = Depends(deps.get_db),
|
|
stock_movement_id: str,
|
|
current_user: models.User = Depends(deps.get_current_active_user),
|
|
) -> Any:
|
|
"""
|
|
Get stock movement by ID.
|
|
"""
|
|
stock_movement = crud.stock_movement.get(db, id=stock_movement_id)
|
|
if not stock_movement:
|
|
raise HTTPException(status_code=404, detail="Stock movement not found")
|
|
return stock_movement
|
|
|
|
|
|
@router.get("/by-product/{product_id}", response_model=List[schemas.StockMovement])
|
|
def read_stock_movements_by_product(
|
|
*,
|
|
db: Session = Depends(deps.get_db),
|
|
product_id: str,
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
current_user: models.User = Depends(deps.get_current_active_user),
|
|
) -> Any:
|
|
"""
|
|
Get stock movements by product.
|
|
"""
|
|
stock_movements = crud.stock_movement.get_by_product(
|
|
db, product_id=product_id, skip=skip, limit=limit
|
|
)
|
|
return stock_movements
|
|
|
|
|
|
@router.get("/by-type/{movement_type}", response_model=List[schemas.StockMovement])
|
|
def read_stock_movements_by_type(
|
|
*,
|
|
db: Session = Depends(deps.get_db),
|
|
movement_type: MovementType,
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
current_user: models.User = Depends(deps.get_current_active_user),
|
|
) -> Any:
|
|
"""
|
|
Get stock movements by movement type.
|
|
"""
|
|
stock_movements = crud.stock_movement.get_by_movement_type(
|
|
db, movement_type=movement_type, skip=skip, limit=limit
|
|
)
|
|
return stock_movements |