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