120 lines
3.5 KiB
Python

from typing import Any, List, Optional
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from app import crud, schemas
from app.db.session import get_db
from app.models.inventory_movement import MovementType
router = APIRouter()
@router.get("/movements/", response_model=List[schemas.InventoryMovementWithProduct])
def read_inventory_movements(
db: Session = Depends(get_db),
skip: int = 0,
limit: int = 100,
product_id: Optional[str] = None,
movement_type: Optional[schemas.MovementTypeEnum] = None,
) -> Any:
"""
Retrieve inventory movements with optional filtering.
"""
if movement_type:
db_movement_type = MovementType(movement_type)
else:
db_movement_type = None
movements = crud.inventory.get_multi(
db, skip=skip, limit=limit, product_id=product_id, movement_type=db_movement_type
)
return movements
@router.post(
"/movements/", response_model=schemas.InventoryMovement, status_code=status.HTTP_201_CREATED
)
def create_inventory_movement(
*,
db: Session = Depends(get_db),
movement_in: schemas.InventoryMovementCreate,
) -> Any:
"""
Create a new inventory movement (stock in, stock out, adjustment, return).
"""
# Check if product exists
product = crud.product.get(db, product_id=movement_in.product_id)
if not product:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Product not found",
)
# For stock out, check if there is enough stock
if (
movement_in.type == schemas.MovementTypeEnum.STOCK_OUT
and product.current_stock < movement_in.quantity
):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Insufficient stock for product {product.name}. Available: {product.current_stock}, Requested: {movement_in.quantity}",
)
try:
movement = crud.inventory.create(db, obj_in=movement_in)
return movement
except ValueError as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e),
) from e
@router.get("/movements/{movement_id}", response_model=schemas.InventoryMovementWithProduct)
def read_inventory_movement(
*,
db: Session = Depends(get_db),
movement_id: str,
) -> Any:
"""
Get a specific inventory movement by ID.
"""
movement = crud.inventory.get(db, movement_id=movement_id)
if not movement:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Inventory movement not found",
)
return movement
@router.delete(
"/movements/{movement_id}", status_code=status.HTTP_204_NO_CONTENT, response_model=None
)
def delete_inventory_movement(
*,
db: Session = Depends(get_db),
movement_id: str,
) -> Any:
"""
Delete an inventory movement and revert its effect on stock.
Warning: This will alter inventory history and may cause inconsistencies.
Consider using adjustments instead for corrections.
"""
movement = crud.inventory.get(db, movement_id=movement_id)
if not movement:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Inventory movement not found",
)
try:
crud.inventory.remove(db, movement_id=movement_id)
return None
except ValueError as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e),
) from e